1<?php
2
3require_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
4
5use ComboStrap\CallStack;
6use ComboStrap\LogUtility;
7use ComboStrap\PluginUtility;
8use ComboStrap\Tag\WebCodeTag;
9use ComboStrap\TagAttributes;
10use ComboStrap\XmlTagProcessing;
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 = XmlTagProcessing::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(), WebCodeTag::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->attachCssInternalStyleSheet($snippetId);
187                        $snippetManager->attachJavascriptFromComponentId($snippetId);
188
189                        /**
190                         *
191                         * Calculation
192                         * `
193                         * openssl dgst -sha256 -binary rrdiagram.js | openssl base64 -A
194                         * `
195                         * $sha256integrity = ;
196                         */
197                        $snippetManager->attachJavascriptComboResourceForSlot(
198                            $snippetId,
199                            "library:$libraryId:0.9.4.1:$libraryId.js",
200                            "sha256-" . "noP8Tag5vKjRfh3+8GXy5QSZqKnRt7WQe6I9rGVl+go="
201                        );
202
203                        /**
204                         * This code is replaced at runtime by the diagram
205                         */
206                        $class = self::CLASS_NAME;
207                        $renderer->doc .= "<pre class=\"$class\">" . hsc($bnfCode) . "</pre>";
208                    } else {
209                        LogUtility::msg("No code component with bnf grammar was found", LogUtility::LVL_MSG_WARNING, self::CANONICAL);
210                    }
211                    break;
212
213            }
214            return true;
215        }
216
217
218        // unsupported $mode
219        return false;
220
221    }
222
223
224}
225
226