xref: /plugin/combo/syntax/label.php (revision 21913ab3235d516e2fa19c7e3929b555b3a2bda1)
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
7*21913ab3SNickeauuse ComboStrap\Bootstrap;
8*21913ab3SNickeauuse ComboStrap\CallStack;
9*21913ab3SNickeauuse ComboStrap\InternalMediaLink;
105f891b7eSNickeauuse ComboStrap\LogUtility;
115f891b7eSNickeauuse ComboStrap\PluginUtility;
125f891b7eSNickeauuse ComboStrap\Tag;
13*21913ab3SNickeauuse ComboStrap\TagAttributes;
14*21913ab3SNickeau
155f891b7eSNickeau
165f891b7eSNickeaurequire_once(__DIR__ . '/../class/HeaderUtility.php');
175f891b7eSNickeau
185f891b7eSNickeauif (!defined('DOKU_INC')) die();
195f891b7eSNickeau
205f891b7eSNickeau
215f891b7eSNickeauclass syntax_plugin_combo_label extends DokuWiki_Syntax_Plugin
225f891b7eSNickeau{
235f891b7eSNickeau
245f891b7eSNickeau
255f891b7eSNickeau    const TAG = "label";
265f891b7eSNickeau
275f891b7eSNickeau    /**
285f891b7eSNickeau     * The id of the heading element for a accordion label
295f891b7eSNickeau     */
305f891b7eSNickeau    const HEADING_ID = "headingId";
315f891b7eSNickeau    /**
325f891b7eSNickeau     * The id of the collapsable target
335f891b7eSNickeau     */
345f891b7eSNickeau    const TARGET_ID = "targetId";
355f891b7eSNickeau
365f891b7eSNickeau    /**
375f891b7eSNickeau     * An indicator attribute that tells if the accordion is collpased or not
385f891b7eSNickeau     */
395f891b7eSNickeau    const COLLAPSED = "collapsed";
405f891b7eSNickeau
415f891b7eSNickeau    function getType()
425f891b7eSNickeau    {
435f891b7eSNickeau        return 'formatting';
445f891b7eSNickeau    }
455f891b7eSNickeau
465f891b7eSNickeau    /**
475f891b7eSNickeau     * How Dokuwiki will add P element
485f891b7eSNickeau     *
495f891b7eSNickeau     *  * 'normal' - The plugin can be used inside paragraphs (inline)
505f891b7eSNickeau     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
515f891b7eSNickeau     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
525f891b7eSNickeau     *
535f891b7eSNickeau     * @see DokuWiki_Syntax_Plugin::getPType()
545f891b7eSNickeau     */
555f891b7eSNickeau    function getPType()
565f891b7eSNickeau    {
57*21913ab3SNickeau        return 'block';
585f891b7eSNickeau    }
595f891b7eSNickeau
605f891b7eSNickeau    function getAllowedTypes()
615f891b7eSNickeau    {
625f891b7eSNickeau        return array('substition', 'formatting', 'disabled');
635f891b7eSNickeau    }
645f891b7eSNickeau
655f891b7eSNickeau    function getSort()
665f891b7eSNickeau    {
675f891b7eSNickeau        return 201;
685f891b7eSNickeau    }
695f891b7eSNickeau
705f891b7eSNickeau
715f891b7eSNickeau    function connectTo($mode)
725f891b7eSNickeau    {
735f891b7eSNickeau
745f891b7eSNickeau        $this->Lexer->addEntryPattern(PluginUtility::getContainerTagPattern(self::TAG), $mode, PluginUtility::getModeForComponent($this->getPluginComponent()));
755f891b7eSNickeau    }
765f891b7eSNickeau
775f891b7eSNickeau    public function postConnect()
785f891b7eSNickeau    {
795f891b7eSNickeau        $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeForComponent($this->getPluginComponent()));
805f891b7eSNickeau    }
815f891b7eSNickeau
825f891b7eSNickeau    function handle($match, $state, $pos, Doku_Handler $handler)
835f891b7eSNickeau    {
845f891b7eSNickeau
855f891b7eSNickeau        switch ($state) {
865f891b7eSNickeau
875f891b7eSNickeau            case DOKU_LEXER_ENTER:
885f891b7eSNickeau                $tagAttributes = PluginUtility::getTagAttributes($match);
895f891b7eSNickeau
905f891b7eSNickeau                $tag = new Tag(self::TAG, $tagAttributes, $state, $handler);
915f891b7eSNickeau                $parentTag = $tag->getParent();
925f891b7eSNickeau                $context = null;
935f891b7eSNickeau                if ($parentTag != null) {
945f891b7eSNickeau                    $grandfather = $parentTag->getParent();
955f891b7eSNickeau                    if ($grandfather != null) {
965f891b7eSNickeau                        $grandFatherName = $grandfather->getName();
975f891b7eSNickeau                        switch ($grandFatherName) {
985f891b7eSNickeau                            case syntax_plugin_combo_accordion::TAG:
995f891b7eSNickeau                                $id = $parentTag->getAttribute("id");
1005f891b7eSNickeau                                $tagAttributes["id"] = $id;
1015f891b7eSNickeau                                $tagAttributes[self::HEADING_ID] = "heading" . ucfirst($id);
1025f891b7eSNickeau                                $tagAttributes[self::TARGET_ID] = "collapse" . ucfirst($id);
1035f891b7eSNickeau                                $parentAttribute = $parentTag->getAttributes();
1045f891b7eSNickeau                                if (!key_exists(self::COLLAPSED, $parentAttribute)) {
1055f891b7eSNickeau                                    // Accordion are collapsed by default
1065f891b7eSNickeau                                    $tagAttributes[self::COLLAPSED] = "true";
1075f891b7eSNickeau                                } else {
1085f891b7eSNickeau                                    $tagAttributes[self::COLLAPSED] = $parentAttribute[self::COLLAPSED];
1095f891b7eSNickeau                                }
1105f891b7eSNickeau                                $context = syntax_plugin_combo_accordion::TAG;
1115f891b7eSNickeau                                break;
1125f891b7eSNickeau                            case  syntax_plugin_combo_tabs::TAG:
1135f891b7eSNickeau                                $context = syntax_plugin_combo_tabs::TAG;
1145f891b7eSNickeau                                $tagAttributes = $parentTag->getAttributes();
1155f891b7eSNickeau                                break;
1165f891b7eSNickeau                            default:
1175f891b7eSNickeau                                LogUtility::log2FrontEnd("The label is included in the $grandFatherName component and this is unexpected", LogUtility::LVL_MSG_WARNING, self::TAG);
1185f891b7eSNickeau                        }
119*21913ab3SNickeau                    } else {
120*21913ab3SNickeau                        /**
121*21913ab3SNickeau                         * An panel may render alone in preview
122*21913ab3SNickeau                         */
123*21913ab3SNickeau                        if ($parentTag->getContext() == syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE) {
124*21913ab3SNickeau                            $context = syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE;
125*21913ab3SNickeau                        }
1265f891b7eSNickeau                    }
1275f891b7eSNickeau                }
1285f891b7eSNickeau
1295f891b7eSNickeau                return array(
1305f891b7eSNickeau                    PluginUtility::STATE => $state,
1315f891b7eSNickeau                    PluginUtility::ATTRIBUTES => $tagAttributes,
1325f891b7eSNickeau                    PluginUtility::CONTEXT => $context
1335f891b7eSNickeau                );
1345f891b7eSNickeau
1355f891b7eSNickeau            case DOKU_LEXER_UNMATCHED :
13632b85071SNickeau                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
1375f891b7eSNickeau
1385f891b7eSNickeau            case DOKU_LEXER_EXIT :
139*21913ab3SNickeau                $callStack = CallStack::createFromHandler($handler);
140*21913ab3SNickeau                $openingTag = $callStack->moveToPreviousCorrespondingOpeningCall();
1415f891b7eSNickeau                $context = $openingTag->getContext();
142*21913ab3SNickeau
143*21913ab3SNickeau                /**
144*21913ab3SNickeau                 * An image in a label should have no link (ie no anchor)
145*21913ab3SNickeau                 * because a anchor is used for navigation
146*21913ab3SNickeau                 */
147*21913ab3SNickeau                while ($callStack->next()) {
148*21913ab3SNickeau                    $actualCall = $callStack->getActualCall();
149*21913ab3SNickeau                    if ($actualCall->getTagName() == syntax_plugin_combo_media::TAG) {
150*21913ab3SNickeau                        $actualCall->addAttribute(TagAttributes::LINKING_KEY, InternalMediaLink::LINKING_NOLINK_VALUE);
151*21913ab3SNickeau                    }
152*21913ab3SNickeau                }
153*21913ab3SNickeau
154*21913ab3SNickeau                $callStack->closeAndResetPointer();
155*21913ab3SNickeau
1565f891b7eSNickeau                return array(
1575f891b7eSNickeau                    PluginUtility::STATE => $state,
1585f891b7eSNickeau                    PluginUtility::CONTEXT => $context,
1595f891b7eSNickeau                    PluginUtility::ATTRIBUTES => $openingTag->getAttributes()
1605f891b7eSNickeau                );
1615f891b7eSNickeau
1625f891b7eSNickeau
1635f891b7eSNickeau        }
1645f891b7eSNickeau        return array();
1655f891b7eSNickeau
1665f891b7eSNickeau    }
1675f891b7eSNickeau
1685f891b7eSNickeau    /**
1695f891b7eSNickeau     * Render the output
1705f891b7eSNickeau     * @param string $format
1715f891b7eSNickeau     * @param Doku_Renderer $renderer
1725f891b7eSNickeau     * @param array $data - what the function handle() return'ed
1735f891b7eSNickeau     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
1745f891b7eSNickeau     * @see DokuWiki_Syntax_Plugin::render()
1755f891b7eSNickeau     *
1765f891b7eSNickeau     *
1775f891b7eSNickeau     */
1785f891b7eSNickeau    function render($format, Doku_Renderer $renderer, $data)
1795f891b7eSNickeau    {
1805f891b7eSNickeau
1815f891b7eSNickeau        if ($format == 'xhtml') {
1825f891b7eSNickeau
1835f891b7eSNickeau            /** @var Doku_Renderer_xhtml $renderer */
1845f891b7eSNickeau            $state = $data[PluginUtility::STATE];
1855f891b7eSNickeau            switch ($state) {
1865f891b7eSNickeau
1875f891b7eSNickeau                case DOKU_LEXER_ENTER:
1885f891b7eSNickeau
1895f891b7eSNickeau                    $context = $data[PluginUtility::CONTEXT];
1905f891b7eSNickeau                    switch ($context) {
1915f891b7eSNickeau                        case syntax_plugin_combo_accordion::TAG:
1925f891b7eSNickeau                            $attribute = $data[PluginUtility::ATTRIBUTES];
1935f891b7eSNickeau                            $headingId = $attribute[self::HEADING_ID];
1945f891b7eSNickeau                            $collapseId = $attribute[self::TARGET_ID];
1955f891b7eSNickeau                            $collapsed = $attribute[self::COLLAPSED];
1965f891b7eSNickeau                            if ($collapsed == "false") {
1975f891b7eSNickeau                                $collapsedClass = "collapsed";
1985f891b7eSNickeau                            } else {
1995f891b7eSNickeau                                $collapsedClass = "";
2005f891b7eSNickeau                            }
2015f891b7eSNickeau                            $renderer->doc .= "<div class=\"card-header\" id=\"$headingId\">" . DOKU_LF;
2025f891b7eSNickeau                            $renderer->doc .= "<h2 class=\"mb-0\">";
203*21913ab3SNickeau                            $dataNamespace = Bootstrap::getDataNamespace();
204*21913ab3SNickeau                            $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\">";
2055f891b7eSNickeau                            break;
2065f891b7eSNickeau                        case syntax_plugin_combo_tabs::TAG:
2075f891b7eSNickeau                            $attributes = $data[PluginUtility::ATTRIBUTES];
2085f891b7eSNickeau                            $renderer->doc .= syntax_plugin_combo_tabs::openNavigationalTabElement($attributes);
2095f891b7eSNickeau                            break;
210*21913ab3SNickeau                        case syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE:
211*21913ab3SNickeau                            $attributes = syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE_ATTRIBUTES;
212*21913ab3SNickeau                            $renderer->doc .= "<ul style=\"list-style-type: none;padding-inline-start: 0;\">";
213*21913ab3SNickeau                            $renderer->doc .= syntax_plugin_combo_tabs::openNavigationalTabElement($attributes);
214*21913ab3SNickeau                            break;
2155f891b7eSNickeau                        default:
216*21913ab3SNickeau                            LogUtility::log2FrontEnd("The context ($context) of the label is unknown in enter", LogUtility::LVL_MSG_WARNING, self::TAG);
217*21913ab3SNickeau
2185f891b7eSNickeau                    }
2195f891b7eSNickeau                    break;
2205f891b7eSNickeau
2215f891b7eSNickeau                case DOKU_LEXER_UNMATCHED :
22232b85071SNickeau                    $renderer->doc .= PluginUtility::renderUnmatched($data);
2235f891b7eSNickeau                    break;
2245f891b7eSNickeau
2255f891b7eSNickeau                case DOKU_LEXER_EXIT:
2265f891b7eSNickeau                    $context = $data[PluginUtility::CONTEXT];
2275f891b7eSNickeau                    switch ($context) {
2285f891b7eSNickeau                        case syntax_plugin_combo_accordion::TAG:
2295f891b7eSNickeau                            $attribute = $data[PluginUtility::ATTRIBUTES];
2305f891b7eSNickeau                            $collapseId = $attribute[self::TARGET_ID];
2315f891b7eSNickeau                            $headingId = $attribute[self::HEADING_ID];
2325f891b7eSNickeau                            $collapsed = $attribute[self::COLLAPSED];
2335f891b7eSNickeau                            if ($collapsed == "false") {
2345f891b7eSNickeau                                $showClass = "show";
2355f891b7eSNickeau                            } else {
2365f891b7eSNickeau                                $showClass = "";
2375f891b7eSNickeau                            }
2385f891b7eSNickeau                            $renderer->doc .= "</button></h2></div>";
239*21913ab3SNickeau                            $dataNamespace = Bootstrap::getDataNamespace();
240*21913ab3SNickeau                            $renderer->doc .= "<div id=\"$collapseId\" class=\"collapse $showClass\" aria-labelledby=\"$headingId\" data-{$dataNamespace}parent=\"#$headingId\">";
2415f891b7eSNickeau                            $renderer->doc .= "<div class=\"card-body\">" . DOKU_LF;
2425f891b7eSNickeau                            break;
2435f891b7eSNickeau                        case syntax_plugin_combo_tabs::TAG:
2445f891b7eSNickeau                            $renderer->doc .= syntax_plugin_combo_tabs::closeNavigationalTabElement();
2455f891b7eSNickeau                            break;
246*21913ab3SNickeau                        case syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE:
247*21913ab3SNickeau                            $renderer->doc .= syntax_plugin_combo_tabs::closeNavigationalTabElement();
248*21913ab3SNickeau                            $renderer->doc .= "</ul>";
249*21913ab3SNickeau                            break;
2505f891b7eSNickeau                        default:
2515f891b7eSNickeau                            LogUtility::log2FrontEnd("The context ($context) of the label is unknown in exit", LogUtility::LVL_MSG_WARNING, self::TAG);
2525f891b7eSNickeau
253*21913ab3SNickeau
2545f891b7eSNickeau                    }
2555f891b7eSNickeau                    break;
2565f891b7eSNickeau
2575f891b7eSNickeau
2585f891b7eSNickeau            }
2595f891b7eSNickeau        }
2605f891b7eSNickeau        // unsupported $mode
2615f891b7eSNickeau        return false;
2625f891b7eSNickeau    }
2635f891b7eSNickeau
2645f891b7eSNickeau
2655f891b7eSNickeau}
2665f891b7eSNickeau
267