14d35caa7SGreg Roach<?php 24d35caa7SGreg Roach 34d35caa7SGreg Roach/** 44d35caa7SGreg Roach * webtrees: online genealogy 5d11be702SGreg Roach * Copyright (C) 2023 webtrees development team 64d35caa7SGreg Roach * This program is free software: you can redistribute it and/or modify 74d35caa7SGreg Roach * it under the terms of the GNU General Public License as published by 84d35caa7SGreg Roach * the Free Software Foundation, either version 3 of the License, or 94d35caa7SGreg Roach * (at your option) any later version. 104d35caa7SGreg Roach * This program is distributed in the hope that it will be useful, 114d35caa7SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 124d35caa7SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 134d35caa7SGreg Roach * GNU General Public License for more details. 144d35caa7SGreg Roach * You should have received a copy of the GNU General Public License 154d35caa7SGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 164d35caa7SGreg Roach */ 174d35caa7SGreg Roach 184d35caa7SGreg Roachdeclare(strict_types=1); 194d35caa7SGreg Roach 204d35caa7SGreg Roachnamespace Fisharebest\Webtrees\Factories; 214d35caa7SGreg Roach 224d35caa7SGreg Roachuse Fisharebest\Webtrees\CommonMark\CensusTableExtension; 234d35caa7SGreg Roachuse Fisharebest\Webtrees\CommonMark\XrefExtension; 244d35caa7SGreg Roachuse Fisharebest\Webtrees\Contracts\MarkdownFactoryInterface; 254d35caa7SGreg Roachuse Fisharebest\Webtrees\Tree; 266f595250SGreg Roachuse League\CommonMark\Environment\Environment; 274d35caa7SGreg Roachuse League\CommonMark\Extension\Autolink\AutolinkExtension; 286f595250SGreg Roachuse League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension; 296f595250SGreg Roachuse League\CommonMark\Extension\CommonMark\Node\Inline\Link; 306f595250SGreg Roachuse League\CommonMark\Extension\CommonMark\Renderer\Inline\LinkRenderer; 316f595250SGreg Roachuse League\CommonMark\Extension\Table\TableExtension; 326f595250SGreg Roachuse League\CommonMark\MarkdownConverter; 336f595250SGreg Roachuse League\CommonMark\Node\Block\Document; 346f595250SGreg Roachuse League\CommonMark\Node\Block\Paragraph; 35db3f0368SGreg Roachuse League\CommonMark\Node\Inline\Newline; 366f595250SGreg Roachuse League\CommonMark\Node\Inline\Text; 37db3f0368SGreg Roachuse League\CommonMark\Parser\Inline\NewlineParser; 386f595250SGreg Roachuse League\CommonMark\Renderer\Block\DocumentRenderer; 396f595250SGreg Roachuse League\CommonMark\Renderer\Block\ParagraphRenderer; 40db3f0368SGreg Roachuse League\CommonMark\Renderer\Inline\NewlineRenderer; 416f595250SGreg Roachuse League\CommonMark\Renderer\Inline\TextRenderer; 426f595250SGreg Roachuse League\CommonMark\Util\HtmlFilter; 434d35caa7SGreg Roach 44db3f0368SGreg Roachuse function strip_tags; 45db3f0368SGreg Roachuse function strtr; 46db3f0368SGreg Roach 474d35caa7SGreg Roach/** 484d35caa7SGreg Roach * Create a markdown converter. 494d35caa7SGreg Roach */ 504d35caa7SGreg Roachclass MarkdownFactory implements MarkdownFactoryInterface 514d35caa7SGreg Roach{ 5263a2c22bSGreg Roach // Commonmark uses the self-closing form of this tag, so we do the same for consistency. 5328065790SGreg Roach public const BREAK = '<br />'; 5428065790SGreg Roach 556f595250SGreg Roach protected const CONFIG_AUTOLINK = [ 564d35caa7SGreg Roach 'allow_unsafe_links' => false, 576f595250SGreg Roach 'html_input' => HtmlFilter::ESCAPE, 583c3c3c35SGreg Roach 'renderer' => [ 5928065790SGreg Roach 'soft_break' => self::BREAK, 603c3c3c35SGreg Roach ], 616f595250SGreg Roach ]; 626f595250SGreg Roach 636f595250SGreg Roach protected const CONFIG_MARKDOWN = [ 646f595250SGreg Roach 'allow_unsafe_links' => false, 656f595250SGreg Roach 'html_input' => HtmlFilter::ESCAPE, 663c3c3c35SGreg Roach 'renderer' => [ 6728065790SGreg Roach 'soft_break' => self::BREAK, 683c3c3c35SGreg Roach ], 696f595250SGreg Roach 'table' => [ 706f595250SGreg Roach 'wrap' => [ 716f595250SGreg Roach 'enabled' => true, 726f595250SGreg Roach 'tag' => 'div', 736f595250SGreg Roach 'attributes' => [ 746f595250SGreg Roach 'class' => 'table-responsive', 756f595250SGreg Roach ], 766f595250SGreg Roach ], 776f595250SGreg Roach ], 784d35caa7SGreg Roach ]; 794d35caa7SGreg Roach 804d35caa7SGreg Roach /** 816f595250SGreg Roach * @param string $markdown 824d35caa7SGreg Roach * @param Tree|null $tree 834d35caa7SGreg Roach * 846f595250SGreg Roach * @return string 854d35caa7SGreg Roach */ 86*2c6f1bd5SGreg Roach public function autolink(string $markdown, Tree|null $tree = null): string 874d35caa7SGreg Roach { 884d35caa7SGreg Roach // Create a minimal commonmark processor - just add support for auto-links. 896f595250SGreg Roach $environment = new Environment(static::CONFIG_AUTOLINK); 90db3f0368SGreg Roach $environment->addInlineParser(new NewlineParser()); 916f595250SGreg Roach $environment->addRenderer(Document::class, new DocumentRenderer()); 926f595250SGreg Roach $environment->addRenderer(Paragraph::class, new ParagraphRenderer()); 936f595250SGreg Roach $environment->addRenderer(Text::class, new TextRenderer()); 946f595250SGreg Roach $environment->addRenderer(Link::class, new LinkRenderer()); 95db3f0368SGreg Roach $environment->addRenderer(Newline::class, new NewlineRenderer()); 964d35caa7SGreg Roach $environment->addExtension(new AutolinkExtension()); 974d35caa7SGreg Roach 984d35caa7SGreg Roach // Optionally create links to other records. 994d35caa7SGreg Roach if ($tree instanceof Tree) { 1004d35caa7SGreg Roach $environment->addExtension(new XrefExtension($tree)); 1014d35caa7SGreg Roach } 1024d35caa7SGreg Roach 1036f595250SGreg Roach $converter = new MarkDownConverter($environment); 1046f595250SGreg Roach 105f3dfcaedSGreg Roach $html = $converter->convert($markdown)->getContent(); 106f3dfcaedSGreg Roach 10763a2c22bSGreg Roach // We should only have certain tags. Make sure of this. 10863a2c22bSGreg Roach $html = strip_tags($html, ['a', 'br', 'p']); 10963a2c22bSGreg Roach 11063a2c22bSGreg Roach // The markdown convert adds newlines, but not in a documented way. Safest to ignore them. 11163a2c22bSGreg Roach return strtr($html, ["\n" => '']); 1124d35caa7SGreg Roach } 1134d35caa7SGreg Roach 1144d35caa7SGreg Roach /** 1156f595250SGreg Roach * @param string $markdown 1164d35caa7SGreg Roach * @param Tree|null $tree 1174d35caa7SGreg Roach * 1186f595250SGreg Roach * @return string 1194d35caa7SGreg Roach */ 120*2c6f1bd5SGreg Roach public function markdown(string $markdown, Tree|null $tree = null): string 1214d35caa7SGreg Roach { 1226f595250SGreg Roach $environment = new Environment(static::CONFIG_MARKDOWN); 1236f595250SGreg Roach $environment->addExtension(new CommonMarkCoreExtension()); 1246f595250SGreg Roach $environment->addExtension(new TableExtension()); 1254d35caa7SGreg Roach 1264d35caa7SGreg Roach // Convert webtrees 1.x style census tables to commonmark format. 1277a2a7291SGreg Roach $environment->addExtension(new CensusTableExtension()); 1284d35caa7SGreg Roach 1294d35caa7SGreg Roach // Optionally create links to other records. 1304d35caa7SGreg Roach if ($tree instanceof Tree) { 1314d35caa7SGreg Roach $environment->addExtension(new XrefExtension($tree)); 1324d35caa7SGreg Roach } 1334d35caa7SGreg Roach 1346f595250SGreg Roach $converter = new MarkDownConverter($environment); 1356f595250SGreg Roach 13663a2c22bSGreg Roach $html = $converter->convert($markdown)->getContent(); 13763a2c22bSGreg Roach 13863a2c22bSGreg Roach // The markdown convert adds newlines, but not in a documented way. Safest to ignore them. 13963a2c22bSGreg Roach return strtr($html, ["\n" => '']); 1404d35caa7SGreg Roach } 1414d35caa7SGreg Roach} 142