xref: /plugin/combo/syntax/label.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
15f891b7eSNickeau<?php
25f891b7eSNickeau
35f891b7eSNickeau// implementation of
45f891b7eSNickeau// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite
55f891b7eSNickeau
65f891b7eSNickeau// must be run within Dokuwiki
721913ab3SNickeauuse ComboStrap\Bootstrap;
821913ab3SNickeauuse ComboStrap\CallStack;
95f891b7eSNickeauuse ComboStrap\LogUtility;
10*04fd306cSNickeauuse ComboStrap\PanelTag;
115f891b7eSNickeauuse ComboStrap\PluginUtility;
12*04fd306cSNickeauuse ComboStrap\TabsTag;
13*04fd306cSNickeauuse ComboStrap\XmlTagProcessing;
145f891b7eSNickeau
155f891b7eSNickeau
165f891b7eSNickeauclass syntax_plugin_combo_label extends DokuWiki_Syntax_Plugin
175f891b7eSNickeau{
185f891b7eSNickeau
195f891b7eSNickeau
205f891b7eSNickeau    const TAG = "label";
215f891b7eSNickeau
225f891b7eSNickeau    /**
235f891b7eSNickeau     * The id of the heading element for a accordion label
245f891b7eSNickeau     */
255f891b7eSNickeau    const HEADING_ID = "headingId";
265f891b7eSNickeau    /**
275f891b7eSNickeau     * The id of the collapsable target
285f891b7eSNickeau     */
295f891b7eSNickeau    const TARGET_ID = "targetId";
305f891b7eSNickeau
315f891b7eSNickeau    /**
325f891b7eSNickeau     * An indicator attribute that tells if the accordion is collpased or not
335f891b7eSNickeau     */
345f891b7eSNickeau    const COLLAPSED = "collapsed";
355f891b7eSNickeau
365f891b7eSNickeau    function getType()
375f891b7eSNickeau    {
385f891b7eSNickeau        return 'formatting';
395f891b7eSNickeau    }
405f891b7eSNickeau
415f891b7eSNickeau    /**
425f891b7eSNickeau     * How Dokuwiki will add P element
435f891b7eSNickeau     *
445f891b7eSNickeau     *  * 'normal' - The plugin can be used inside paragraphs (inline)
455f891b7eSNickeau     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
465f891b7eSNickeau     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
475f891b7eSNickeau     *
485f891b7eSNickeau     * @see DokuWiki_Syntax_Plugin::getPType()
495f891b7eSNickeau     */
505f891b7eSNickeau    function getPType()
515f891b7eSNickeau    {
5221913ab3SNickeau        return 'block';
535f891b7eSNickeau    }
545f891b7eSNickeau
555f891b7eSNickeau    function getAllowedTypes()
565f891b7eSNickeau    {
575f891b7eSNickeau        return array('substition', 'formatting', 'disabled');
585f891b7eSNickeau    }
595f891b7eSNickeau
605f891b7eSNickeau    function getSort()
615f891b7eSNickeau    {
625f891b7eSNickeau        return 201;
635f891b7eSNickeau    }
645f891b7eSNickeau
655f891b7eSNickeau
665f891b7eSNickeau    function connectTo($mode)
675f891b7eSNickeau    {
685f891b7eSNickeau
69*04fd306cSNickeau        $this->Lexer->addEntryPattern(XmlTagProcessing::getContainerTagPattern(self::TAG), $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
705f891b7eSNickeau    }
715f891b7eSNickeau
725f891b7eSNickeau    public function postConnect()
735f891b7eSNickeau    {
749337a630SNickeau        $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeFromTag($this->getPluginComponent()));
755f891b7eSNickeau    }
765f891b7eSNickeau
775f891b7eSNickeau    function handle($match, $state, $pos, Doku_Handler $handler)
785f891b7eSNickeau    {
795f891b7eSNickeau
805f891b7eSNickeau        switch ($state) {
815f891b7eSNickeau
825f891b7eSNickeau            case DOKU_LEXER_ENTER:
835f891b7eSNickeau                $tagAttributes = PluginUtility::getTagAttributes($match);
84*04fd306cSNickeau                $callStack = CallStack::createFromHandler($handler);
85*04fd306cSNickeau                $parentTag = $callStack->moveToParent();
865f891b7eSNickeau                $context = null;
87*04fd306cSNickeau                if ($parentTag!==false) {
88*04fd306cSNickeau                    $grandfather = $callStack->moveToParent();
89*04fd306cSNickeau                    if ($grandfather !== false) {
90*04fd306cSNickeau                        $grandFatherName = $grandfather->getTagName();
915f891b7eSNickeau                        switch ($grandFatherName) {
925f891b7eSNickeau                            case syntax_plugin_combo_accordion::TAG:
935f891b7eSNickeau                                $id = $parentTag->getAttribute("id");
945f891b7eSNickeau                                $tagAttributes["id"] = $id;
955f891b7eSNickeau                                $tagAttributes[self::HEADING_ID] = "heading" . ucfirst($id);
965f891b7eSNickeau                                $tagAttributes[self::TARGET_ID] = "collapse" . ucfirst($id);
975f891b7eSNickeau                                $parentAttribute = $parentTag->getAttributes();
985f891b7eSNickeau                                if (!key_exists(self::COLLAPSED, $parentAttribute)) {
995f891b7eSNickeau                                    // Accordion are collapsed by default
1005f891b7eSNickeau                                    $tagAttributes[self::COLLAPSED] = "true";
1015f891b7eSNickeau                                } else {
1025f891b7eSNickeau                                    $tagAttributes[self::COLLAPSED] = $parentAttribute[self::COLLAPSED];
1035f891b7eSNickeau                                }
1045f891b7eSNickeau                                $context = syntax_plugin_combo_accordion::TAG;
1055f891b7eSNickeau                                break;
106*04fd306cSNickeau                            case  TabsTag::TAG:
107*04fd306cSNickeau                                $context = TabsTag::TAG;
1085f891b7eSNickeau                                $tagAttributes = $parentTag->getAttributes();
1095f891b7eSNickeau                                break;
1105f891b7eSNickeau                            default:
1115f891b7eSNickeau                                LogUtility::log2FrontEnd("The label is included in the $grandFatherName component and this is unexpected", LogUtility::LVL_MSG_WARNING, self::TAG);
1125f891b7eSNickeau                        }
11321913ab3SNickeau                    } else {
11421913ab3SNickeau                        /**
11521913ab3SNickeau                         * An panel may render alone in preview
11621913ab3SNickeau                         */
117*04fd306cSNickeau                        if ($parentTag->getContext() == PanelTag::CONTEXT_PREVIEW_ALONE) {
118*04fd306cSNickeau                            $context = PanelTag::CONTEXT_PREVIEW_ALONE;
11921913ab3SNickeau                        }
1205f891b7eSNickeau                    }
1215f891b7eSNickeau                }
1225f891b7eSNickeau
1235f891b7eSNickeau                return array(
1245f891b7eSNickeau                    PluginUtility::STATE => $state,
1255f891b7eSNickeau                    PluginUtility::ATTRIBUTES => $tagAttributes,
1265f891b7eSNickeau                    PluginUtility::CONTEXT => $context
1275f891b7eSNickeau                );
1285f891b7eSNickeau
1295f891b7eSNickeau            case DOKU_LEXER_UNMATCHED :
13032b85071SNickeau                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
1315f891b7eSNickeau
1325f891b7eSNickeau            case DOKU_LEXER_EXIT :
13321913ab3SNickeau                $callStack = CallStack::createFromHandler($handler);
13421913ab3SNickeau                $openingTag = $callStack->moveToPreviousCorrespondingOpeningCall();
1355f891b7eSNickeau                $context = $openingTag->getContext();
13621913ab3SNickeau
13721913ab3SNickeau                /**
13821913ab3SNickeau                 * An image in a label should have no link (ie no anchor)
13921913ab3SNickeau                 * because a anchor is used for navigation
14021913ab3SNickeau                 */
141531e725cSNickeau                $callStack->processNoLinkOnImageToEndStack();
14221913ab3SNickeau
14321913ab3SNickeau                $callStack->closeAndResetPointer();
14421913ab3SNickeau
145531e725cSNickeau
1465f891b7eSNickeau                return array(
1475f891b7eSNickeau                    PluginUtility::STATE => $state,
1485f891b7eSNickeau                    PluginUtility::CONTEXT => $context,
1495f891b7eSNickeau                    PluginUtility::ATTRIBUTES => $openingTag->getAttributes()
1505f891b7eSNickeau                );
1515f891b7eSNickeau
1525f891b7eSNickeau
1535f891b7eSNickeau        }
1545f891b7eSNickeau        return array();
1555f891b7eSNickeau
1565f891b7eSNickeau    }
1575f891b7eSNickeau
1585f891b7eSNickeau    /**
1595f891b7eSNickeau     * Render the output
1605f891b7eSNickeau     * @param string $format
1615f891b7eSNickeau     * @param Doku_Renderer $renderer
1625f891b7eSNickeau     * @param array $data - what the function handle() return'ed
1635f891b7eSNickeau     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
1645f891b7eSNickeau     * @see DokuWiki_Syntax_Plugin::render()
1655f891b7eSNickeau     *
1665f891b7eSNickeau     *
1675f891b7eSNickeau     */
168*04fd306cSNickeau    function render($format, Doku_Renderer $renderer, $data): bool
1695f891b7eSNickeau    {
1705f891b7eSNickeau
1715f891b7eSNickeau        if ($format == 'xhtml') {
1725f891b7eSNickeau
1735f891b7eSNickeau            /** @var Doku_Renderer_xhtml $renderer */
1745f891b7eSNickeau            $state = $data[PluginUtility::STATE];
1755f891b7eSNickeau            switch ($state) {
1765f891b7eSNickeau
1775f891b7eSNickeau                case DOKU_LEXER_ENTER:
1785f891b7eSNickeau
1795f891b7eSNickeau                    $context = $data[PluginUtility::CONTEXT];
1805f891b7eSNickeau                    switch ($context) {
1815f891b7eSNickeau                        case syntax_plugin_combo_accordion::TAG:
1825f891b7eSNickeau                            $attribute = $data[PluginUtility::ATTRIBUTES];
1835f891b7eSNickeau                            $headingId = $attribute[self::HEADING_ID];
1845f891b7eSNickeau                            $collapseId = $attribute[self::TARGET_ID];
1855f891b7eSNickeau                            $collapsed = $attribute[self::COLLAPSED];
1865f891b7eSNickeau                            if ($collapsed == "false") {
1875f891b7eSNickeau                                $collapsedClass = "collapsed";
188*04fd306cSNickeau                                $ariaExpanded = "true";
1895f891b7eSNickeau                            } else {
1905f891b7eSNickeau                                $collapsedClass = "";
191*04fd306cSNickeau                                $ariaExpanded = "false";
1925f891b7eSNickeau                            }
1935f891b7eSNickeau                            $renderer->doc .= "<div class=\"card-header\" id=\"$headingId\">" . DOKU_LF;
1945f891b7eSNickeau                            $renderer->doc .= "<h2 class=\"mb-0\">";
19521913ab3SNickeau                            $dataNamespace = Bootstrap::getDataNamespace();
196*04fd306cSNickeau                            /** @noinspection HtmlUnknownAttribute */
197*04fd306cSNickeau                            $renderer->doc .= "<button class=\"btn btn-link btn-block text-left $collapsedClass\" type=\"button\" data{$dataNamespace}-toggle=\"collapse\" data{$dataNamespace}-target=\"#$collapseId\" aria-expanded=\"$ariaExpanded\" aria-controls=\"$collapseId\">";
1985f891b7eSNickeau                            break;
199*04fd306cSNickeau                        case TabsTag::TAG:
2005f891b7eSNickeau                            $attributes = $data[PluginUtility::ATTRIBUTES];
201*04fd306cSNickeau                            $renderer->doc .= TabsTag::openNavigationalTabElement($attributes);
2025f891b7eSNickeau                            break;
203*04fd306cSNickeau                        case PanelTag::CONTEXT_PREVIEW_ALONE:
204*04fd306cSNickeau                            $attributes = PanelTag::CONTEXT_PREVIEW_ALONE_ATTRIBUTES;
20521913ab3SNickeau                            $renderer->doc .= "<ul style=\"list-style-type: none;padding-inline-start: 0;\">";
206*04fd306cSNickeau                            $renderer->doc .= TabsTag::openNavigationalTabElement($attributes);
20721913ab3SNickeau                            break;
2085f891b7eSNickeau                        default:
20921913ab3SNickeau                            LogUtility::log2FrontEnd("The context ($context) of the label is unknown in enter", LogUtility::LVL_MSG_WARNING, self::TAG);
21021913ab3SNickeau
2115f891b7eSNickeau                    }
2125f891b7eSNickeau                    break;
2135f891b7eSNickeau
2145f891b7eSNickeau                case DOKU_LEXER_UNMATCHED :
21532b85071SNickeau                    $renderer->doc .= PluginUtility::renderUnmatched($data);
2165f891b7eSNickeau                    break;
2175f891b7eSNickeau
2185f891b7eSNickeau                case DOKU_LEXER_EXIT:
2195f891b7eSNickeau                    $context = $data[PluginUtility::CONTEXT];
2205f891b7eSNickeau                    switch ($context) {
2215f891b7eSNickeau                        case syntax_plugin_combo_accordion::TAG:
2225f891b7eSNickeau                            $attribute = $data[PluginUtility::ATTRIBUTES];
2235f891b7eSNickeau                            $collapseId = $attribute[self::TARGET_ID];
2245f891b7eSNickeau                            $headingId = $attribute[self::HEADING_ID];
2255f891b7eSNickeau                            $collapsed = $attribute[self::COLLAPSED];
2265f891b7eSNickeau                            if ($collapsed == "false") {
2275f891b7eSNickeau                                $showClass = "show";
2285f891b7eSNickeau                            } else {
2295f891b7eSNickeau                                $showClass = "";
2305f891b7eSNickeau                            }
2315f891b7eSNickeau                            $renderer->doc .= "</button></h2></div>";
23221913ab3SNickeau                            $dataNamespace = Bootstrap::getDataNamespace();
23321913ab3SNickeau                            $renderer->doc .= "<div id=\"$collapseId\" class=\"collapse $showClass\" aria-labelledby=\"$headingId\" data-{$dataNamespace}parent=\"#$headingId\">";
2345f891b7eSNickeau                            $renderer->doc .= "<div class=\"card-body\">" . DOKU_LF;
2355f891b7eSNickeau                            break;
236*04fd306cSNickeau                        case TabsTag::TAG:
237*04fd306cSNickeau                            $renderer->doc .= TabsTag::closeNavigationalTabElement();
2385f891b7eSNickeau                            break;
239*04fd306cSNickeau                        case PanelTag::CONTEXT_PREVIEW_ALONE:
240*04fd306cSNickeau                            $renderer->doc .= TabsTag::closeNavigationalTabElement();
24121913ab3SNickeau                            $renderer->doc .= "</ul>";
24221913ab3SNickeau                            break;
2435f891b7eSNickeau                        default:
2445f891b7eSNickeau                            LogUtility::log2FrontEnd("The context ($context) of the label is unknown in exit", LogUtility::LVL_MSG_WARNING, self::TAG);
2455f891b7eSNickeau
24621913ab3SNickeau
2475f891b7eSNickeau                    }
2485f891b7eSNickeau                    break;
2495f891b7eSNickeau
2505f891b7eSNickeau
2515f891b7eSNickeau            }
2525f891b7eSNickeau        }
2535f891b7eSNickeau        // unsupported $mode
2545f891b7eSNickeau        return false;
2555f891b7eSNickeau    }
2565f891b7eSNickeau
2575f891b7eSNickeau
2585f891b7eSNickeau}
2595f891b7eSNickeau
260