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