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