1<?php
2
3
4use ComboStrap\Bootstrap;
5use ComboStrap\BrandButton;
6use ComboStrap\ButtonTag;
7use ComboStrap\CallStack;
8use ComboStrap\LogUtility;
9use ComboStrap\PluginUtility;
10use ComboStrap\TagAttributes;
11use ComboStrap\TagAttribute\Toggle;
12use ComboStrap\XmlTagProcessing;
13
14
15class syntax_plugin_combo_toggle extends DokuWiki_Syntax_Plugin
16{
17
18    const TAG = "toggle";
19    const CANONICAL = self::TAG;
20    const WIDGET_ATTRIBUTE = "widget";
21
22
23    /**
24     * Syntax Type.
25     *
26     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
27     * @see DokuWiki_Syntax_Plugin::getType()
28     */
29    function getType(): string
30    {
31        return 'substition';
32    }
33
34    /**
35     * How Dokuwiki will add P element
36     *
37     *  * 'normal' - The plugin can be used inside paragraphs
38     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
39     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
40     *
41     * @see DokuWiki_Syntax_Plugin::getPType()
42     */
43    function getPType(): string
44    {
45        // button or link
46        return 'normal';
47    }
48
49    /**
50     * @return array
51     * Allow which kind of plugin inside
52     *
53     * array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
54     *
55     */
56    function getAllowedTypes(): array
57    {
58        return array('baseonly', 'formatting', 'substition', 'protected', 'disabled');
59    }
60
61    function getSort(): int
62    {
63        return 201;
64    }
65
66    public
67    function accepts($mode): bool
68    {
69        return syntax_plugin_combo_preformatted::disablePreformatted($mode)
70            && Toggle::disableEntity($mode);
71    }
72
73
74    /**
75     * Create a pattern that will called this plugin
76     *
77     * @param string $mode
78     * @see Doku_Parser_Mode::connectTo()
79     */
80    function connectTo($mode)
81    {
82
83        $pattern = XmlTagProcessing::getContainerTagPattern(self::getTag());
84        $this->Lexer->addEntryPattern($pattern, $mode, 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent());
85
86
87    }
88
89    function postConnect()
90    {
91
92        $this->Lexer->addExitPattern('</' . self::getTag() . '>', 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent());
93
94    }
95
96    function handle($match, $state, $pos, Doku_Handler $handler)
97    {
98
99
100        switch ($state) {
101
102            case DOKU_LEXER_ENTER :
103
104                /**
105                 * Default parameters, type definition and parsing
106                 */
107                $defaultParameters[self::WIDGET_ATTRIBUTE] = BrandButton::WIDGET_BUTTON_VALUE;
108                $knownTypes = ButtonTag::TYPES;
109                $tagAttributes = TagAttributes::createFromTagMatch($match, $defaultParameters, $knownTypes)
110                    ->setLogicalTag(self::TAG);
111
112                return array(
113                    PluginUtility::STATE => $state,
114                    PluginUtility::ATTRIBUTES => $tagAttributes->toCallStackArray()
115                );
116
117            case DOKU_LEXER_UNMATCHED :
118                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
119
120            case DOKU_LEXER_EXIT :
121
122                return array(
123                    PluginUtility::STATE => $state
124                );
125
126
127        }
128        return array();
129
130    }
131
132    /**
133     * Render the output
134     * @param string $format
135     * @param Doku_Renderer $renderer
136     * @param array $data - what the function handle() return
137     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
138     * @see DokuWiki_Syntax_Plugin::render()
139     *
140     *
141     */
142    function render($format, Doku_Renderer $renderer, $data): bool
143    {
144
145        if ($format === "xhtml") {
146            $state = $data[PluginUtility::STATE];
147            switch ($state) {
148                case DOKU_LEXER_ENTER:
149
150                    $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES])
151                        ->setLogicalTag(self::CANONICAL);
152
153                    $targetId = $tagAttributes->getValueAndRemoveIfPresent("target-id");
154                    if ($targetId === null) {
155                        $renderer->doc .= LogUtility::wrapInRedForHtml("The target id is mandatory");
156                        return false;
157                    }
158                    /**
159                     * Snippet
160                     */
161                    PluginUtility::getSnippetManager()->attachCssInternalStyleSheet(self::CANONICAL);
162
163                    $bootstrapNamespace = "bs-";
164                    if (Bootstrap::getBootStrapMajorVersion() == Bootstrap::BootStrapFourMajorVersion) {
165                        $bootstrapNamespace = "";
166                    }
167                    /**
168                     * Types
169                     */
170                    $type = $tagAttributes->getType();
171                    if ($type !== null) {
172                        $tagAttributes->addClassName("btn-$type");
173                    }
174                    /**
175                     * Should be in link form for bootstrap
176                     */
177                    if (substr($targetId, 0, 1) != "#") {
178                        $targetId = "#" . $targetId;
179                    }
180                    $tagAttributes->addComponentAttributeValue("data-{$bootstrapNamespace}toggle", "collapse");
181                    $tagAttributes->addComponentAttributeValue("data-{$bootstrapNamespace}target", $targetId);
182
183                    /**
184                     * Aria
185                     */
186                    $toggleState = $tagAttributes->getValueAndRemove(Toggle::TOGGLE_STATE, Toggle::TOGGLE_STATE_COLLAPSED);
187                    switch ($toggleState) {
188                        case Toggle::TOGGLE_STATE_EXPANDED:
189                            $tagAttributes->addComponentAttributeValue("aria-expanded", true);
190                            break;
191                        case Toggle::TOGGLE_STATE_COLLAPSED:
192                            $tagAttributes->addComponentAttributeValue("aria-expanded", false);
193                            $tagAttributes->addClassName("collapsed");
194                            break;
195                    }
196
197
198                    $targetLabel = $tagAttributes->getValueAndRemoveIfPresent("targetLabel");
199                    if ($targetLabel === null) {
200                        $targetLabel = "Toggle $targetId";
201                    }
202                    $tagAttributes->addComponentAttributeValue("aria-label", $targetLabel);
203                    $tagAttributes->addClassName("btn");
204                    $renderer->doc .= $tagAttributes->toHtmlEnterTag("button");
205                    break;
206                case DOKU_LEXER_UNMATCHED:
207                    $renderer->doc .= PluginUtility::renderUnmatched($data);
208                    break;
209                case DOKU_LEXER_EXIT:
210                    $renderer->doc .= "</button>";
211                    break;
212
213            }
214            return true;
215        }
216
217        // unsupported $mode
218        return false;
219    }
220
221    public
222    static function getTag(): string
223    {
224        return self::TAG;
225    }
226
227
228}
229
230