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