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