1<?php 2 3/** 4 * webtrees: online genealogy 5 * Copyright (C) 2023 webtrees development team 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 */ 17 18declare(strict_types=1); 19 20namespace Fisharebest\Webtrees\Factories; 21 22use Fisharebest\Webtrees\CommonMark\CensusTableExtension; 23use Fisharebest\Webtrees\CommonMark\XrefExtension; 24use Fisharebest\Webtrees\Contracts\MarkdownFactoryInterface; 25use Fisharebest\Webtrees\Tree; 26use League\CommonMark\Environment\Environment; 27use League\CommonMark\Extension\Autolink\AutolinkExtension; 28use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension; 29use League\CommonMark\Extension\CommonMark\Node\Inline\Link; 30use League\CommonMark\Extension\CommonMark\Renderer\Inline\LinkRenderer; 31use League\CommonMark\Extension\Table\TableExtension; 32use League\CommonMark\MarkdownConverter; 33use League\CommonMark\Node\Block\Document; 34use League\CommonMark\Node\Block\Paragraph; 35use League\CommonMark\Node\Inline\Newline; 36use League\CommonMark\Node\Inline\Text; 37use League\CommonMark\Parser\Inline\NewlineParser; 38use League\CommonMark\Renderer\Block\DocumentRenderer; 39use League\CommonMark\Renderer\Block\ParagraphRenderer; 40use League\CommonMark\Renderer\Inline\NewlineRenderer; 41use League\CommonMark\Renderer\Inline\TextRenderer; 42use League\CommonMark\Util\HtmlFilter; 43 44use function strip_tags; 45use function strtr; 46 47/** 48 * Create a markdown converter. 49 */ 50class MarkdownFactory implements MarkdownFactoryInterface 51{ 52 // Commonmark uses the self-closing form of this tag, so we do the same for consistency. 53 public const string BREAK = '<br />'; 54 55 protected const array CONFIG_AUTOLINK = [ 56 'allow_unsafe_links' => false, 57 'html_input' => HtmlFilter::ESCAPE, 58 'renderer' => [ 59 'soft_break' => self::BREAK, 60 ], 61 ]; 62 63 protected const array CONFIG_MARKDOWN = [ 64 'allow_unsafe_links' => false, 65 'html_input' => HtmlFilter::ESCAPE, 66 'renderer' => [ 67 'soft_break' => self::BREAK, 68 ], 69 'table' => [ 70 'wrap' => [ 71 'enabled' => true, 72 'tag' => 'div', 73 'attributes' => [ 74 'class' => 'table-responsive', 75 ], 76 ], 77 ], 78 ]; 79 80 /** 81 * @param string $markdown 82 * @param Tree|null $tree 83 * 84 * @return string 85 */ 86 public function autolink(string $markdown, Tree|null $tree = null): string 87 { 88 // Create a minimal commonmark processor - just add support for auto-links. 89 $environment = new Environment(static::CONFIG_AUTOLINK); 90 $environment->addInlineParser(new NewlineParser()); 91 $environment->addRenderer(Document::class, new DocumentRenderer()); 92 $environment->addRenderer(Paragraph::class, new ParagraphRenderer()); 93 $environment->addRenderer(Text::class, new TextRenderer()); 94 $environment->addRenderer(Link::class, new LinkRenderer()); 95 $environment->addRenderer(Newline::class, new NewlineRenderer()); 96 $environment->addExtension(new AutolinkExtension()); 97 98 // Optionally create links to other records. 99 if ($tree instanceof Tree) { 100 $environment->addExtension(new XrefExtension($tree)); 101 } 102 103 $converter = new MarkDownConverter($environment); 104 105 $html = $converter->convert($markdown)->getContent(); 106 107 // We should only have certain tags. Make sure of this. 108 $html = strip_tags($html, ['a', 'br', 'p']); 109 110 // The markdown convert adds newlines, but not in a documented way. Safest to ignore them. 111 return strtr($html, ["\n" => '']); 112 } 113 114 /** 115 * @param string $markdown 116 * @param Tree|null $tree 117 * 118 * @return string 119 */ 120 public function markdown(string $markdown, Tree|null $tree = null): string 121 { 122 $environment = new Environment(static::CONFIG_MARKDOWN); 123 $environment->addExtension(new CommonMarkCoreExtension()); 124 $environment->addExtension(new TableExtension()); 125 126 // Convert webtrees 1.x style census tables to commonmark format. 127 $environment->addExtension(new CensusTableExtension()); 128 129 // Optionally create links to other records. 130 if ($tree instanceof Tree) { 131 $environment->addExtension(new XrefExtension($tree)); 132 } 133 134 $converter = new MarkDownConverter($environment); 135 136 $html = $converter->convert($markdown)->getContent(); 137 138 // The markdown convert adds newlines, but not in a documented way. Safest to ignore them. 139 return strtr($html, ["\n" => '']); 140 } 141} 142