18ec9a8f2SSungbin Jeon<?php 28ec9a8f2SSungbin Jeon 38ec9a8f2SSungbin Jeonnamespace Dokuwiki\Plugin\Commonmark; 48ec9a8f2SSungbin Jeon 594a075eeSSungbin Jeonuse League\CommonMark\Environment\Environment; 694a075eeSSungbin Jeonuse League\CommonMark\Parser\MarkdownParser; 71e536badSSungbin Jeonuse Dokuwiki\Plugin\Commonmark\Extension\CommonmarkToDokuwikiExtension; 8f46768a8SSungbin Jeonuse Dokuwiki\Plugin\Commonmark\Extension\FootnoteToDokuwikiExtension; 978c882e7SSungbin Jeonuse League\CommonMark\Extension\Strikethrough\StrikethroughExtension; 10656793f4SSungbin Jeonuse Dokuwiki\Plugin\Commonmark\Extension\TableExtension; 1181da5a38SSungbin Jeonuse League\CommonMark\Extension\FrontMatter\FrontMatterExtension; 1281da5a38SSungbin Jeonuse League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter; 138ec9a8f2SSungbin Jeon 148ec9a8f2SSungbin Jeonclass Commonmark { 15836a4a7aSChalix public static function RendtoDW($markdown, $frontmatter_tag = 'off', $render_softbreaks = 0): array { 1680734199SSungbin Jeon // heading info 1780734199SSungbin Jeon $headingInfo = []; 1880734199SSungbin Jeon 1980734199SSungbin Jeon // create environment 20836a4a7aSChalix $environment = self::createDWEnvironment($render_softbreaks); 218ec9a8f2SSungbin Jeon 2280734199SSungbin Jeon // create parser 2394a075eeSSungbin Jeon $parser = new MarkdownParser($environment); 2480734199SSungbin Jeon // create Dokuwiki Renderer 258ec9a8f2SSungbin Jeon $DWRenderer = new DWRenderer($environment); 268ec9a8f2SSungbin Jeon 2781da5a38SSungbin Jeon # separate frontmatter and main text 2881da5a38SSungbin Jeon $FMresult = self::ExtractFrontmatter($markdown); 2981da5a38SSungbin Jeon $frontmatter = $FMresult->getFrontMatter(); 3081da5a38SSungbin Jeon $markdownOnly = $FMresult->getContent(); 318bcf583bSSungbin Jeon $tagStr = ''; # initialize tag string 3281da5a38SSungbin Jeon //print_r($frontmatter); 3381da5a38SSungbin Jeon 3481da5a38SSungbin Jeon # extract tags only 35022ce692SSungbin Jeon if(!empty($frontmatter) && gettype($frontmatter) == "array") { // frontmatter must be array if valid 36022ce692SSungbin Jeon if (array_key_exists('tags', $frontmatter)) { 3781da5a38SSungbin Jeon $tags = $frontmatter['tags']; 387569cca4SSungbin Jeon $tagStr = "{{tag>"; 3981da5a38SSungbin Jeon foreach ($tags as $tag) { 4081da5a38SSungbin Jeon $tagStr = $tagStr. "\"". $tag. "\" "; 4181da5a38SSungbin Jeon } 424384789bSSungbin Jeon $tagStr = $tagStr. "}}"; 438bcf583bSSungbin Jeon } 44022ce692SSungbin Jeon } 4581da5a38SSungbin Jeon 46ac4825fcSSungbin Jeon // pre-processing: convert slash inside wikilink to colon & image wikilinks 475ba4c344SSungbin Jeon $markdownOnly = self::ParseDokuwikiWikilinks($markdownOnly); 4881da5a38SSungbin Jeon $document = $parser->parse($markdownOnly); 4981da5a38SSungbin Jeon $renderResult = $DWRenderer->renderNode($document); 5080734199SSungbin Jeon foreach ($document->iterator() as $node) { 51*5458b938SSungbin Jeon if($node instanceof \League\CommonMark\Extension\CommonMark\Node\Block\Heading) { 52*5458b938SSungbin Jeon // collect inline text recursively 53*5458b938SSungbin Jeon $collectInlineText = function($node) use (&$collectInlineText) { 54*5458b938SSungbin Jeon $text = ''; 55*5458b938SSungbin Jeon for ($child = $node->firstChild(); $child !== null; $child = $child->next()) { 56*5458b938SSungbin Jeon if (method_exists($child, 'getLiteral')) { 57*5458b938SSungbin Jeon $text .= $child->getLiteral(); 589b5593feSSungbin Jeon } else { 59*5458b938SSungbin Jeon // recurse into nested inline nodes (strong, emphasis, etc.) 60*5458b938SSungbin Jeon $text .= $collectInlineText($child); 619b5593feSSungbin Jeon } 62*5458b938SSungbin Jeon } 63*5458b938SSungbin Jeon return $text; 64*5458b938SSungbin Jeon }; 65*5458b938SSungbin Jeon 66*5458b938SSungbin Jeon $first = $node->firstChild(); 67*5458b938SSungbin Jeon if ($first === null) { 68*5458b938SSungbin Jeon $headingName = ''; 69*5458b938SSungbin Jeon } elseif($first instanceof \League\CommonMark\Extension\CommonMark\Node\Inline\Link) { 70*5458b938SSungbin Jeon // set headingName as [[<Url>|<text>]] 71*5458b938SSungbin Jeon // link URL and its inner text (may contain nested inlines) 72*5458b938SSungbin Jeon $linkText = $collectInlineText($first); 73*5458b938SSungbin Jeon $headingName = '[[' . $first->getUrl() . '|' . $linkText . ']]'; 74*5458b938SSungbin Jeon } else { 75*5458b938SSungbin Jeon // collect all inline text inside the heading 76*5458b938SSungbin Jeon $headingName = $collectInlineText($node); 77*5458b938SSungbin Jeon } 78*5458b938SSungbin Jeon 799b5593feSSungbin Jeon $headingInfo[$headingName] = array( 8080734199SSungbin Jeon 'level' => $node->getLevel(), 8180734199SSungbin Jeon 'startline' => $node->getStartLine(), 8280734199SSungbin Jeon 'endline' => $node->getEndLine() 8380734199SSungbin Jeon ); 8480734199SSungbin Jeon } 8580734199SSungbin Jeon } 8681da5a38SSungbin Jeon 877569cca4SSungbin Jeon if($frontmatter_tag == 'off') { 8880734199SSungbin Jeon return array('text'=>$renderResult, 'heading'=>$headingInfo); 897569cca4SSungbin Jeon } elseif($frontmatter_tag == 'upper') { 9080734199SSungbin Jeon return array('text'=>$tagStr."\n\n".$renderResult, 'heading'=>$headingInfo); 9180734199SSungbin Jeon //return $tagStr."\n\n".$renderResult; 927569cca4SSungbin Jeon } else { 9380734199SSungbin Jeon return array('text'=>$renderResult."\n\n".$tagStr, 'heading'=>$headingInfo); 9480734199SSungbin Jeon //return $renderResult."\n\n".$tagStr; 957569cca4SSungbin Jeon } 9681da5a38SSungbin Jeon } 9781da5a38SSungbin Jeon 9881da5a38SSungbin Jeon // Temporary implementation: separate method for frontmatter extraction 9980734199SSungbin Jeon // Since some parsed frontmatter info must be included in main text, it should be merged 10081da5a38SSungbin Jeon public static function ExtractFrontmatter($markdown) { 10181da5a38SSungbin Jeon $frontMatterExtension = new FrontMatterExtension(); 10281da5a38SSungbin Jeon $result = $frontMatterExtension->getFrontMatterParser()->parse($markdown); 10381da5a38SSungbin Jeon 10481da5a38SSungbin Jeon return $result; 1058ec9a8f2SSungbin Jeon } 1068ec9a8f2SSungbin Jeon 107ac4825fcSSungbin Jeon // replace slash in MD wikilink to colon to match DW syntax 1085ba4c344SSungbin Jeon public static function ParseDokuwikiWikilinks($text) { 109ac4825fcSSungbin Jeon $pattern = "/(?:\[\[\b|(?!^)\G)[^\/|\]]*\K\/+/"; 110ac4825fcSSungbin Jeon $result = preg_replace($pattern, ":", $text); 1115ba4c344SSungbin Jeon $pattern = "/!\[\[(.*)\]\]/"; 112ac4825fcSSungbin Jeon $result = preg_replace($pattern, '{{$1}}', $result); 113ac4825fcSSungbin Jeon return $result; 114ac4825fcSSungbin Jeon } 115ac4825fcSSungbin Jeon 116836a4a7aSChalix public static function createDWEnvironment($render_softbreaks): Environment { 11751966319SChalix $config = [ 11851966319SChalix 'html_input' => 'allow', 1190f46309aSChalix 'commonmark' => ['hard_break'=> "\\\\ "] 12051966319SChalix ]; 12158199fd4SChalix if ($render_softbreaks) { 1220f46309aSChalix $config['renderer']['soft_break'] = $config['commonmark']['hard_break']; 12358199fd4SChalix } 12458199fd4SChalix 125b0a36678SSungbin Jeon $environment = new Environment($config); 1268ec9a8f2SSungbin Jeon $environment->addExtension(new CommonMarkToDokuWikiExtension()); 127f46768a8SSungbin Jeon $environment->addExtension(new FootnoteToDokuwikiExtension()); 12878c882e7SSungbin Jeon $environment->addExtension(new StrikethroughExtension()); 129656793f4SSungbin Jeon $environment->addExtension(new TableExtension()); 13081da5a38SSungbin Jeon $environment->addExtension(new FrontMatterExtension()); 131f46768a8SSungbin Jeon 1328ec9a8f2SSungbin Jeon return $environment; 1338ec9a8f2SSungbin Jeon } 1348ec9a8f2SSungbin Jeon} 1358ec9a8f2SSungbin Jeon 1368ec9a8f2SSungbin Jeon?> 137