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