xref: /plugin/combo/syntax/label.php (revision 23723136447b7913f53b9b11536e95bab29a3790)
1<?php
2
3// implementation of
4// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite
5
6// must be run within Dokuwiki
7use ComboStrap\Bootstrap;
8use ComboStrap\CallStack;
9use ComboStrap\MediaLink;
10use ComboStrap\LogUtility;
11use ComboStrap\PluginUtility;
12use ComboStrap\Tag;
13use ComboStrap\TagAttributes;
14
15
16require_once(__DIR__ . '/../class/HeaderUtility.php');
17
18if (!defined('DOKU_INC')) die();
19
20
21class syntax_plugin_combo_label extends DokuWiki_Syntax_Plugin
22{
23
24
25    const TAG = "label";
26
27    /**
28     * The id of the heading element for a accordion label
29     */
30    const HEADING_ID = "headingId";
31    /**
32     * The id of the collapsable target
33     */
34    const TARGET_ID = "targetId";
35
36    /**
37     * An indicator attribute that tells if the accordion is collpased or not
38     */
39    const COLLAPSED = "collapsed";
40
41    function getType()
42    {
43        return 'formatting';
44    }
45
46    /**
47     * How Dokuwiki will add P element
48     *
49     *  * 'normal' - The plugin can be used inside paragraphs (inline)
50     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
51     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
52     *
53     * @see DokuWiki_Syntax_Plugin::getPType()
54     */
55    function getPType()
56    {
57        return 'block';
58    }
59
60    function getAllowedTypes()
61    {
62        return array('substition', 'formatting', 'disabled');
63    }
64
65    function getSort()
66    {
67        return 201;
68    }
69
70
71    function connectTo($mode)
72    {
73
74        $this->Lexer->addEntryPattern(PluginUtility::getContainerTagPattern(self::TAG), $mode, PluginUtility::getModeForComponent($this->getPluginComponent()));
75    }
76
77    public function postConnect()
78    {
79        $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeForComponent($this->getPluginComponent()));
80    }
81
82    function handle($match, $state, $pos, Doku_Handler $handler)
83    {
84
85        switch ($state) {
86
87            case DOKU_LEXER_ENTER:
88                $tagAttributes = PluginUtility::getTagAttributes($match);
89
90                $tag = new Tag(self::TAG, $tagAttributes, $state, $handler);
91                $parentTag = $tag->getParent();
92                $context = null;
93                if ($parentTag != null) {
94                    $grandfather = $parentTag->getParent();
95                    if ($grandfather != null) {
96                        $grandFatherName = $grandfather->getName();
97                        switch ($grandFatherName) {
98                            case syntax_plugin_combo_accordion::TAG:
99                                $id = $parentTag->getAttribute("id");
100                                $tagAttributes["id"] = $id;
101                                $tagAttributes[self::HEADING_ID] = "heading" . ucfirst($id);
102                                $tagAttributes[self::TARGET_ID] = "collapse" . ucfirst($id);
103                                $parentAttribute = $parentTag->getAttributes();
104                                if (!key_exists(self::COLLAPSED, $parentAttribute)) {
105                                    // Accordion are collapsed by default
106                                    $tagAttributes[self::COLLAPSED] = "true";
107                                } else {
108                                    $tagAttributes[self::COLLAPSED] = $parentAttribute[self::COLLAPSED];
109                                }
110                                $context = syntax_plugin_combo_accordion::TAG;
111                                break;
112                            case  syntax_plugin_combo_tabs::TAG:
113                                $context = syntax_plugin_combo_tabs::TAG;
114                                $tagAttributes = $parentTag->getAttributes();
115                                break;
116                            default:
117                                LogUtility::log2FrontEnd("The label is included in the $grandFatherName component and this is unexpected", LogUtility::LVL_MSG_WARNING, self::TAG);
118                        }
119                    } else {
120                        /**
121                         * An panel may render alone in preview
122                         */
123                        if ($parentTag->getContext() == syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE) {
124                            $context = syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE;
125                        }
126                    }
127                }
128
129                return array(
130                    PluginUtility::STATE => $state,
131                    PluginUtility::ATTRIBUTES => $tagAttributes,
132                    PluginUtility::CONTEXT => $context
133                );
134
135            case DOKU_LEXER_UNMATCHED :
136                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
137
138            case DOKU_LEXER_EXIT :
139                $callStack = CallStack::createFromHandler($handler);
140                $openingTag = $callStack->moveToPreviousCorrespondingOpeningCall();
141                $context = $openingTag->getContext();
142
143                /**
144                 * An image in a label should have no link (ie no anchor)
145                 * because a anchor is used for navigation
146                 */
147                while ($callStack->next()) {
148                    $actualCall = $callStack->getActualCall();
149                    if ($actualCall->getTagName() == syntax_plugin_combo_media::TAG) {
150                        $actualCall->addAttribute(TagAttributes::LINKING_KEY, MediaLink::LINKING_NOLINK_VALUE);
151                    }
152                }
153
154                $callStack->closeAndResetPointer();
155
156                return array(
157                    PluginUtility::STATE => $state,
158                    PluginUtility::CONTEXT => $context,
159                    PluginUtility::ATTRIBUTES => $openingTag->getAttributes()
160                );
161
162
163        }
164        return array();
165
166    }
167
168    /**
169     * Render the output
170     * @param string $format
171     * @param Doku_Renderer $renderer
172     * @param array $data - what the function handle() return'ed
173     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
174     * @see DokuWiki_Syntax_Plugin::render()
175     *
176     *
177     */
178    function render($format, Doku_Renderer $renderer, $data)
179    {
180
181        if ($format == 'xhtml') {
182
183            /** @var Doku_Renderer_xhtml $renderer */
184            $state = $data[PluginUtility::STATE];
185            switch ($state) {
186
187                case DOKU_LEXER_ENTER:
188
189                    $context = $data[PluginUtility::CONTEXT];
190                    switch ($context) {
191                        case syntax_plugin_combo_accordion::TAG:
192                            $attribute = $data[PluginUtility::ATTRIBUTES];
193                            $headingId = $attribute[self::HEADING_ID];
194                            $collapseId = $attribute[self::TARGET_ID];
195                            $collapsed = $attribute[self::COLLAPSED];
196                            if ($collapsed == "false") {
197                                $collapsedClass = "collapsed";
198                            } else {
199                                $collapsedClass = "";
200                            }
201                            $renderer->doc .= "<div class=\"card-header\" id=\"$headingId\">" . DOKU_LF;
202                            $renderer->doc .= "<h2 class=\"mb-0\">";
203                            $dataNamespace = Bootstrap::getDataNamespace();
204                            $renderer->doc .= "<button class=\"btn btn-link btn-block text-left $collapsedClass\" type=\"button\" data{$dataNamespace}-toggle=\"collapse\" data{$dataNamespace}-target=\"#$collapseId\" aria-expanded=\"true\" aria-controls=\"$collapseId\">";
205                            break;
206                        case syntax_plugin_combo_tabs::TAG:
207                            $attributes = $data[PluginUtility::ATTRIBUTES];
208                            $renderer->doc .= syntax_plugin_combo_tabs::openNavigationalTabElement($attributes);
209                            break;
210                        case syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE:
211                            $attributes = syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE_ATTRIBUTES;
212                            $renderer->doc .= "<ul style=\"list-style-type: none;padding-inline-start: 0;\">";
213                            $renderer->doc .= syntax_plugin_combo_tabs::openNavigationalTabElement($attributes);
214                            break;
215                        default:
216                            LogUtility::log2FrontEnd("The context ($context) of the label is unknown in enter", LogUtility::LVL_MSG_WARNING, self::TAG);
217
218                    }
219                    break;
220
221                case DOKU_LEXER_UNMATCHED :
222                    $renderer->doc .= PluginUtility::renderUnmatched($data);
223                    break;
224
225                case DOKU_LEXER_EXIT:
226                    $context = $data[PluginUtility::CONTEXT];
227                    switch ($context) {
228                        case syntax_plugin_combo_accordion::TAG:
229                            $attribute = $data[PluginUtility::ATTRIBUTES];
230                            $collapseId = $attribute[self::TARGET_ID];
231                            $headingId = $attribute[self::HEADING_ID];
232                            $collapsed = $attribute[self::COLLAPSED];
233                            if ($collapsed == "false") {
234                                $showClass = "show";
235                            } else {
236                                $showClass = "";
237                            }
238                            $renderer->doc .= "</button></h2></div>";
239                            $dataNamespace = Bootstrap::getDataNamespace();
240                            $renderer->doc .= "<div id=\"$collapseId\" class=\"collapse $showClass\" aria-labelledby=\"$headingId\" data-{$dataNamespace}parent=\"#$headingId\">";
241                            $renderer->doc .= "<div class=\"card-body\">" . DOKU_LF;
242                            break;
243                        case syntax_plugin_combo_tabs::TAG:
244                            $renderer->doc .= syntax_plugin_combo_tabs::closeNavigationalTabElement();
245                            break;
246                        case syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE:
247                            $renderer->doc .= syntax_plugin_combo_tabs::closeNavigationalTabElement();
248                            $renderer->doc .= "</ul>";
249                            break;
250                        default:
251                            LogUtility::log2FrontEnd("The context ($context) of the label is unknown in exit", LogUtility::LVL_MSG_WARNING, self::TAG);
252
253
254                    }
255                    break;
256
257
258            }
259        }
260        // unsupported $mode
261        return false;
262    }
263
264
265}
266
267