1<?php
2/**
3 * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved.
4 *
5 * This source code is licensed under the GPL license found in the
6 * COPYING  file in the root directory of this source tree.
7 *
8 * @license  GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
9 * @author   ComboStrap <support@combostrap.com>
10 *
11 */
12
13use ComboStrap\Bootstrap;
14use ComboStrap\Xml\XhtmlUtility;
15use ComboStrap\LinkMarkup;
16use ComboStrap\NavBarUtility;
17use ComboStrap\PluginUtility;
18use ComboStrap\XmlTagProcessing;
19
20
21require_once(__DIR__ . '/../vendor/autoload.php');
22
23
24/**
25 *
26 * See https://getbootstrap.com/docs/4.0/components/collapse/
27 *
28 * The name of the class must follow a pattern (don't change it) ie syntax_plugin_PluginName_ComponentName
29 */
30class syntax_plugin_combo_navbarcollapse extends DokuWiki_Syntax_Plugin
31{
32    const TAG = 'collapse';
33    const COMPONENT = 'navbarcollapse';
34
35    /**
36     * Syntax Type.
37     *
38     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
39     * @see DokuWiki_Syntax_Plugin::getType()
40     */
41    function getType()
42    {
43        return 'container';
44    }
45
46    /**
47     * @return array
48     * Allow which kind of plugin inside
49     *
50     * No one of array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
51     * because we manage self the content and we call self the parser
52     */
53    public function getAllowedTypes()
54    {
55        return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs');
56    }
57
58    public function accepts($mode)
59    {
60
61        $accept = syntax_plugin_combo_preformatted::disablePreformatted($mode);
62
63        // P element are not welcome in a navbar
64        if ($mode == "eol") {
65            $accept = false;
66        }
67
68        return $accept;
69
70    }
71
72
73    /**
74     * How Dokuwiki will add P element
75     *
76     * * 'normal' - The plugin can be used inside paragraphs
77     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
78     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
79     *
80     * @see DokuWiki_Syntax_Plugin::getPType()
81     */
82    function getPType()
83    {
84        return 'block';
85    }
86
87    /**
88     * @see Doku_Parser_Mode::getSort()
89     *
90     * the mode with the lowest sort number will win out
91     * the container (parent) must then have a lower number than the child
92     */
93    function getSort()
94    {
95        return 100;
96    }
97
98    /**
99     * Create a pattern that will called this plugin
100     *
101     * @param string $mode
102     * @see Doku_Parser_Mode::connectTo()
103     */
104    function connectTo($mode)
105    {
106        // Only inside a navbar
107        if ($mode == PluginUtility::getModeFromTag(syntax_plugin_combo_menubar::TAG)) {
108            $pattern = XmlTagProcessing::getContainerTagPattern(self::TAG);
109            $this->Lexer->addEntryPattern($pattern, $mode, 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent());
110        }
111
112    }
113
114    public function postConnect()
115    {
116
117        $this->Lexer->addExitPattern('</' . self::TAG . '>', 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent());
118
119    }
120
121    /**
122     *
123     * The handle function goal is to parse the matched syntax through the pattern function
124     * and to return the result for use in the renderer
125     * This result is always cached until the page is modified.
126     * @param string $match
127     * @param int $state
128     * @param int $pos
129     * @param Doku_Handler $handler
130     * @return array|bool
131     * @see DokuWiki_Syntax_Plugin::handle()
132     *
133     */
134    function handle($match, $state, $pos, Doku_Handler $handler)
135    {
136
137        switch ($state) {
138
139            case DOKU_LEXER_ENTER:
140
141                $tagAttributes = PluginUtility::getTagAttributes($match);
142                return array(
143                    PluginUtility::STATE => $state,
144                    PluginUtility::ATTRIBUTES => $tagAttributes
145                );
146
147            case DOKU_LEXER_UNMATCHED :
148
149                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
150
151
152            case DOKU_LEXER_EXIT :
153
154                return array(PluginUtility::STATE => $state);
155
156
157        }
158
159        return array();
160
161    }
162
163    /**
164     * Render the output
165     * @param string $format
166     * @param Doku_Renderer $renderer
167     * @param array $data - what the function handle() return'ed
168     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
169     * @see DokuWiki_Syntax_Plugin::render()
170     *
171     *
172     */
173    function render($format, Doku_Renderer $renderer, $data)
174    {
175        $state = $data[PluginUtility::STATE];
176        switch ($format) {
177            case 'xhtml':
178                /** @var Doku_Renderer_xhtml $renderer */
179
180                switch ($state) {
181
182                    case DOKU_LEXER_ENTER :
183
184                        $attributes = $data[PluginUtility::ATTRIBUTES];
185
186                        // The button is the hamburger menu that will be shown
187                        $idElementToCollapse = 'navbarcollapse';
188                        $dataNamespace = Bootstrap::getDataNamespace();
189                        $renderer->doc .= "<button class=\"navbar-toggler\" type=\"button\" data{$dataNamespace}-toggle=\"collapse\" data{$dataNamespace}-target=\"#$idElementToCollapse\" aria-controls=\"$idElementToCollapse\" aria-expanded=\"false\" aria-label=\"Toggle navigation\"";
190                        if (array_key_exists("order", $attributes)) {
191                            $renderer->doc .= ' style="order:' . $attributes["order"] . '"';
192                            unset($attributes["order"]);
193                        }
194                        $renderer->doc .= '>' . DOKU_LF;
195                        $renderer->doc .= '<span class="navbar-toggler-icon"></span>' . DOKU_LF;
196                        $renderer->doc .= '</button>' . DOKU_LF;
197
198
199                        $classValue = "collapse navbar-collapse";
200                        if (array_key_exists("class", $attributes)) {
201                            $attributes["class"] .= " {$classValue}";
202                        } else {
203                            $attributes["class"] = "{$classValue}";
204                        }
205                        $renderer->doc .= '<div id="' . $idElementToCollapse . '" ' . PluginUtility::array2HTMLAttributesAsString($attributes) . '>';
206
207                        // All element below will collapse
208                        break;
209
210                    case DOKU_LEXER_UNMATCHED:
211                        $renderer->doc .= NavBarUtility::text(PluginUtility::renderUnmatched($data));
212                        break;
213
214
215                    case DOKU_LEXER_EXIT :
216
217                        $renderer->doc .= '</div>' . DOKU_LF;
218                        break;
219                }
220                return true;
221
222        }
223        return false;
224    }
225
226
227    public static function getElementName()
228    {
229        return PluginUtility::getTagName(get_called_class());
230    }
231
232
233}
234