From 3aa3a0421a48b97d915a75d9a22e914f5923b429 Mon Sep 17 00:00:00 2001 From: Taufik Nurrohman Date: Sat, 20 Jun 2020 08:15:48 +0700 Subject: [PATCH] Revert Parsedown Extra to Version 0.8.0 Related: https://github.com/erusev/parsedown-extra/issues/152 --- README.md | 2 +- .../engine/kernel/parsedown-extra.php | 268 ++++++++++++++---- 2 files changed, 209 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 971760d9..7ab36dee 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Release Notes ### master - - Updated [Parsedown Extra](https://github.com/erusev/parsedown-extra) to version 0.8.1. + - Updated [Parsedown Extra](https://github.com/erusev/parsedown-extra) to version 0.8.0. ### 2.3.1 diff --git a/lot/x/markdown/engine/kernel/parsedown-extra.php b/lot/x/markdown/engine/kernel/parsedown-extra.php index e4b8b466..8782d358 100644 --- a/lot/x/markdown/engine/kernel/parsedown-extra.php +++ b/lot/x/markdown/engine/kernel/parsedown-extra.php @@ -17,13 +17,13 @@ class ParsedownExtra extends Parsedown { # ~ - const version = '0.8.1'; + const version = '0.8.0'; # ~ function __construct() { - if (version_compare(parent::version, '1.7.4') < 0) + if (version_compare(parent::version, '1.7.1') < 0) { throw new Exception('ParsedownExtra requires a later version of Parsedown'); } @@ -43,7 +43,13 @@ function __construct() function text($text) { - $markup = parent::text($text); + $Elements = $this->textElements($text); + + # convert to markup + $markup = $this->elements($Elements); + + # trim line breaks + $markup = trim($markup, "\n"); # merge consecutive dl elements @@ -139,25 +145,27 @@ protected function blockFootnoteComplete($Block) protected function blockDefinitionList($Line, $Block) { - if ( ! isset($Block) or isset($Block['type'])) + if ( ! isset($Block) or $Block['type'] !== 'Paragraph') { return; } $Element = array( 'name' => 'dl', - 'handler' => 'elements', - 'text' => array(), + 'elements' => array(), ); - $terms = explode("\n", $Block['element']['text']); + $terms = explode("\n", $Block['element']['handler']['argument']); foreach ($terms as $term) { - $Element['text'] []= array( + $Element['elements'] []= array( 'name' => 'dt', - 'handler' => 'line', - 'text' => $term, + 'handler' => array( + 'function' => 'lineElements', + 'argument' => $term, + 'destination' => 'elements' + ), ); } @@ -185,15 +193,17 @@ protected function blockDefinitionListContinue($Line, array $Block) if (isset($Block['interrupted'])) { - $Block['dd']['handler'] = 'text'; - $Block['dd']['text'] .= "\n\n"; + $Block['dd']['handler']['function'] = 'textElements'; + $Block['dd']['handler']['argument'] .= "\n\n"; + + $Block['dd']['handler']['destination'] = 'elements'; unset($Block['interrupted']); } $text = substr($Line['body'], min($Line['indent'], 4)); - $Block['dd']['text'] .= "\n" . $text; + $Block['dd']['handler']['argument'] .= "\n" . $text; return $Block; } @@ -206,17 +216,13 @@ protected function blockHeader($Line) { $Block = parent::blockHeader($Line); - if (! isset($Block)) { - return null; - } - - if (preg_match('/[ #]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['text'], $matches, PREG_OFFSET_CAPTURE)) + if ($Block !== null && preg_match('/[ #]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['handler']['argument'], $matches, PREG_OFFSET_CAPTURE)) { $attributeString = $matches[1][0]; $Block['element']['attributes'] = $this->parseAttributeData($attributeString); - $Block['element']['text'] = substr($Block['element']['text'], 0, $matches[0][1]); + $Block['element']['handler']['argument'] = substr($Block['element']['handler']['argument'], 0, $matches[0][1]); } return $Block; @@ -225,11 +231,98 @@ protected function blockHeader($Line) # # Markup + protected function blockMarkup($Line) + { + if ($this->markupEscaped or $this->safeMode) + { + return; + } + + if (preg_match('/^<(\w[\w-]*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) + { + $element = strtolower($matches[1]); + + if (in_array($element, $this->textLevelElements)) + { + return; + } + + $Block = array( + 'name' => $matches[1], + 'depth' => 0, + 'element' => array( + 'rawHtml' => $Line['text'], + 'autobreak' => true, + ), + ); + + $length = strlen($matches[0]); + $remainder = substr($Line['text'], $length); + + if (trim($remainder) === '') + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + $Block['closed'] = true; + $Block['void'] = true; + } + } + else + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + return; + } + if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) + { + $Block['closed'] = true; + } + } + + return $Block; + } + } + + protected function blockMarkupContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open + { + $Block['depth'] ++; + } + + if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close + { + if ($Block['depth'] > 0) + { + $Block['depth'] --; + } + else + { + $Block['closed'] = true; + } + } + + if (isset($Block['interrupted'])) + { + $Block['element']['rawHtml'] .= "\n"; + unset($Block['interrupted']); + } + + $Block['element']['rawHtml'] .= "\n".$Line['body']; + + return $Block; + } + protected function blockMarkupComplete($Block) { if ( ! isset($Block['void'])) { - $Block['markup'] = $this->processTag($Block['markup']); + $Block['element']['rawHtml'] = $this->processTag($Block['element']['rawHtml']); } return $Block; @@ -242,17 +335,13 @@ protected function blockSetextHeader($Line, array $Block = null) { $Block = parent::blockSetextHeader($Line, $Block); - if (! isset($Block)) { - return null; - } - - if (preg_match('/[ ]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['text'], $matches, PREG_OFFSET_CAPTURE)) + if ($Block !== null && preg_match('/[ ]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['handler']['argument'], $matches, PREG_OFFSET_CAPTURE)) { $attributeString = $matches[1][0]; $Block['element']['attributes'] = $this->parseAttributeData($attributeString); - $Block['element']['text'] = substr($Block['element']['text'], 0, $matches[0][1]); + $Block['element']['handler']['argument'] = substr($Block['element']['handler']['argument'], 0, $matches[0][1]); } return $Block; @@ -286,8 +375,7 @@ protected function inlineFootnoteMarker($Excerpt) $Element = array( 'name' => 'sup', 'attributes' => array('id' => 'fnref'.$this->DefinitionData['Footnote'][$name]['count'].':'.$name), - 'handler' => 'element', - 'text' => array( + 'element' => array( 'name' => 'a', 'attributes' => array('href' => '#fn:'.$name, 'class' => 'footnote-ref'), 'text' => $this->DefinitionData['Footnote'][$name]['number'], @@ -310,11 +398,7 @@ protected function inlineLink($Excerpt) { $Link = parent::inlineLink($Excerpt); - if (! isset($Link)) { - return null; - } - - $remainder = substr($Excerpt['text'], $Link['extent']); + $remainder = $Link !== null ? substr($Excerpt['text'], $Link['extent']) : ''; if (preg_match('/^[ ]*{('.$this->regexAttribute.'+)}/', $remainder, $matches)) { @@ -330,21 +414,52 @@ protected function inlineLink($Excerpt) # ~ # - protected function unmarkedText($text) + private $currentAbreviation; + private $currentMeaning; + + protected function insertAbreviation(array $Element) { - $text = parent::unmarkedText($text); + if (isset($Element['text'])) + { + $Element['elements'] = self::pregReplaceElements( + '/\b'.preg_quote($this->currentAbreviation, '/').'\b/', + array( + array( + 'name' => 'abbr', + 'attributes' => array( + 'title' => $this->currentMeaning, + ), + 'text' => $this->currentAbreviation, + ) + ), + $Element['text'] + ); + + unset($Element['text']); + } + + return $Element; + } + + protected function inlineText($text) + { + $Inline = parent::inlineText($text); if (isset($this->DefinitionData['Abbreviation'])) { foreach ($this->DefinitionData['Abbreviation'] as $abbreviation => $meaning) { - $pattern = '/\b'.preg_quote($abbreviation, '/').'\b/'; + $this->currentAbreviation = $abbreviation; + $this->currentMeaning = $meaning; - $text = preg_replace($pattern, ''.$abbreviation.'', $text); + $Inline['element'] = $this->elementApplyRecursiveDepthFirst( + array($this, 'insertAbreviation'), + $Inline['element'] + ); } } - return $text; + return $Inline; } # @@ -360,18 +475,21 @@ protected function addDdElement(array $Line, array $Block) $Block['dd'] = array( 'name' => 'dd', - 'handler' => 'line', - 'text' => $text, + 'handler' => array( + 'function' => 'lineElements', + 'argument' => $text, + 'destination' => 'elements' + ), ); if (isset($Block['interrupted'])) { - $Block['dd']['handler'] = 'text'; + $Block['dd']['handler']['function'] = 'textElements'; unset($Block['interrupted']); } - $Block['element']['text'] []= & $Block['dd']; + $Block['element']['elements'] []= & $Block['dd']; return $Block; } @@ -381,15 +499,11 @@ protected function buildFootnoteElement() $Element = array( 'name' => 'div', 'attributes' => array('class' => 'footnotes'), - 'handler' => 'elements', - 'text' => array( - array( - 'name' => 'hr', - ), + 'elements' => array( + array('name' => 'hr'), array( 'name' => 'ol', - 'handler' => 'elements', - 'text' => array(), + 'elements' => array(), ), ), ); @@ -405,34 +519,68 @@ protected function buildFootnoteElement() $text = $DefinitionData['text']; - $text = parent::text($text); + $textElements = parent::textElements($text); $numbers = range(1, $DefinitionData['count']); - $backLinksMarkup = ''; + $backLinkElements = array(); foreach ($numbers as $number) { - $backLinksMarkup .= ' '; + $backLinkElements[] = array('text' => ' '); + $backLinkElements[] = array( + 'name' => 'a', + 'attributes' => array( + 'href' => "#fnref$number:$definitionId", + 'rev' => 'footnote', + 'class' => 'footnote-backref', + ), + 'rawHtml' => '↩', + 'allowRawHtmlInSafeMode' => true, + 'autobreak' => false, + ); } - $backLinksMarkup = substr($backLinksMarkup, 1); + unset($backLinkElements[0]); - if (substr($text, - 4) === '

') - { - $backLinksMarkup = ' '.$backLinksMarkup; + $n = count($textElements) -1; - $text = substr_replace($text, $backLinksMarkup.'

', - 4); + if ($textElements[$n]['name'] === 'p') + { + $backLinkElements = array_merge( + array( + array( + 'rawHtml' => ' ', + 'allowRawHtmlInSafeMode' => true, + ), + ), + $backLinkElements + ); + + unset($textElements[$n]['name']); + + $textElements[$n] = array( + 'name' => 'p', + 'elements' => array_merge( + array($textElements[$n]), + $backLinkElements + ), + ); } else { - $text .= "\n".'

'.$backLinksMarkup.'

'; + $textElements[] = array( + 'name' => 'p', + 'elements' => $backLinkElements + ); } - $Element['text'][1]['text'] []= array( + $Element['elements'][1]['elements'] []= array( 'name' => 'li', 'attributes' => array('id' => 'fn:'.$definitionId), - 'rawHtml' => "\n".$text."\n", + 'elements' => array_merge( + $textElements + ), ); }