1531e725cSNickeau<?php 2531e725cSNickeau 3531e725cSNickeau// implementation of 4531e725cSNickeau// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code 5531e725cSNickeau 6531e725cSNickeau// must be run within Dokuwiki 7531e725cSNickeauuse ComboStrap\PluginUtility; 8531e725cSNickeauuse ComboStrap\Prism; 9531e725cSNickeauuse ComboStrap\Tag; 10531e725cSNickeauuse ComboStrap\TagAttributes; 11531e725cSNickeau 1237748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/StringUtility.php'); 1337748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/Prism.php'); 14531e725cSNickeau 15531e725cSNickeauif (!defined('DOKU_INC')) die(); 16531e725cSNickeau 17531e725cSNickeau/** 18531e725cSNickeau * 19531e725cSNickeau * Support <a href="https://github.github.com/gfm/#fenced-code-blocks">Github code block</a> 20531e725cSNickeau * 21531e725cSNickeau * The original code markdown code block is the {@link syntax_plugin_combo_preformatted} 22531e725cSNickeau */ 23531e725cSNickeauclass syntax_plugin_combo_codemarkdown extends DokuWiki_Syntax_Plugin 24531e725cSNickeau{ 25531e725cSNickeau 26531e725cSNickeau 27531e725cSNickeau /** 28531e725cSNickeau * The exit pattern of markdown 29531e725cSNickeau * use in the enter pattern as regexp look-ahead 30531e725cSNickeau */ 31531e725cSNickeau const MARKDOWN_EXIT_PATTERN = "^\s*(?:\`|~){3}\s*$"; 32531e725cSNickeau 33531e725cSNickeau /** 34531e725cSNickeau * The syntax name, not a tag 35531e725cSNickeau * This must be the same that the last part name 36531e725cSNickeau * of the class (without any space !) 37531e725cSNickeau * This is the id in the callstack 38531e725cSNickeau * and gives us just a way to get the 39531e725cSNickeau * {@link \dokuwiki\Extension\SyntaxPlugin::getPluginComponent()} 40531e725cSNickeau * value (tag = plugin component) 41531e725cSNickeau */ 42531e725cSNickeau const TAG = "codemarkdown"; 43531e725cSNickeau 44531e725cSNickeau 45531e725cSNickeau function getType() 46531e725cSNickeau { 47531e725cSNickeau /** 48531e725cSNickeau * You can't write in a code block 49531e725cSNickeau */ 50531e725cSNickeau return 'protected'; 51531e725cSNickeau } 52531e725cSNickeau 53531e725cSNickeau /** 54531e725cSNickeau * How DokuWiki will add P element 55531e725cSNickeau * 56531e725cSNickeau * * 'normal' - The plugin can be used inside paragraphs 57531e725cSNickeau * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 58531e725cSNickeau * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 59531e725cSNickeau * 60531e725cSNickeau * @see DokuWiki_Syntax_Plugin::getPType() 61531e725cSNickeau */ 62531e725cSNickeau function getPType() 63531e725cSNickeau { 64531e725cSNickeau return 'block'; 65531e725cSNickeau } 66531e725cSNickeau 67531e725cSNickeau /** 68531e725cSNickeau * @return array 69531e725cSNickeau * Allow which kind of plugin inside 70531e725cSNickeau * 71531e725cSNickeau * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 72531e725cSNickeau * because we manage self the content and we call self the parser 73531e725cSNickeau * 74531e725cSNickeau * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php 75531e725cSNickeau */ 76531e725cSNickeau function getAllowedTypes() 77531e725cSNickeau { 78531e725cSNickeau return array(); 79531e725cSNickeau } 80531e725cSNickeau 81*4cadd4f8SNickeau /** 82*4cadd4f8SNickeau * Order of precedence 83*4cadd4f8SNickeau * @return int 84*4cadd4f8SNickeau */ 85*4cadd4f8SNickeau function getSort(): int 86531e725cSNickeau { 87531e725cSNickeau 88531e725cSNickeau return 199; 89531e725cSNickeau } 90531e725cSNickeau 91531e725cSNickeau 92531e725cSNickeau function connectTo($mode) 93531e725cSNickeau { 94531e725cSNickeau 95531e725cSNickeau // 96531e725cSNickeau // This pattern works with mgs flag 97531e725cSNickeau // 98531e725cSNickeau // Match: 99531e725cSNickeau // * the start of a line 100531e725cSNickeau // * any consecutive blank character 101531e725cSNickeau // * 3 consecutive backtick characters (`) or tildes (~) 102531e725cSNickeau // * a word (info string - ie the language) 103531e725cSNickeau // * any consecutive blank character 104531e725cSNickeau // * the end of a line 105531e725cSNickeau // * a look ahead to see if we have the exit pattern 106531e725cSNickeau // https://github.github.com/gfm/#fenced-code-blocks 107531e725cSNickeau $gitHubMarkdownPattern = "^\s*(?:\`|~){3}\w*\s*$(?=.*?" . self::MARKDOWN_EXIT_PATTERN . ")"; 1089337a630SNickeau $this->Lexer->addEntryPattern($gitHubMarkdownPattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 109531e725cSNickeau 110531e725cSNickeau 111531e725cSNickeau } 112531e725cSNickeau 113531e725cSNickeau 114531e725cSNickeau function postConnect() 115531e725cSNickeau { 116531e725cSNickeau 117531e725cSNickeau 1189337a630SNickeau $this->Lexer->addExitPattern(self::MARKDOWN_EXIT_PATTERN, PluginUtility::getModeFromTag($this->getPluginComponent())); 119531e725cSNickeau 120531e725cSNickeau 121531e725cSNickeau } 122531e725cSNickeau 123531e725cSNickeau /** 124531e725cSNickeau * 125531e725cSNickeau * The handle function goal is to parse the matched syntax through the pattern function 126531e725cSNickeau * and to return the result for use in the renderer 127531e725cSNickeau * This result is always cached until the page is modified. 128531e725cSNickeau * @param string $match 129531e725cSNickeau * @param int $state 130531e725cSNickeau * @param int $pos - byte position in the original source file 131531e725cSNickeau * @param Doku_Handler $handler 132531e725cSNickeau * @return array|bool 133531e725cSNickeau * @see DokuWiki_Syntax_Plugin::handle() 134531e725cSNickeau * 135531e725cSNickeau */ 136531e725cSNickeau function handle($match, $state, $pos, Doku_Handler $handler) 137531e725cSNickeau { 138531e725cSNickeau 139531e725cSNickeau switch ($state) { 140531e725cSNickeau 141531e725cSNickeau case DOKU_LEXER_ENTER: 142531e725cSNickeau $trimmedMatch = trim($match); 143531e725cSNickeau $language = preg_replace("(`{3}|~{3})", "", $trimmedMatch); 144531e725cSNickeau 145531e725cSNickeau $attributes = [TagAttributes::TYPE_KEY => $language]; 146531e725cSNickeau return array( 147531e725cSNickeau PluginUtility::STATE => $state, 148531e725cSNickeau PluginUtility::ATTRIBUTES => $attributes 149531e725cSNickeau ); 150531e725cSNickeau 151531e725cSNickeau case DOKU_LEXER_UNMATCHED : 152531e725cSNickeau 153531e725cSNickeau return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 154531e725cSNickeau 155531e725cSNickeau 156531e725cSNickeau case DOKU_LEXER_EXIT : 157531e725cSNickeau 158531e725cSNickeau return array(PluginUtility::STATE => $state); 159531e725cSNickeau 160531e725cSNickeau 161531e725cSNickeau } 162531e725cSNickeau return array(); 163531e725cSNickeau 164531e725cSNickeau } 165531e725cSNickeau 166531e725cSNickeau /** 167531e725cSNickeau * Render the output 168531e725cSNickeau * @param string $format 169531e725cSNickeau * @param Doku_Renderer $renderer 170531e725cSNickeau * @param array $data - what the function handle() return'ed 171531e725cSNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 172531e725cSNickeau * @see DokuWiki_Syntax_Plugin::render() 173531e725cSNickeau * 174531e725cSNickeau * 175531e725cSNickeau */ 176531e725cSNickeau function render($format, Doku_Renderer $renderer, $data) 177531e725cSNickeau { 178531e725cSNickeau 179531e725cSNickeau 180531e725cSNickeau if ($format == 'xhtml') { 181531e725cSNickeau 182531e725cSNickeau /** @var Doku_Renderer_xhtml $renderer */ 183531e725cSNickeau $state = $data [PluginUtility::STATE]; 184531e725cSNickeau switch ($state) { 185531e725cSNickeau case DOKU_LEXER_ENTER : 186531e725cSNickeau $attributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES], syntax_plugin_combo_code::CODE_TAG); 187531e725cSNickeau Prism::htmlEnter($renderer, $this, $attributes); 188531e725cSNickeau break; 189531e725cSNickeau 190531e725cSNickeau case DOKU_LEXER_UNMATCHED : 191531e725cSNickeau 192531e725cSNickeau // Delete the eol at the beginning and end 193531e725cSNickeau // otherwise we get a big block 194531e725cSNickeau $payload = trim($data[PluginUtility::PAYLOAD], "\n\r"); 195531e725cSNickeau $renderer->doc .= PluginUtility::htmlEncode($payload); 196531e725cSNickeau break; 197531e725cSNickeau 198531e725cSNickeau case DOKU_LEXER_EXIT : 199531e725cSNickeau 200531e725cSNickeau Prism::htmlExit($renderer); 201531e725cSNickeau break; 202531e725cSNickeau 203531e725cSNickeau } 204531e725cSNickeau return true; 205531e725cSNickeau } else if ($format == 'code') { 206531e725cSNickeau 207531e725cSNickeau /** 208531e725cSNickeau * The renderer to download the code 209531e725cSNickeau * @var Doku_Renderer_code $renderer 210531e725cSNickeau */ 211531e725cSNickeau $state = $data [PluginUtility::STATE]; 212531e725cSNickeau if ($state == DOKU_LEXER_UNMATCHED) { 213531e725cSNickeau 214531e725cSNickeau $attributes = $data[PluginUtility::ATTRIBUTES]; 215531e725cSNickeau $text = $data[PluginUtility::PAYLOAD]; 216531e725cSNickeau $language = strtolower($attributes["type"]); 217531e725cSNickeau $filename = $language; 218531e725cSNickeau $renderer->code($text, $language, $filename); 219531e725cSNickeau 220531e725cSNickeau } 221531e725cSNickeau } 222531e725cSNickeau 223531e725cSNickeau // unsupported $mode 224531e725cSNickeau return false; 225531e725cSNickeau 226531e725cSNickeau } 227531e725cSNickeau 228531e725cSNickeau 229531e725cSNickeau} 230531e725cSNickeau 231