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