1*37748cd8SNickeau<?php 2*37748cd8SNickeau 3*37748cd8SNickeau 4*37748cd8SNickeauuse ComboStrap\CallStack; 5*37748cd8SNickeauuse ComboStrap\LogUtility; 6*37748cd8SNickeauuse ComboStrap\PluginUtility; 7*37748cd8SNickeauuse ComboStrap\TagAttributes; 8*37748cd8SNickeau 9*37748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 10*37748cd8SNickeau 11*37748cd8SNickeau 12*37748cd8SNickeau/** 13*37748cd8SNickeau * Railroad 14*37748cd8SNickeau * https://github.com/Chrriis/rrdiagram-js/ 15*37748cd8SNickeau */ 16*37748cd8SNickeauclass syntax_plugin_combo_railroad extends DokuWiki_Syntax_Plugin 17*37748cd8SNickeau{ 18*37748cd8SNickeau 19*37748cd8SNickeau /** 20*37748cd8SNickeau * Enable or disable the code component 21*37748cd8SNickeau */ 22*37748cd8SNickeau const TAG = 'railroad'; 23*37748cd8SNickeau const CLASS_NAME = "railroad-bnf"; 24*37748cd8SNickeau 25*37748cd8SNickeau const CANONICAL = self::TAG; 26*37748cd8SNickeau 27*37748cd8SNickeau 28*37748cd8SNickeau function getType(): string 29*37748cd8SNickeau { 30*37748cd8SNickeau return 'container'; 31*37748cd8SNickeau } 32*37748cd8SNickeau 33*37748cd8SNickeau /** 34*37748cd8SNickeau * How DokuWiki will add P element 35*37748cd8SNickeau * 36*37748cd8SNickeau * * 'normal' - The plugin can be used inside paragraphs 37*37748cd8SNickeau * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 38*37748cd8SNickeau * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 39*37748cd8SNickeau * 40*37748cd8SNickeau * @see DokuWiki_Syntax_Plugin::getPType() 41*37748cd8SNickeau */ 42*37748cd8SNickeau function getPType(): string 43*37748cd8SNickeau { 44*37748cd8SNickeau return 'block'; 45*37748cd8SNickeau } 46*37748cd8SNickeau 47*37748cd8SNickeau /** 48*37748cd8SNickeau * @return array 49*37748cd8SNickeau * Allow which kind of plugin inside 50*37748cd8SNickeau * 51*37748cd8SNickeau * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 52*37748cd8SNickeau * because we manage self the content and we call self the parser 53*37748cd8SNickeau * 54*37748cd8SNickeau * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php 55*37748cd8SNickeau */ 56*37748cd8SNickeau function getAllowedTypes(): array 57*37748cd8SNickeau { 58*37748cd8SNickeau return array('baseonly', 'container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); 59*37748cd8SNickeau } 60*37748cd8SNickeau 61*37748cd8SNickeau function getSort(): int 62*37748cd8SNickeau { 63*37748cd8SNickeau return 199; 64*37748cd8SNickeau } 65*37748cd8SNickeau 66*37748cd8SNickeau public function accepts($mode): bool 67*37748cd8SNickeau { 68*37748cd8SNickeau return syntax_plugin_combo_preformatted::disablePreformatted($mode); 69*37748cd8SNickeau } 70*37748cd8SNickeau 71*37748cd8SNickeau 72*37748cd8SNickeau function connectTo($mode) 73*37748cd8SNickeau { 74*37748cd8SNickeau 75*37748cd8SNickeau 76*37748cd8SNickeau $pattern = PluginUtility::getContainerTagPattern(self::TAG); 77*37748cd8SNickeau $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 78*37748cd8SNickeau 79*37748cd8SNickeau 80*37748cd8SNickeau } 81*37748cd8SNickeau 82*37748cd8SNickeau 83*37748cd8SNickeau function postConnect() 84*37748cd8SNickeau { 85*37748cd8SNickeau 86*37748cd8SNickeau $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeFromTag($this->getPluginComponent())); 87*37748cd8SNickeau 88*37748cd8SNickeau 89*37748cd8SNickeau } 90*37748cd8SNickeau 91*37748cd8SNickeau /** 92*37748cd8SNickeau * 93*37748cd8SNickeau * The handle function goal is to parse the matched syntax through the pattern function 94*37748cd8SNickeau * and to return the result for use in the renderer 95*37748cd8SNickeau * This result is always cached until the page is modified. 96*37748cd8SNickeau * @param string $match 97*37748cd8SNickeau * @param int $state 98*37748cd8SNickeau * @param int $pos - byte position in the original source file 99*37748cd8SNickeau * @param Doku_Handler $handler 100*37748cd8SNickeau * @return array|bool 101*37748cd8SNickeau * @see DokuWiki_Syntax_Plugin::handle() 102*37748cd8SNickeau * 103*37748cd8SNickeau */ 104*37748cd8SNickeau function handle($match, $state, $pos, Doku_Handler $handler) 105*37748cd8SNickeau { 106*37748cd8SNickeau 107*37748cd8SNickeau switch ($state) { 108*37748cd8SNickeau 109*37748cd8SNickeau case DOKU_LEXER_ENTER : 110*37748cd8SNickeau $tagAttributes = TagAttributes::createFromTagMatch($match); 111*37748cd8SNickeau return array( 112*37748cd8SNickeau PluginUtility::STATE => $state, 113*37748cd8SNickeau PluginUtility::ATTRIBUTES => $tagAttributes->toCallStackArray() 114*37748cd8SNickeau ); 115*37748cd8SNickeau 116*37748cd8SNickeau case DOKU_LEXER_UNMATCHED : 117*37748cd8SNickeau 118*37748cd8SNickeau return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 119*37748cd8SNickeau 120*37748cd8SNickeau 121*37748cd8SNickeau case DOKU_LEXER_EXIT : 122*37748cd8SNickeau $callStack = CallStack::createFromHandler($handler); 123*37748cd8SNickeau $callStack->moveToPreviousCorrespondingOpeningCall(); 124*37748cd8SNickeau $bnfCode = ""; 125*37748cd8SNickeau $bnfCodeFound = false; 126*37748cd8SNickeau while ($actual = $callStack->next()) { 127*37748cd8SNickeau if (in_array($actual->getTagName(), syntax_plugin_combo_webcode::CODE_TAGS)) { 128*37748cd8SNickeau switch ($actual->getState()) { 129*37748cd8SNickeau case DOKU_LEXER_ENTER: 130*37748cd8SNickeau $actualCodeType = strtolower($actual->getType()); 131*37748cd8SNickeau if ($actualCodeType === 'bnf') { 132*37748cd8SNickeau $bnfCodeFound = true; 133*37748cd8SNickeau }; 134*37748cd8SNickeau break; 135*37748cd8SNickeau case DOKU_LEXER_UNMATCHED: 136*37748cd8SNickeau if($bnfCodeFound) { 137*37748cd8SNickeau $bnfCode = $actual->getCapturedContent(); 138*37748cd8SNickeau break 2; 139*37748cd8SNickeau } 140*37748cd8SNickeau break; 141*37748cd8SNickeau } 142*37748cd8SNickeau } 143*37748cd8SNickeau } 144*37748cd8SNickeau return array( 145*37748cd8SNickeau PluginUtility::STATE => $state, 146*37748cd8SNickeau PluginUtility::PAYLOAD => $bnfCode 147*37748cd8SNickeau ); 148*37748cd8SNickeau 149*37748cd8SNickeau 150*37748cd8SNickeau } 151*37748cd8SNickeau return array(); 152*37748cd8SNickeau 153*37748cd8SNickeau } 154*37748cd8SNickeau 155*37748cd8SNickeau /** 156*37748cd8SNickeau * Render the output 157*37748cd8SNickeau * @param string $format 158*37748cd8SNickeau * @param Doku_Renderer $renderer 159*37748cd8SNickeau * @param array $data - what the function handle() return'ed 160*37748cd8SNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 161*37748cd8SNickeau * @see DokuWiki_Syntax_Plugin::render() 162*37748cd8SNickeau * 163*37748cd8SNickeau * 164*37748cd8SNickeau */ 165*37748cd8SNickeau function render($format, Doku_Renderer $renderer, $data) 166*37748cd8SNickeau { 167*37748cd8SNickeau 168*37748cd8SNickeau 169*37748cd8SNickeau if ($format == 'xhtml') { 170*37748cd8SNickeau 171*37748cd8SNickeau /** @var Doku_Renderer_xhtml $renderer */ 172*37748cd8SNickeau $state = $data [PluginUtility::STATE]; 173*37748cd8SNickeau switch ($state) { 174*37748cd8SNickeau case DOKU_LEXER_ENTER : 175*37748cd8SNickeau break; 176*37748cd8SNickeau 177*37748cd8SNickeau case DOKU_LEXER_UNMATCHED : 178*37748cd8SNickeau 179*37748cd8SNickeau $renderer->doc .= PluginUtility::renderUnmatched($data); 180*37748cd8SNickeau break; 181*37748cd8SNickeau 182*37748cd8SNickeau case DOKU_LEXER_EXIT : 183*37748cd8SNickeau $bnfCode = $data[PluginUtility::PAYLOAD]; 184*37748cd8SNickeau if (!empty($bnfCode)) { 185*37748cd8SNickeau $snippetManager = PluginUtility::getSnippetManager(); 186*37748cd8SNickeau $snippetId = self::TAG; 187*37748cd8SNickeau $libraryId = "rrdiagram"; 188*37748cd8SNickeau $snippetManager->attachCssSnippetForBar($snippetId); 189*37748cd8SNickeau $snippetManager->attachJavascriptSnippetForBar($snippetId); 190*37748cd8SNickeau $snippetManager->attachTagsForBar($snippetId)->setTags( 191*37748cd8SNickeau array( 192*37748cd8SNickeau "script" => 193*37748cd8SNickeau [ 194*37748cd8SNickeau array( 195*37748cd8SNickeau "src" => PluginUtility::getResourceBaseUrl() . "/library/$libraryId/$libraryId.js", 196*37748cd8SNickeau "integrity" => "sha256-iYKdedDsJ2q8Vl0lgyGw6y5iM5Bu4RYEs02X+/5SKVY=", 197*37748cd8SNickeau "crossorigin" => "anonymous" 198*37748cd8SNickeau ) 199*37748cd8SNickeau ], 200*37748cd8SNickeau 201*37748cd8SNickeau ) 202*37748cd8SNickeau ); 203*37748cd8SNickeau /** 204*37748cd8SNickeau * This code is replaced at runtime by the diagram 205*37748cd8SNickeau */ 206*37748cd8SNickeau $class = self::CLASS_NAME; 207*37748cd8SNickeau $renderer->doc .= "<pre class=\"$class\">$bnfCode</pre>"; 208*37748cd8SNickeau } else { 209*37748cd8SNickeau LogUtility::msg("No code component with bnf grammar was found", LogUtility::LVL_MSG_WARNING, self::CANONICAL); 210*37748cd8SNickeau } 211*37748cd8SNickeau break; 212*37748cd8SNickeau 213*37748cd8SNickeau } 214*37748cd8SNickeau return true; 215*37748cd8SNickeau } 216*37748cd8SNickeau 217*37748cd8SNickeau 218*37748cd8SNickeau // unsupported $mode 219*37748cd8SNickeau return false; 220*37748cd8SNickeau 221*37748cd8SNickeau } 222*37748cd8SNickeau 223*37748cd8SNickeau 224*37748cd8SNickeau} 225*37748cd8SNickeau 226