xref: /plugin/combo/syntax/railroad.php (revision 26a7e0f890fa8e62fec018ac7f93dc9387751661)
1<?php
2
3
4use ComboStrap\CallStack;
5use ComboStrap\LogUtility;
6use ComboStrap\Os;
7use ComboStrap\PluginUtility;
8use ComboStrap\TagAttributes;
9
10require_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
11
12
13/**
14 * Railroad
15 * https://github.com/Chrriis/rrdiagram-js/
16 */
17class syntax_plugin_combo_railroad extends DokuWiki_Syntax_Plugin
18{
19
20    const TAG = 'railroad';
21    const CLASS_NAME = "railroad-bnf";
22
23    const CANONICAL = self::TAG;
24
25
26    function getType(): string
27    {
28        return 'container';
29    }
30
31    /**
32     * How DokuWiki will add P element
33     *
34     *  * 'normal' - The plugin can be used inside paragraphs
35     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
36     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
37     *
38     * @see DokuWiki_Syntax_Plugin::getPType()
39     */
40    function getPType(): string
41    {
42        return 'block';
43    }
44
45    /**
46     * @return array
47     * Allow which kind of plugin inside
48     *
49     * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
50     * because we manage self the content and we call self the parser
51     *
52     * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php
53     */
54    function getAllowedTypes(): array
55    {
56        return array('baseonly', 'container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs');
57    }
58
59    function getSort(): int
60    {
61        return 199;
62    }
63
64    public function accepts($mode): bool
65    {
66        return syntax_plugin_combo_preformatted::disablePreformatted($mode);
67    }
68
69
70    function connectTo($mode)
71    {
72
73
74        $pattern = PluginUtility::getContainerTagPattern(self::TAG);
75        $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
76
77
78    }
79
80
81    function postConnect()
82    {
83
84        $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeFromTag($this->getPluginComponent()));
85
86
87    }
88
89    /**
90     *
91     * The handle function goal is to parse the matched syntax through the pattern function
92     * and to return the result for use in the renderer
93     * This result is always cached until the page is modified.
94     * @param string $match
95     * @param int $state
96     * @param int $pos - byte position in the original source file
97     * @param Doku_Handler $handler
98     * @return array|bool
99     * @see DokuWiki_Syntax_Plugin::handle()
100     *
101     */
102    function handle($match, $state, $pos, Doku_Handler $handler)
103    {
104
105        switch ($state) {
106
107            case DOKU_LEXER_ENTER :
108                $tagAttributes = TagAttributes::createFromTagMatch($match);
109                return array(
110                    PluginUtility::STATE => $state,
111                    PluginUtility::ATTRIBUTES => $tagAttributes->toCallStackArray()
112                );
113
114            case DOKU_LEXER_UNMATCHED :
115
116                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
117
118
119            case DOKU_LEXER_EXIT :
120                $callStack = CallStack::createFromHandler($handler);
121                $callStack->moveToPreviousCorrespondingOpeningCall();
122                $bnfCode = "";
123                $bnfCodeFound = false;
124                while ($actual = $callStack->next()) {
125                    if (in_array($actual->getTagName(), syntax_plugin_combo_webcode::CODE_TAGS)) {
126                        switch ($actual->getState()) {
127                            case DOKU_LEXER_ENTER:
128                                $actualCodeType = strtolower($actual->getType());
129                                if ($actualCodeType === 'bnf') {
130                                    $bnfCodeFound = true;
131                                };
132                                break;
133                            case DOKU_LEXER_UNMATCHED:
134                                if($bnfCodeFound) {
135                                    $bnfCode = $actual->getCapturedContent();
136                                    break 2;
137                                }
138                                break;
139                        }
140                    }
141                }
142                return array(
143                    PluginUtility::STATE => $state,
144                    PluginUtility::PAYLOAD => $bnfCode
145                );
146
147
148        }
149        return array();
150
151    }
152
153    /**
154     * Render the output
155     * @param string $format
156     * @param Doku_Renderer $renderer
157     * @param array $data - what the function handle() return'ed
158     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
159     * @see DokuWiki_Syntax_Plugin::render()
160     *
161     *
162     */
163    function render($format, Doku_Renderer $renderer, $data)
164    {
165
166
167        if ($format == 'xhtml') {
168
169            /** @var Doku_Renderer_xhtml $renderer */
170            $state = $data [PluginUtility::STATE];
171            switch ($state) {
172                case DOKU_LEXER_ENTER :
173                    break;
174
175                case DOKU_LEXER_UNMATCHED :
176
177                    $renderer->doc .= PluginUtility::renderUnmatched($data);
178                    break;
179
180                case DOKU_LEXER_EXIT :
181                    $bnfCode = $data[PluginUtility::PAYLOAD];
182                    if (!empty($bnfCode)) {
183                        $snippetManager = PluginUtility::getSnippetManager();
184                        $snippetId = self::TAG;
185                        $libraryId = "rrdiagram";
186                        $snippetManager->attachCssSnippetForBar($snippetId);
187                        $snippetManager->attachJavascriptSnippetForBar($snippetId);
188
189                        /**
190                         *
191                         * Calculation
192                         * `
193                         * openssl dgst -sha256 -binary rrdiagram.js | openssl base64 -A
194                         * `
195                         */
196                        $sha256integrity = "iYKdedDsJ2q8Vl0lgyGw6y5iM5Bu4RYEs02X+/5SKVY=";
197
198                        $snippetManager->attachTagsForBar($snippetId)->setTags(
199                            array(
200                                "script" =>
201                                    [
202                                        array(
203                                            "src" => PluginUtility::getResourceBaseUrl() . "/library/$libraryId/0.9.4/$libraryId.js",
204                                            "integrity" => "sha256-".$sha256integrity,
205                                            "crossorigin" => "anonymous"
206                                        )
207                                    ],
208
209                            )
210                        );
211                        /**
212                         * This code is replaced at runtime by the diagram
213                         */
214                        $class = self::CLASS_NAME;
215                        $renderer->doc .= "<pre class=\"$class\">".hsc($bnfCode)."</pre>";
216                    } else {
217                        LogUtility::msg("No code component with bnf grammar was found", LogUtility::LVL_MSG_WARNING, self::CANONICAL);
218                    }
219                    break;
220
221            }
222            return true;
223        }
224
225
226        // unsupported $mode
227        return false;
228
229    }
230
231
232}
233
234