xref: /plugin/mermaid/syntax.php (revision c6570b71a87dc0fe9b0f4bb9223799729731ea00)
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