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