diff --git a/app/Entities/Tools/Markdown/CustomStrikeThroughExtension.php b/app/Entities/Tools/Markdown/CustomStrikeThroughExtension.php new file mode 100644 index 000000000..cb8b0ffc2 --- /dev/null +++ b/app/Entities/Tools/Markdown/CustomStrikeThroughExtension.php @@ -0,0 +1,16 @@ +<?php namespace BookStack\Entities\Tools\Markdown; + +use League\CommonMark\ConfigurableEnvironmentInterface; +use League\CommonMark\Extension\ExtensionInterface; +use League\CommonMark\Extension\Strikethrough\Strikethrough; +use League\CommonMark\Extension\Strikethrough\StrikethroughDelimiterProcessor; + +class CustomStrikeThroughExtension implements ExtensionInterface +{ + + public function register(ConfigurableEnvironmentInterface $environment) + { + $environment->addDelimiterProcessor(new StrikethroughDelimiterProcessor()); + $environment->addInlineRenderer(Strikethrough::class, new CustomStrikethroughRenderer()); + } +} \ No newline at end of file diff --git a/app/Entities/Tools/Markdown/CustomStrikethroughRenderer.php b/app/Entities/Tools/Markdown/CustomStrikethroughRenderer.php new file mode 100644 index 000000000..4371fb84c --- /dev/null +++ b/app/Entities/Tools/Markdown/CustomStrikethroughRenderer.php @@ -0,0 +1,24 @@ +<?php namespace BookStack\Entities\Tools\Markdown; + +use League\CommonMark\ElementRendererInterface; +use League\CommonMark\Extension\Strikethrough\Strikethrough; +use League\CommonMark\HtmlElement; +use League\CommonMark\Inline\Element\AbstractInline; +use League\CommonMark\Inline\Renderer\InlineRendererInterface; + +/** + * This is a somewhat clone of the League\CommonMark\Extension\Strikethrough\StrikethroughRender + * class but modified slightly to use <s> HTML tags instead of <del> in order to + * match front-end markdown-it rendering. + */ +class CustomStrikethroughRenderer implements InlineRendererInterface +{ + public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer) + { + if (!($inline instanceof Strikethrough)) { + throw new \InvalidArgumentException('Incompatible inline type: ' . get_class($inline)); + } + + return new HtmlElement('s', $inline->getData('attributes', []), $htmlRenderer->renderInlines($inline->children())); + } +} \ No newline at end of file diff --git a/app/Entities/Tools/PageContent.php b/app/Entities/Tools/PageContent.php index 91de94211..62982f4ad 100644 --- a/app/Entities/Tools/PageContent.php +++ b/app/Entities/Tools/PageContent.php @@ -1,6 +1,7 @@ <?php namespace BookStack\Entities\Tools; use BookStack\Entities\Models\Page; +use BookStack\Entities\Tools\Markdown\CustomStrikeThroughExtension; use DOMDocument; use DOMNodeList; use DOMXPath; @@ -51,6 +52,7 @@ class PageContent $environment = Environment::createCommonMarkEnvironment(); $environment->addExtension(new TableExtension()); $environment->addExtension(new TaskListExtension()); + $environment->addExtension(new CustomStrikeThroughExtension()); $converter = new CommonMarkConverter([], $environment); return $converter->convertToHtml($markdown); } diff --git a/tests/Entity/PageContentTest.php b/tests/Entity/PageContentTest.php index 857645823..6d5200794 100644 --- a/tests/Entity/PageContentTest.php +++ b/tests/Entity/PageContentTest.php @@ -461,4 +461,22 @@ class PageContentTest extends TestCase $pageView = $this->get($page->getUrl()); $pageView->assertElementExists('.page-content input[type=checkbox]'); } + + public function test_page_markdown_strikethrough_rendering() + { + $this->asEditor(); + $page = Page::query()->first(); + + $content = '~~some crossed out text~~'; + $this->put($page->getUrl(), [ + 'name' => $page->name, 'markdown' => $content, + 'html' => '', 'summary' => '' + ]); + + $page->refresh(); + $this->assertStringMatchesFormat('%A<s%A>some crossed out text</s>%A', $page->html); + + $pageView = $this->get($page->getUrl()); + $pageView->assertElementExists('.page-content p > s'); + } }