From bbb9d06f29a563c5d1762e5408d4ecbc502d425c Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 10 Nov 2023 12:28:26 +0000 Subject: [PATCH] add tests + some new markdown functionality --- Utils/Parser/Markdown/Markdown.php | 641 ++++++++++++------ tests/Utils/Parser/Markdown/MarkdownTest.php | 89 +++ tests/Utils/Parser/Markdown/data/checkbox.htm | 0 tests/Utils/Parser/Markdown/data/checkbox.md | 2 + tests/Utils/Parser/Markdown/data/emoji.html | 1 + tests/Utils/Parser/Markdown/data/emoji.md | 1 + .../Utils/Parser/Markdown/data/emphasis.html | 2 +- tests/Utils/Parser/Markdown/data/emphasis.md | 2 +- .../Utils/Parser/Markdown/data/keystroke.html | 1 + tests/Utils/Parser/Markdown/data/keystroke.md | 1 + tests/Utils/Parser/Markdown/data/mark.html | 1 + tests/Utils/Parser/Markdown/data/mark.md | 1 + tests/Utils/Parser/Markdown/data/video.md | 1 - .../Parser/Markdown/manualdata/address.html | 1 + .../Parser/Markdown/manualdata/address.md | 1 + .../Parser/Markdown/manualdata/contact.html | 9 + .../Parser/Markdown/manualdata/contact.md | 9 + .../video.html => manualdata/embed.html} | 3 +- .../Utils/Parser/Markdown/manualdata/embed.md | 4 + .../Utils/Parser/Markdown/manualdata/map.html | 1 + tests/Utils/Parser/Markdown/manualdata/map.md | 1 + .../Parser/Markdown/manualdata/progress.html | 1 + .../Parser/Markdown/manualdata/progress.md | 1 + .../Parser/Markdown/manualdata/spoiler.html | 1 + .../Parser/Markdown/manualdata/spoiler.md | 1 + .../Markdown/manualdata/spoiler_block.html | 1 + .../Markdown/manualdata/spoiler_block.md | 3 + .../Markdown/manualdata/typographer.html | 1 + .../Parser/Markdown/manualdata/typographer.md | 1 + 29 files changed, 563 insertions(+), 219 deletions(-) create mode 100644 tests/Utils/Parser/Markdown/data/checkbox.htm create mode 100644 tests/Utils/Parser/Markdown/data/checkbox.md create mode 100644 tests/Utils/Parser/Markdown/data/emoji.html create mode 100644 tests/Utils/Parser/Markdown/data/emoji.md create mode 100644 tests/Utils/Parser/Markdown/data/keystroke.html create mode 100644 tests/Utils/Parser/Markdown/data/keystroke.md create mode 100644 tests/Utils/Parser/Markdown/data/mark.html create mode 100644 tests/Utils/Parser/Markdown/data/mark.md delete mode 100644 tests/Utils/Parser/Markdown/data/video.md create mode 100644 tests/Utils/Parser/Markdown/manualdata/address.html create mode 100644 tests/Utils/Parser/Markdown/manualdata/address.md create mode 100644 tests/Utils/Parser/Markdown/manualdata/contact.html create mode 100644 tests/Utils/Parser/Markdown/manualdata/contact.md rename tests/Utils/Parser/Markdown/{data/video.html => manualdata/embed.html} (62%) create mode 100644 tests/Utils/Parser/Markdown/manualdata/embed.md create mode 100644 tests/Utils/Parser/Markdown/manualdata/map.html create mode 100644 tests/Utils/Parser/Markdown/manualdata/map.md create mode 100644 tests/Utils/Parser/Markdown/manualdata/progress.html create mode 100644 tests/Utils/Parser/Markdown/manualdata/progress.md create mode 100644 tests/Utils/Parser/Markdown/manualdata/spoiler.html create mode 100644 tests/Utils/Parser/Markdown/manualdata/spoiler.md create mode 100644 tests/Utils/Parser/Markdown/manualdata/spoiler_block.html create mode 100644 tests/Utils/Parser/Markdown/manualdata/spoiler_block.md create mode 100644 tests/Utils/Parser/Markdown/manualdata/typographer.html create mode 100644 tests/Utils/Parser/Markdown/manualdata/typographer.md diff --git a/Utils/Parser/Markdown/Markdown.php b/Utils/Parser/Markdown/Markdown.php index 559aeae57..735a4a0ac 100755 --- a/Utils/Parser/Markdown/Markdown.php +++ b/Utils/Parser/Markdown/Markdown.php @@ -32,6 +32,23 @@ use phpOMS\Uri\UriFactory; * @see https://github.com/BenjaminHoegh/ParsedownExtended * @see https://github.com/doowzs/parsedown-extreme * @since 1.0.0 + * + * @todo: Add + * 2. Calendar (own widget) + * 3. Event (own widget) + * 4. Tasks (own widget) + * 5. Vote/Survey (own widget) + * 6. Website link/embed widgets (facebook, linkedIn, twitter, ...) + * 7. User/Supplier/Client/Employee (own widget, should make use of schema) + * 8. Address (own widget, should make use of schema) + * 9. Contact (own widget, should make use of schema) + * 10. Item (own widget, should make use of schema) + * 11. Progress radial + * 12. Timeline horizontal/vertical/matrix + * 14. Tabs horizontal/vertical + * 15. Checklist (own widget) + * 16. Gallery + * 17. Form (own widget) */ class Markdown { @@ -70,7 +87,7 @@ class Markdown * @since 1.0.0 */ protected array $underlineRegex = [ - '_' => '/^__((?:\\\\_|[^_]|_[^_]*+_)+?)__(?!_)/us', + '_' => '/^[_]{2}((?:\\\\\_|[^_]|[_][^_]_+[_])+?)[_]{2}(?![_])/s', ]; /** @@ -81,7 +98,6 @@ class Markdown */ protected array $emRegex = [ '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', - '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', ]; /** @@ -275,7 +291,7 @@ class Markdown * @since 1.0.0 */ private const CONTINUABLE = [ - 'Code', 'Comment', 'FencedCode', 'List', 'Quote', 'Table', 'Math', 'Checkbox', 'Footnote', 'DefinitionList', 'Markup' + 'Code', 'Comment', 'FencedCode', 'List', 'Quote', 'Table', 'Math', 'Spoiler', 'Checkbox', 'Footnote', 'DefinitionList', 'Markup' ]; /** @@ -285,7 +301,7 @@ class Markdown * @since 1.0.0 */ private const COMPLETABLE = [ - 'Math', 'Table', 'Checkbox', 'Footnote', 'Markup', 'Code', 'FencedCode', 'List' + 'Math', 'Spoiler', 'Table', 'Checkbox', 'Footnote', 'Markup', 'Code', 'FencedCode', 'List' ]; /** @@ -424,7 +440,7 @@ class Markdown // Marks if ($this->options['mark'] ?? true) { - $this->inlineTypes['='][] = 'mark'; + $this->inlineTypes['='][] = 'Mark'; $this->inlineMarkerList .= '='; } @@ -434,6 +450,12 @@ class Markdown $this->inlineMarkerList .= '['; } + // Spoiler + if ($this->options['spoiler'] ?? false) { + $this->inlineTypes['>'][] = 'Spoiler'; + $this->inlineMarkerList .= '='; + } + // Inline Math if ($this->options['math'] ?? false) { $this->inlineTypes['\\'][] = 'Math'; @@ -473,32 +495,19 @@ class Markdown $this->inlineMarkerList .= '?'; } - // Smartypants - if ($this->options['smarty'] ?? false) { - $this->inlineTypes['<'][] = 'Smartypants'; - $this->inlineMarkerList .= '<'; - $this->inlineTypes['>'][] = 'Smartypants'; - $this->inlineMarkerList .= '>'; - $this->inlineTypes['-'][] = 'Smartypants'; - $this->inlineMarkerList .= '-'; - $this->inlineTypes['.'][] = 'Smartypants'; - $this->inlineMarkerList .= '.'; - $this->inlineTypes["'"][] = 'Smartypants'; - $this->inlineMarkerList .= "'"; - $this->inlineTypes['"'][] = 'Smartypants'; - $this->inlineMarkerList .= '"'; - $this->inlineTypes['`'][] = 'Smartypants'; - $this->inlineMarkerList .= '`'; - } - // Block Math if ($this->options['math'] ?? false) { $this->blockTypes['\\'][] = 'Math'; $this->blockTypes['$'][] = 'Math'; } - // Task - if ($this->options['lists']['tasks'] ?? true) { + // Block Spoiler + if ($this->options['spoiler'] ?? false) { + $this->blockTypes['?'][] = 'Spoiler'; + } + + // Checkbox + if ($this->options['lists']['checkbox'] ?? true) { $this->blockTypes['['][] = 'Checkbox'; } @@ -507,6 +516,24 @@ class Markdown $this->inlineTypes['['][] = 'Embeding'; $this->inlineMarkerList .= '['; } + + // Map + if ($this->options['map'] ?? false) { + $this->inlineTypes['['][] = 'Map'; + $this->inlineMarkerList .= '['; + } + + // Address + if ($this->options['address'] ?? false) { + $this->inlineTypes['['][] = 'Address'; + $this->inlineMarkerList .= '['; + } + + // Contact + if ($this->options['contact'] ?? false) { + $this->inlineTypes['['][] = 'Contact'; + $this->inlineMarkerList .= '['; + } } /** @@ -518,7 +545,7 @@ class Markdown * * @since 1.0.0 */ - public static function parse($text) : string + public static function parse(string $text) : string { $parsedown = new self(); @@ -1205,6 +1232,30 @@ class Markdown ]; } + /** + * Handle marks + * + * @param array{text:string, context:string, before:string} $excerpt Inline data + * + * @return null|array{extent:int, element:array} + * + * @since 1.0.0 + */ + protected function inlineSpoiler(array $excerpt) : ?array + { + if (\preg_match('/^>!(.*?)! \strlen($matches[0]), + 'element' => [ + 'name' => 'mark', + 'text' => $matches[2], + ], + ]; + } + /** * Handle keystrokes * @@ -1322,6 +1373,232 @@ class Markdown return null; } + /** + * Handle map + * + * @param array{text:string, context:string, before:string} $excerpt Inline data + * + * @return null|array{extent:int, element:array} + * + * @since 1.0.0 + */ + protected function inlineMap(array $excerpt) : ?array + { + if (!($this->options['map'] ?? false) + || (\preg_match('/\[map(?:\s+(?:name="([^"]+)"|country="([^"]+)"|city="([^"]+)"|zip="([^"]+)"|address="([^"]+)"|lat="([^"]+)"|lon="([^"]+)")){0,3}\]/', $excerpt['text'], $matches) !== 1) + ) { + return null; + } + + $name = $matches[1]; + $country = $matches[2]; + $city = $matches[3]; + $zip = $matches[4]; + $address = $matches[5]; + + $lat = empty($matches[6]) ? '' : (float) $matches[6]; + $lon = empty($matches[7]) ? '' : (float) $matches[7]; + + if ($lat === '' || $lon === '') { + [$lat, $lon] = \phpOMS\Api\Geocoding\Nominatim::geocoding($country, $city, $address, $zip); + } + + return [ + 'extent' => \strlen($matches[0]), + 'element' => [ + 'name' => 'div', + 'text' => '', + 'attributes' => [ + 'id' => '-' . \bin2hex(\random_bytes(4)), + 'class' => 'map', + 'data-lat' => $lat, + 'data-lon' => $lon, + ] + ], + ]; + } + + /** + * Handle address + * + * @param array{text:string, context:string, before:string} $excerpt Inline data + * + * @return null|array{extent:int, element:array} + * + * @since 1.0.0 + */ + protected function inlineAddress(array $excerpt) : ?array + { + if (!($this->options['address'] ?? false) + || (\preg_match('/\[addr(?:\s+(?:name="([^"]+)"|country="([^"]+)"|city="([^"]+)"|zip="([^"]+)"|address="([^"]+)")){0,3}\]/', $excerpt['text'], $matches) !== 1) + ) { + return null; + } + + $name = $matches[1]; + $country = $matches[2]; + $city = $matches[3]; + $zip = $matches[4]; + $address = $matches[5]; + + return [ + 'extent' => \strlen($matches[0]), + 'element' => [ + 'name' => 'div', + //'text' => '', + 'attributes' => [ + 'class' => 'addressWidget', + ], + 'elements' => [ + [ + 'name' => 'span', + 'text' => $name, + 'attributes' => ['class' => 'addressWidget-name'], + ], + [ + 'name' => 'span', + 'text' => $address, + 'attributes' => ['class' => 'addressWidget-address'], + ], + [ + 'name' => 'span', + 'text' => $zip, + 'attributes' => ['class' => 'addressWidget-zip'], + ], + [ + 'name' => 'span', + 'text' => $city, + 'attributes' => ['class' => 'addressWidget-city'], + ], + [ + 'name' => 'span', + 'text' => $country, + 'attributes' => ['class' => 'addressWidget-country'], + ], + ], + ], + ]; + } + + /** + * Handle contact + * + * @param array{text:string, context:string, before:string} $excerpt Inline data + * + * @return null|array{extent:int, element:array} + * + * @since 1.0.0 + */ + protected function inlineContact(array $excerpt) : ?array + { + if (!($this->options['contact'] ?? false) + || (\preg_match('/\[contact.*?([a-zA-Z]+)="([a-zA-Z0-9\-_]+)"\]/', $excerpt['text'], $matches) !== 1) + ) { + return null; + } + + $src = ''; + switch ($matches[1]) { + case 'email': + $src = 'Resources/icons/company/email.svg'; + break; + case 'phone': + $src = 'Resources/icons/company/phone.svg'; + break; + case 'twitter': + $src = 'Resources/icons/company/twitter.svg'; + break; + case 'instagram': + $src = 'Resources/icons/company/instagram.svg'; + break; + case 'discord': + $src = 'Resources/icons/company/discord.svg'; + break; + case 'slack': + $src = 'Resources/icons/company/slack.svg'; + break; + case 'teams': + $src = 'Resources/icons/company/teams.svg'; + break; + case 'facebook': + $src = 'Resources/icons/company/facebook.svg'; + break; + case 'youtube': + $src = 'Resources/icons/company/youtube.svg'; + break; + case 'paypal': + $src = 'Resources/icons/company/paypal.svg'; + break; + } + + return [ + 'extent' => \strlen($matches[0]), + 'element' => [ + 'name' => 'a', + //'text' => '', + 'attributes' => [ + 'class' => 'contactWidget', + 'href' => '', + ], + 'elements' => [ + [ + 'name' => 'img', + 'attributes' => [ + 'class' => 'contactWidget-icon', + 'src' => $src + ], + ], + [ + 'name' => 'span', + 'text' => $matches[2], + 'attributes' => ['class' => 'contactWidget-contact'], + ] + ], + + ], + ]; + } + + /** + * Handle progress + * + * @param array{text:string, context:string, before:string} $excerpt Inline data + * + * @return null|array{extent:int, element:array} + * + * @since 1.0.0 + */ + protected function inlineProgress(array $excerpt) : ?array + { + if (!($this->options['progress'] ?? false) + || (\preg_match('/\[progress(?:\s+(?:type="([^"]+)"|percent="([^"]+)"|value="([^"]+)")){0,3}\]/', $excerpt['text'], $matches) !== 1) + ) { + return null; + } + + // $type = $matches[1] ?? 'meter'; + $percent = $matches[2] ?? ($matches[3]); + $value = $matches[3] ?? $matches[2]; + + if ($percent === '' + || $value === '' + ) { + return null; + } + + return [ + 'extent' => \strlen($matches[0]), + 'element' => [ + 'name' => 'progress', + //'text' => '', + 'attributes' => [ + 'value' => $value, + 'max' => '100', + ] + ], + ]; + } + /** * Handle super script * @@ -1406,140 +1683,6 @@ class Markdown ]; } - /** - * Handle smartypants - * - * @param array{text:string, context:string, before:string} $excerpt Inline data - * - * @return null|array{extent:int, element:array} - * - * @since 1.0.0 - */ - protected function inlineSmartypants(array $excerpt) : ?array - { - if (\preg_match('/(``)(?!\s)([^"\'`]{1,})(\'\')|(\")(?!\s)([^\"]{1,})(\")|(\')(?!\s)([^\']{1,})(\')|(<{2})(?!\s)([^<>]{1,})(>{2})|(\.{3})|(-{3})|(-{2})/i', $excerpt['text'], $matches) !== 1) { - return null; - } - - // Substitutions - $backtickDoublequoteOpen = $this->options['smarty']['substitutions']['left-double-quote'] ?? '“'; - $backtickDoublequoteClose = $this->options['smarty']['substitutions']['right-double-quote'] ?? '”'; - - $smartDoublequoteOpen = $this->options['smarty']['substitutions']['left-double-quote'] ?? '“'; - $smartDoublequoteClose = $this->options['smarty']['substitutions']['right-double-quote'] ?? '”'; - $smartSinglequoteOpen = $this->options['smarty']['substitutions']['left-single-quote'] ?? '‘'; - $smartSinglequoteClose = $this->options['smarty']['substitutions']['right-single-quote'] ?? '’'; - - $leftAngleQuote = $this->options['smarty']['substitutions']['left-angle-quote'] ?? '«'; - $rightAngleQuote = $this->options['smarty']['substitutions']['right-angle-quote'] ?? '»'; - - $matches = \array_values(\array_filter($matches)); - - // Smart backticks - $smartBackticks = $this->options['smarty']['smart_backticks'] ?? false; - - if ($smartBackticks && $matches[1] === '``') { - $length = \strlen(\trim($excerpt['before'])); - if ($length > 0) { - return null; - } - - return [ - 'extent' => \strlen($matches[0]), - 'element' => [ - 'text' => \html_entity_decode($backtickDoublequoteOpen).$matches[2].\html_entity_decode($backtickDoublequoteClose), - ], - ]; - } - - // Smart quotes - $smartQuotes = $this->options['smarty']['smart_quotes'] ?? true; - - if ($smartQuotes) { - if ($matches[1] === "'") { - $length = \strlen(\trim($excerpt['before'])); - if ($length > 0) { - return null; - } - - return [ - 'extent' => \strlen($matches[0]), - 'element' => [ - 'text' => \html_entity_decode($smartSinglequoteOpen).$matches[2].\html_entity_decode($smartSinglequoteClose), - ], - ]; - } - - if ($matches[1] === '"') { - $length = \strlen(\trim($excerpt['before'])); - if ($length > 0) { - return null; - } - - return [ - 'extent' => \strlen($matches[0]), - 'element' => [ - 'text' => \html_entity_decode($smartDoublequoteOpen).$matches[2].\html_entity_decode($smartDoublequoteClose), - ], - ]; - } - } - - // Smart angled quotes - $smartAngledQuotes = $this->options['smarty']['smart_angled_quotes'] ?? true; - - if ($smartAngledQuotes && $matches[1] === '<<') { - $length = \strlen(\trim($excerpt['before'])); - if ($length > 0) { - return null; - } - - return [ - 'extent' => \strlen($matches[0]), - 'element' => [ - 'text' => \html_entity_decode($leftAngleQuote).$matches[2].\html_entity_decode($rightAngleQuote), - ], - ]; - } - - // Smart dashes - $smartDashes = $this->options['smarty']['smart_dashes'] ?? true; - - if ($smartDashes) { - if ($matches[1] === '---') { - return [ - 'extent' => \strlen($matches[0]), - 'element' => [ - 'rawHtml' => $this->options['smarty']['substitutions']['mdash'] ?? '—', - ], - ]; - } - - if ($matches[1] === '--') { - return [ - 'extent' => \strlen($matches[0]), - 'element' => [ - 'rawHtml' => $this->options['smarty']['substitutions']['ndash'] ?? '–', - ], - ]; - } - } - - // Smart ellipses - $smartEllipses = $this->options['smarty']['smart_ellipses'] ?? true; - - if ($smartEllipses && $matches[1] === '...') { - return [ - 'extent' => \strlen($matches[0]), - 'element' => [ - 'rawHtml' => $this->options['smarty']['substitutions']['ellipses'] ?? '…', - ], - ]; - } - - return null; - } - /** * Handle math * @@ -1832,7 +1975,7 @@ class Markdown return null; } - list($name, $pattern) = $line['text'][0] <= '-' ? ['ul', '[*+-]'] : ['ol', '[0-9]{1,9}+[.\)]']; + [$name, $pattern] = $line['text'][0] <= '-' ? ['ul', '[*+-]'] : ['ol', '[0-9]{1,9}+[.\)]']; if (\preg_match('/^(' . $pattern . '([ ]++|$))(.*+)/', $line['text'], $matches) !== 1) { return null; @@ -2320,6 +2463,7 @@ class Markdown return $block; } + if (\preg_match('/^(?options['code']['blocks'] ?? true) + || !($this->options['code'] ?? true) + ) { + return null; + } + + $marker = $line['text'][0]; + $openerLength = \strspn($line['text'], $marker); + + if ($openerLength < 3) { + return null; + } + + $summary = \trim(\preg_replace('/^\?{3}([^\s]+)(.+)?/s', '$1', $line['text'])); + + $infostring = \trim(\substr($line['text'], $openerLength), "\t "); + if (\strpos($infostring, '?') !== false) { + return null; + } + + return [ + 'char' => $marker, + 'openerLength' => $openerLength, + 'element' => [ + 'name' => 'details', + 'elements' => [ + [ + 'name' => 'summary', + 'text' => $summary, + ], + [ + 'name' => 'span', // @todo: check if without span possible + 'text' => '', + ] + ], + ], + ]; + } + /** * Complete block table * @@ -2639,9 +2834,13 @@ class Markdown */ protected function blockCheckboxComplete(array $block) : array { + if ($this->markupEscaped || $this->safeMode) { + $text = \htmlspecialchars($block['text'], \ENT_QUOTES, 'UTF-8'); + } + $html = $block['handler'] === 'unchecked' - ? $this->checkboxUnchecked($block['text']) - : $this->checkboxChecked($block['text']); + ? ' ' . $this->formatOnce($text) + : ' ' . $this->formatOnce($text); $block['element'] = [ 'rawHtml' => $html, @@ -2651,42 +2850,6 @@ class Markdown return $block; } - /** - * Generate unchecked checkbox html - * - * @param string Checkbox text - * - * @return string - * - * @since 1.0.0 - */ - protected function checkboxUnchecked(string $text) : string - { - if ($this->markupEscaped || $this->safeMode) { - $text = \htmlspecialchars($text, \ENT_QUOTES, 'UTF-8'); - } - - return ' ' . $this->formatOnce($text); - } - - /** - * Generate checked checkbox html - * - * @param string Checkbox text - * - * @return string - * - * @since 1.0.0 - */ - protected function checkboxChecked(string $text) : string - { - if ($this->markupEscaped || $this->safeMode) { - $text = \htmlspecialchars($text, \ENT_QUOTES, 'UTF-8'); - } - - return ' ' . $this->formatOnce($text); - } - /** * Formats text without double escaping * @@ -3259,24 +3422,21 @@ class Markdown ++$this->definitionData['Footnote'][$name]['count']; - if (!isset($this->definitionData['Footnote'][$name]['number'])) - { + if (!isset($this->definitionData['Footnote'][$name]['number'])) { $this->definitionData['Footnote'][$name]['number'] = ++ $this->footnoteCount; // » & } - $element = [ - 'name' => 'sup', - 'attributes' => ['id' => 'fnref' . $this->definitionData['Footnote'][$name]['count'] . ':' . $name], - 'element' => [ - 'name' => 'a', - 'attributes' => ['href' => '#fn:' . $name, 'class' => 'footnote-ref'], - 'text' => $this->definitionData['Footnote'][$name]['number'], - ], - ]; - return [ 'extent' => \strlen($matches[0]), - 'element' => $element, + 'element' => [ + 'name' => 'sup', + 'attributes' => ['id' => 'fnref' . $this->definitionData['Footnote'][$name]['count'] . ':' . $name], + 'element' => [ + 'name' => 'a', + 'attributes' => ['href' => '#fn:' . $name, 'class' => 'footnote-ref'], + 'text' => $this->definitionData['Footnote'][$name]['number'], + ], + ] ]; } @@ -3848,6 +4008,57 @@ class Markdown return $block; } + /** + * Continue block spoiler + * + * @param array{body:string, indent:int, text:string} $line Line data + * @param array $block Current block + * + * @return null|array + * + * @since 1.0.0 + */ + protected function blockSpoilerContinue(array $line, array $block) : ?array + { + if (isset($block['complete'])) { + return null; + } + + if (isset($block['interrupted'])) { + $block['element']['element']['text'] .= \str_repeat("\n", $block['interrupted']); + + unset($block['interrupted']); + } + + if (($len = \strspn($line['text'], $block['char'])) >= $block['openerLength'] + && \rtrim(\substr($line['text'], $len), ' ') === '' + ) { + $block['element']['element']['text'] = \substr($block['element']['element']['text'], 1); + + $block['complete'] = true; + + return $block; + } + + $block['element']['element']['text'] .= "\n" . $line['body']; + + return $block; + } + + /** + * Complete block spoiler + * + * @param array $block Current block + * + * @return array + * + * @since 1.0.0 + */ + protected function blockSpoilerComplete(array $block) : array + { + return $block; + } + /** * Continue block list * @@ -4130,10 +4341,10 @@ class Markdown return null; } - $Definition = $this->definitionData['Reference'][$definition]; + $definition = $this->definitionData['Reference'][$definition]; - $element['attributes']['href'] = $Definition['url']; - $element['attributes']['title'] = $Definition['title']; + $element['attributes']['href'] = $definition['url']; + $element['attributes']['title'] = $definition['title']; } return [ diff --git a/tests/Utils/Parser/Markdown/MarkdownTest.php b/tests/Utils/Parser/Markdown/MarkdownTest.php index abf8c207e..d35bfc902 100755 --- a/tests/Utils/Parser/Markdown/MarkdownTest.php +++ b/tests/Utils/Parser/Markdown/MarkdownTest.php @@ -70,6 +70,95 @@ final class MarkdownTest extends \PHPUnit\Framework\TestCase ); } + public function testMap() : void + { + $parser = new Markdown([ + 'map' => true + ]); + + self::assertEquals( + \file_get_contents(__DIR__ . '/manualdata/map.html'), + $parser->text(\file_get_contents(__DIR__ . '/manualdata/map.md')) + ); + } + + public function testContact() : void + { + $parser = new Markdown([ + 'contact' => true + ]); + + self::assertEquals( + \file_get_contents(__DIR__ . '/manualdata/contact.html'), + $parser->text(\file_get_contents(__DIR__ . '/manualdata/contact.md')) + ); + } + + public function testTypographer() : void + { + $parser = new Markdown([ + 'typographer' => true + ]); + + self::assertEquals( + \file_get_contents(__DIR__ . '/manualdata/typographer.html'), + $parser->text(\file_get_contents(__DIR__ . '/manualdata/typographer.md')) + ); + } + + public function testAddress() : void + { + $parser = new Markdown([ + 'address' => true + ]); + + self::assertEquals( + \file_get_contents(__DIR__ . '/manualdata/address.html'), + $parser->text(\file_get_contents(__DIR__ . '/manualdata/address.md')) + ); + } + + public function testProgress() : void + { + $parser = new Markdown([ + 'progress' => true + ]); + + self::assertEquals( + \file_get_contents(__DIR__ . '/manualdata/progress.html'), + $parser->text(\file_get_contents(__DIR__ . '/manualdata/progress.md')) + ); + } + + public function testSpoiler() : void + { + $parser = new Markdown([ + 'spoiler' => true + ]); + + self::assertEquals( + \file_get_contents(__DIR__ . '/manualdata/spoiler.html'), + $parser->text(\file_get_contents(__DIR__ . '/manualdata/spoiler.md')) + ); + + self::assertEquals( + \file_get_contents(__DIR__ . '/manualdata/spoiler_block.html'), + $parser->text(\file_get_contents(__DIR__ . '/manualdata/spoiler_block.md')) + ); + } + + public function testEmbed() : void + { + $parser = new Markdown([ + 'embeding' => true + ]); + + self::assertEquals( + \file_get_contents(__DIR__ . '/manualdata/embed.html'), + $parser->text(\file_get_contents(__DIR__ . '/manualdata/embed.md')) + ); + } + public function testMath() : void { $parser = new Markdown([ diff --git a/tests/Utils/Parser/Markdown/data/checkbox.htm b/tests/Utils/Parser/Markdown/data/checkbox.htm new file mode 100644 index 000000000..e69de29bb diff --git a/tests/Utils/Parser/Markdown/data/checkbox.md b/tests/Utils/Parser/Markdown/data/checkbox.md new file mode 100644 index 000000000..1949d401f --- /dev/null +++ b/tests/Utils/Parser/Markdown/data/checkbox.md @@ -0,0 +1,2 @@ +- [ ] Unchecked +- [x] Checked \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/data/emoji.html b/tests/Utils/Parser/Markdown/data/emoji.html new file mode 100644 index 000000000..7c88617e6 --- /dev/null +++ b/tests/Utils/Parser/Markdown/data/emoji.html @@ -0,0 +1 @@ +📹 \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/data/emoji.md b/tests/Utils/Parser/Markdown/data/emoji.md new file mode 100644 index 000000000..914af9824 --- /dev/null +++ b/tests/Utils/Parser/Markdown/data/emoji.md @@ -0,0 +1 @@ +:video_camera: \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/data/emphasis.html b/tests/Utils/Parser/Markdown/data/emphasis.html index 60ff4bd8b..4571c85f8 100755 --- a/tests/Utils/Parser/Markdown/data/emphasis.html +++ b/tests/Utils/Parser/Markdown/data/emphasis.html @@ -1,4 +1,4 @@ -

underscore, asterisk, one two, three four, a, b

+

underscore, asterisk, one two, three four, a, b

strong and em and strong and em

line line diff --git a/tests/Utils/Parser/Markdown/data/emphasis.md b/tests/Utils/Parser/Markdown/data/emphasis.md index 85b9d2299..b4f6abe1b 100755 --- a/tests/Utils/Parser/Markdown/data/emphasis.md +++ b/tests/Utils/Parser/Markdown/data/emphasis.md @@ -1,4 +1,4 @@ -_underscore_, *asterisk*, _one two_, *three four*, _a_, *b* +__underscore__, *asterisk*, _one two_, *three four*, _a_, *b* **strong** and *em* and **strong** and *em* diff --git a/tests/Utils/Parser/Markdown/data/keystroke.html b/tests/Utils/Parser/Markdown/data/keystroke.html new file mode 100644 index 000000000..a29497cb3 --- /dev/null +++ b/tests/Utils/Parser/Markdown/data/keystroke.html @@ -0,0 +1 @@ +ctrl+shift+A \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/data/keystroke.md b/tests/Utils/Parser/Markdown/data/keystroke.md new file mode 100644 index 000000000..281e60490 --- /dev/null +++ b/tests/Utils/Parser/Markdown/data/keystroke.md @@ -0,0 +1 @@ +[[ctrl]] + [[shift]] + [[A]] \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/data/mark.html b/tests/Utils/Parser/Markdown/data/mark.html new file mode 100644 index 000000000..68f61fb40 --- /dev/null +++ b/tests/Utils/Parser/Markdown/data/mark.html @@ -0,0 +1 @@ +Mark test \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/data/mark.md b/tests/Utils/Parser/Markdown/data/mark.md new file mode 100644 index 000000000..3f6a3099b --- /dev/null +++ b/tests/Utils/Parser/Markdown/data/mark.md @@ -0,0 +1 @@ +==Mark test== \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/data/video.md b/tests/Utils/Parser/Markdown/data/video.md deleted file mode 100644 index 7d2734ba3..000000000 --- a/tests/Utils/Parser/Markdown/data/video.md +++ /dev/null @@ -1 +0,0 @@ -[video src="https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"] \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/address.html b/tests/Utils/Parser/Markdown/manualdata/address.html new file mode 100644 index 000000000..ed1c1e308 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/address.html @@ -0,0 +1 @@ +[addr name="AddrName" address="Addr" city="AddrCity" country="AddrCoutry" zip="AddrZip"] \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/address.md b/tests/Utils/Parser/Markdown/manualdata/address.md new file mode 100644 index 000000000..ed1c1e308 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/address.md @@ -0,0 +1 @@ +[addr name="AddrName" address="Addr" city="AddrCity" country="AddrCoutry" zip="AddrZip"] \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/contact.html b/tests/Utils/Parser/Markdown/manualdata/contact.html new file mode 100644 index 000000000..3b56536b9 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/contact.html @@ -0,0 +1,9 @@ +[contact phone="+49 123 456 789"] +[contact facebook="@jinggaApp"] +[contact discord="jingga"] +[contact email="test@email.com"] +[contact twitter="@jinggaApp"] +[contact youtube="@jinggaApp"] +[contact instagram="jinggaApp"] +[contact slack="jinggaApp"] +[contact teams="jinggaApp"] \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/contact.md b/tests/Utils/Parser/Markdown/manualdata/contact.md new file mode 100644 index 000000000..3b56536b9 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/contact.md @@ -0,0 +1,9 @@ +[contact phone="+49 123 456 789"] +[contact facebook="@jinggaApp"] +[contact discord="jingga"] +[contact email="test@email.com"] +[contact twitter="@jinggaApp"] +[contact youtube="@jinggaApp"] +[contact instagram="jinggaApp"] +[contact slack="jinggaApp"] +[contact teams="jinggaApp"] \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/data/video.html b/tests/Utils/Parser/Markdown/manualdata/embed.html similarity index 62% rename from tests/Utils/Parser/Markdown/data/video.html rename to tests/Utils/Parser/Markdown/manualdata/embed.html index 00eca47ef..401dc2ae1 100644 --- a/tests/Utils/Parser/Markdown/data/video.html +++ b/tests/Utils/Parser/Markdown/manualdata/embed.html @@ -1 +1,2 @@ -

[video src="https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"]

\ No newline at end of file +

[video src="https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"]

+ \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/embed.md b/tests/Utils/Parser/Markdown/manualdata/embed.md new file mode 100644 index 000000000..2a26ec6c9 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/embed.md @@ -0,0 +1,4 @@ +[video src="https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"] +[video src="https://vimeo.com/874474957"] +[video src="https://www.dailymotion.com/video/x3w7rss"] +[video src="test.mp4"] \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/map.html b/tests/Utils/Parser/Markdown/manualdata/map.html new file mode 100644 index 000000000..3ee642cbd --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/map.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/map.md b/tests/Utils/Parser/Markdown/manualdata/map.md new file mode 100644 index 000000000..a7963e89a --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/map.md @@ -0,0 +1 @@ +[map lat="1.0" lon="1.0"] \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/progress.html b/tests/Utils/Parser/Markdown/manualdata/progress.html new file mode 100644 index 000000000..43b83b1d0 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/progress.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/progress.md b/tests/Utils/Parser/Markdown/manualdata/progress.md new file mode 100644 index 000000000..579e077e5 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/progress.md @@ -0,0 +1 @@ +[progress value="33"] \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/spoiler.html b/tests/Utils/Parser/Markdown/manualdata/spoiler.html new file mode 100644 index 000000000..011c08b14 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/spoiler.html @@ -0,0 +1 @@ +This is a >!test spoiler!< in text. \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/spoiler.md b/tests/Utils/Parser/Markdown/manualdata/spoiler.md new file mode 100644 index 000000000..011c08b14 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/spoiler.md @@ -0,0 +1 @@ +This is a >!test spoiler!< in text. \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/spoiler_block.html b/tests/Utils/Parser/Markdown/manualdata/spoiler_block.html new file mode 100644 index 000000000..47ca3f484 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/spoiler_block.html @@ -0,0 +1 @@ +
Test summaryThis is a test spoiler.
\ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/spoiler_block.md b/tests/Utils/Parser/Markdown/manualdata/spoiler_block.md new file mode 100644 index 000000000..f855f1231 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/spoiler_block.md @@ -0,0 +1,3 @@ +???Test summary +This is a test spoiler. +??? \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/typographer.html b/tests/Utils/Parser/Markdown/manualdata/typographer.html new file mode 100644 index 000000000..844c366b5 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/typographer.html @@ -0,0 +1 @@ +© \ No newline at end of file diff --git a/tests/Utils/Parser/Markdown/manualdata/typographer.md b/tests/Utils/Parser/Markdown/manualdata/typographer.md new file mode 100644 index 000000000..e58d56b30 --- /dev/null +++ b/tests/Utils/Parser/Markdown/manualdata/typographer.md @@ -0,0 +1 @@ +(c) \ No newline at end of file