1<?php
2/**
3 * DokuWiki Syntax Plugin Combostrap.
4 *
5 */
6
7use ComboStrap\ExecutionContext;
8use ComboStrap\PluginUtility;
9use ComboStrap\TagAttributes;
10use ComboStrap\XmlTagProcessing;
11
12require_once(__DIR__ . '/../vendor/autoload.php');
13
14/**
15 * All DokuWiki plugins to extend the parser/rendering mechanism
16 * need to inherit from this class
17 *
18 * The name of the class must follow a pattern (don't change it)
19 * ie:
20 *    syntax_plugin_PluginName_ComponentName
21 *
22 * https://getbootstrap.com/docs/4.6/components/collapse/#accordion-example
23 *
24 * Ter info:
25 * https://jqueryui.com/accordion/
26 *
27 * See also: https://getbootstrap.com/docs/5.0/content/reboot/#summary
28 * with a pointer
29 *
30 */
31class syntax_plugin_combo_accordion extends DokuWiki_Syntax_Plugin
32{
33
34
35    const TAG = 'accordion';
36
37
38    /**
39     * Syntax Type.
40     *
41     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
42     * @see DokuWiki_Syntax_Plugin::getType()
43     */
44    function getType()
45    {
46        return 'container';
47    }
48
49    /**
50     * @return array
51     * Allow which kind of plugin inside
52     *
53     * One of array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
54     * 'baseonly' will run only in the base mode
55     * because we manage self the content and we call self the parser
56     *
57     * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php
58     */
59    public function getAllowedTypes(): array
60    {
61        return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs');
62    }
63
64    public function accepts($mode): bool
65    {
66        /**
67         * header mode is disable to take over
68         * and replace it with {@link syntax_plugin_combo_heading}
69         */
70        if ($mode == "header") {
71            return false;
72        }
73        /**
74         *
75         */
76        return syntax_plugin_combo_preformatted::disablePreformatted($mode);
77
78    }
79
80    /**
81     * How Dokuwiki will add P element
82     *
83     *  * 'normal' - Inline
84     *  * 'block' - Block (p are not created inside)
85     *  * 'stack' - Block (p can be created inside)
86     *
87     * @see DokuWiki_Syntax_Plugin::getPType()
88     */
89    function getPType()
90    {
91        return 'block';
92    }
93
94    /**
95     * @see Doku_Parser_Mode::getSort()
96     * Higher number than the teaser-columns
97     * because the mode with the lowest sort number will win out
98     */
99    function getSort()
100    {
101        return 200;
102    }
103
104    /**
105     * Create a pattern that will called this plugin
106     *
107     * @param string $mode
108     * @see Doku_Parser_Mode::connectTo()
109     */
110    function connectTo($mode)
111    {
112
113
114        $pattern = XmlTagProcessing::getContainerTagPattern(self::TAG);
115        $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
116
117
118    }
119
120    public function postConnect()
121    {
122
123
124        $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeFromTag($this->getPluginComponent()));
125
126
127    }
128
129    /**
130     *
131     * The handle function goal is to parse the matched syntax through the pattern function
132     * and to return the result for use in the renderer
133     * This result is always cached until the page is modified.
134     * @param string $match
135     * @param int $state
136     * @param int $pos
137     * @param Doku_Handler $handler
138     * @return array|bool
139     * @see DokuWiki_Syntax_Plugin::handle()
140     *
141     */
142    function handle($match, $state, $pos, Doku_Handler $handler)
143    {
144
145        switch ($state) {
146
147            case DOKU_LEXER_ENTER:
148
149                $attributes = TagAttributes::createFromTagMatch($match)
150                    ->setLogicalTag(self::TAG);
151
152                // Attributes has at
153                // https://getbootstrap.com/docs/4.6/components/collapse/#accordion-example
154                $attributes->addClassName("accordion");
155
156                if (!$attributes->hasComponentAttribute(TagAttributes::ID_KEY)) {
157                    $idKey = ExecutionContext::getActualOrCreateFromEnv()->getIdManager()->generateNewHtmlIdForComponent(self::TAG);
158                    $attributes->addComponentAttributeValue(TagAttributes::ID_KEY, $idKey);
159                }
160
161                return array(
162                    PluginUtility::STATE => $state,
163                    PluginUtility::ATTRIBUTES => $attributes->toCallStackArray()
164                );
165
166            case DOKU_LEXER_UNMATCHED :
167
168                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
169
170
171            case DOKU_LEXER_EXIT :
172
173                return array(
174                    PluginUtility::STATE => $state
175                );
176
177
178        }
179
180        return array();
181
182    }
183
184    /**
185     * Render the output
186     * @param string $format
187     * @param Doku_Renderer $renderer
188     * @param array $data - what the function handle() return'ed
189     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
190     * @see DokuWiki_Syntax_Plugin::render()
191     *
192     *
193     */
194    function render($format, Doku_Renderer $renderer, $data): bool
195    {
196
197        if ($format == 'xhtml') {
198
199            /** @var Doku_Renderer_xhtml $renderer */
200            $state = $data[PluginUtility::STATE];
201            switch ($state) {
202                case DOKU_LEXER_ENTER:
203                    $attributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES])
204                        ->setLogicalTag(self::TAG);
205                    $renderer->doc .= $attributes->toHtmlEnterTag("div");
206                    break;
207                case DOKU_LEXER_UNMATCHED:
208                    $renderer->doc .= PluginUtility::renderUnmatched($data);
209                    break;
210                case DOKU_LEXER_EXIT:
211                    $renderer->doc .= '</div>';
212                    break;
213            }
214
215
216            return true;
217        }
218        return false;
219    }
220
221
222}
223