1<?php 2/** 3 * DokuWiki Plugin mermaid (Syntax Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Robert Weinmeister <develop@weinmeister.org> 7 */ 8 9use dokuwiki\Parsing\Parser; 10 11class syntax_plugin_mermaid extends \dokuwiki\Extension\SyntaxPlugin 12{ 13 /** @inheritDoc */ 14 function getType() 15 { 16 return 'container'; 17 } 18 19 /** @inheritDoc */ 20 function getSort() 21 { 22 return 150; 23 } 24 25 /** 26 * Connect lookup pattern to lexer. 27 * 28 * @param string $mode Parser mode 29 */ 30 function connectTo($mode) 31 { 32 $this->Lexer->addEntryPattern('<mermaid.*?>(?=.*?</mermaid>)',$mode,'plugin_mermaid'); 33 } 34 35 function postConnect() 36 { 37 $this->Lexer->addExitPattern('</mermaid>','plugin_mermaid'); 38 } 39 40 /** 41 * Handle matches of the flowcharts syntax 42 */ 43 function handle($match, $state, $pos, Doku_Handler $handler) 44 { 45 switch ($state) { 46 case DOKU_LEXER_ENTER: 47 return array($state, $match); 48 case DOKU_LEXER_UNMATCHED : 49 return array($state, $match); 50 case DOKU_LEXER_EXIT : 51 return array($state, ''); 52 } 53 return false; 54 } 55 56 /** 57 * Render xhtml output or metadata 58 */ 59 function render($mode, Doku_Renderer $renderer, $indata) 60 { 61 if($mode == 'xhtml'){ 62 list($state, $match) = $indata; 63 switch ($state) { 64 case DOKU_LEXER_ENTER : 65 $values = explode(" ", $match); 66 $divwidth = count($values) < 2 ? 'auto' : $values[1]; 67 $divheight = count($values) < 3 ? 'auto' : substr($values[2], 0, -1); 68 $renderer->doc .= '<div class="mermaid" style="width:'.$divwidth.'; height:'.$divheight.'">'; 69 break; 70 case DOKU_LEXER_UNMATCHED : 71 $instructions = $this->p_get_instructions($match); 72 //echo "<script>console.log('Instructions ".json_encode($instructions)."' );</script>"; 73 $xhtml = $this->p_render($instructions); 74 $renderer->doc .= preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $xhtml); 75 break; 76 case DOKU_LEXER_EXIT : 77 $renderer->doc .= "\r\n</div>"; 78 break; 79 } 80 return true; 81 } 82 return false; 83 } 84 85 /* 86 * Get the parser instructions siutable for the mermaid 87 * 88 */ 89 function p_get_instructions($text) 90 { 91 //import parser classes and mode definitions 92 require_once DOKU_INC . 'inc/parser/parser.php'; 93 94 // https://www.dokuwiki.org/devel:parser 95 // https://www.dokuwiki.org/devel:parser#basic_invocation 96 // Create the parser and the handler 97 $Parser = new Parser(new Doku_Handler()); 98 99 $modes = array(); 100 101 // add default modes 102 $std_modes = array( 'internallink', 'media', 'externallink'); 103 104 foreach($std_modes as $m 105 ){ 106 $class = 'dokuwiki\\Parsing\\ParserMode\\'.ucfirst($m); 107 $obj = new $class(); 108 $modes[] = array( 109 'sort' => $obj->getSort(), 110 'mode' => $m, 111 'obj' => $obj 112 ); 113 } 114 115 // add formatting modes 116 $fmt_modes = array( 'strong', 'emphasis', 'underline', 'monospace', 'subscript', 'superscript', 'deleted'); 117 foreach($fmt_modes as $m) 118 { 119 $obj = new \dokuwiki\Parsing\ParserMode\Formatting($m); 120 $modes[] = array( 121 'sort' => $obj->getSort(), 122 'mode' => $m, 123 'obj' => $obj 124 ); 125 } 126 127 //add modes to parser 128 foreach($modes as $mode) 129 { 130 $Parser->addMode($mode['mode'],$mode['obj']); 131 } 132 133 // Do the parsing 134 $p = $Parser->parse($text); 135 136 return $p; 137 } 138 139 public function p_render($instructions) 140 { 141 $Renderer = p_get_renderer('mermaid'); 142 143 // Loop through the instructions 144 foreach ($instructions as $instruction) { 145 if(method_exists($Renderer, $instruction[0])){ 146 call_user_func_array(array(&$Renderer, $instruction[0]), $instruction[1] ? $instruction[1] : array()); 147 } 148 } 149 150 return $Renderer->doc; 151 } 152} 153