1<?php
2/**
3 * DokuWiki Plugin flowcharts (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Jakob Schwichtenberg <mail@jakobschwichtenberg.com>
7 */
8
9use dokuwiki\Parsing\Parser;
10
11// must be run within Dokuwiki
12if (!defined('DOKU_INC')) {
13    die();
14}
15/**
16* if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
17* if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
18* require_once(DOKU_PLUGIN.'syntax.php');
19*/
20
21class syntax_plugin_flowcharts extends DokuWiki_Syntax_Plugin
22{
23    function getType(){ return 'protected'; }
24
25    // must return a number lower than returned by native 'code' mode (200)
26    function getSort(){ return 158; }
27
28    /**
29     * Connect lookup pattern to lexer.
30     *
31     * @param string $mode Parser mode
32     */
33     function connectTo($mode) {
34        $this->Lexer->addEntryPattern('<flow>(?=.*?</flow>)',$mode,'plugin_flowcharts');
35    }
36    function postConnect() {
37        $this->Lexer->addExitPattern('</flow>','plugin_flowcharts');
38    }
39
40
41    /**
42     * Handle matches of the flowcharts syntax
43     */
44    function handle($match, $state, $pos, Doku_Handler $handler){
45        switch ($state) {
46            case DOKU_LEXER_ENTER:
47                return array($state, '');
48
49            case DOKU_LEXER_UNMATCHED :
50                return array($state, $match);
51
52            case DOKU_LEXER_EXIT :
53                return array($state, '');
54
55        }
56        return false;
57    }
58
59
60    /**
61     * Render xhtml output or metadata
62     */
63    function render($mode, Doku_Renderer $renderer, $indata) {
64        if($mode == 'xhtml'){
65            list($state, $match) = $indata;
66            switch ($state) {
67
68            case DOKU_LEXER_ENTER :
69                  // securityLevel loose allows more advanced functionality such as subgraphs to run.
70                  // @todo: this should be an option in the interface.
71                  $renderer->doc .= '<div class="mermaid">';
72                  break;
73              case DOKU_LEXER_UNMATCHED :
74                  $instructions = $this->p_get_instructions($match);
75                  $xhtml = $this->p_render($instructions);
76                  $renderer->doc .= $xhtml;
77                  break;
78              case DOKU_LEXER_EXIT :
79                  $renderer->doc .= "</div>";
80                  break;
81            }
82            return true;
83        }
84        return false;
85    }
86
87    /*
88     * Get the parser instructions siutable for the mermaid
89     *
90     */
91    function p_get_instructions($text) {
92
93        $modes = array();
94
95        // add default modes
96        $std_modes = array('internallink', 'media','externallink');
97
98        foreach($std_modes as $m){
99            $class = 'dokuwiki\\Parsing\\ParserMode\\'.ucfirst($m);
100            $obj   = new $class();
101            $modes[] = array(
102                'sort' => $obj->getSort(),
103                'mode' => $m,
104                'obj'  => $obj
105            );
106        }
107
108        // add formatting modes
109        $fmt_modes = array('strong','emphasis','underline','monospace',
110                           'subscript','superscript','deleted');
111        foreach($fmt_modes as $m){
112            $obj   = new \dokuwiki\Parsing\ParserMode\Formatting($m);
113            $modes[] = array(
114                'sort' => $obj->getSort(),
115                'mode' => $m,
116                'obj'  => $obj
117            );
118        }
119
120        // Create the parser and handler
121        $Parser = new Parser(new Doku_Handler());
122
123        //add modes to parser
124        foreach($modes as $mode){
125            $Parser->addMode($mode['mode'],$mode['obj']);
126        }
127
128        // Do the parsing
129        $p = $Parser->parse($text);
130
131        return $p;
132    }
133
134    public function p_render($instructions) {
135        $Renderer = p_get_renderer('flowcharts');
136
137        $Renderer->smileys = getSmileys();
138        $Renderer->entities = getEntities();
139        $Renderer->acronyms = getAcronyms();
140        $Renderer->interwiki = getInterwiki();
141
142        // Loop through the instructions
143        foreach ($instructions as $instruction) {
144            // Execute the callback against the Renderer
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}
154
155