xref: /plugin/combo/ComboStrap/PanelTag.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1*04fd306cSNickeau<?php
2*04fd306cSNickeau
3*04fd306cSNickeaunamespace ComboStrap;
4*04fd306cSNickeau
5*04fd306cSNickeau
6*04fd306cSNickeauuse Doku_Handler;
7*04fd306cSNickeauuse syntax_plugin_combo_accordion;
8*04fd306cSNickeauuse syntax_plugin_combo_label;
9*04fd306cSNickeauuse syntax_plugin_combo_tab;
10*04fd306cSNickeau
11*04fd306cSNickeau/**
12*04fd306cSNickeau * A panel wrap content that is cached
13*04fd306cSNickeau * via tabs or accordon
14*04fd306cSNickeau */
15*04fd306cSNickeauclass PanelTag
16*04fd306cSNickeau{
17*04fd306cSNickeau
18*04fd306cSNickeau
19*04fd306cSNickeau    public const SELECTED = 'selected';
20*04fd306cSNickeau    public const PANEL_MARKUP = 'panel';
21*04fd306cSNickeau    public const CANONICAL = PanelTag::PANEL_LOGICAL_MARKUP;
22*04fd306cSNickeau    public const PANEL_LOGICAL_MARKUP = 'panel';
23*04fd306cSNickeau    public const STATE = 'state';
24*04fd306cSNickeau    public const TAB_PANEL_MARKUP = 'tabpanel';
25*04fd306cSNickeau    public const CONTEXT_PREVIEW_ALONE_ATTRIBUTES = array(
26*04fd306cSNickeau        PanelTag::SELECTED => true,
27*04fd306cSNickeau        TagAttributes::ID_KEY => "alone",
28*04fd306cSNickeau        TagAttributes::TYPE_KEY => TabsTag::ENCLOSED_TABS_TYPE
29*04fd306cSNickeau    );
30*04fd306cSNickeau    public const CONF_ENABLE_SECTION_EDITING = "panelEnableSectionEditing";
31*04fd306cSNickeau    /**
32*04fd306cSNickeau     * When the panel is alone in the edit due to the sectioning
33*04fd306cSNickeau     */
34*04fd306cSNickeau    public const CONTEXT_PREVIEW_ALONE = "preview_alone";
35*04fd306cSNickeau
36*04fd306cSNickeau    public static function getSelectedValue(TagAttributes $tagAttributes)
37*04fd306cSNickeau    {
38*04fd306cSNickeau        $selected = $tagAttributes->getValueAndRemoveIfPresent(PanelTag::SELECTED);
39*04fd306cSNickeau        if ($selected !== null) {
40*04fd306cSNickeau            /**
41*04fd306cSNickeau             * Value may be false/true
42*04fd306cSNickeau             */
43*04fd306cSNickeau            return DataType::toBoolean($selected);
44*04fd306cSNickeau
45*04fd306cSNickeau        }
46*04fd306cSNickeau        if ($tagAttributes->hasComponentAttribute(TagAttributes::TYPE_KEY)) {
47*04fd306cSNickeau            $type = $tagAttributes->getType();
48*04fd306cSNickeau            if (strtolower($type) === "selected") {
49*04fd306cSNickeau                return true;
50*04fd306cSNickeau            }
51*04fd306cSNickeau        }
52*04fd306cSNickeau        return false;
53*04fd306cSNickeau
54*04fd306cSNickeau    }
55*04fd306cSNickeau
56*04fd306cSNickeau
57*04fd306cSNickeau    public static function handleEnter(TagAttributes $tagAttributes, Doku_Handler $handler, string $markupTag): array
58*04fd306cSNickeau    {
59*04fd306cSNickeau
60*04fd306cSNickeau        $callStack = CallStack::createFromHandler($handler);
61*04fd306cSNickeau        $parent = $callStack->moveToParent();
62*04fd306cSNickeau        if ($parent !== false) {
63*04fd306cSNickeau            $context = $parent->getTagName();
64*04fd306cSNickeau        } else {
65*04fd306cSNickeau            /**
66*04fd306cSNickeau             * The panel may be alone in preview
67*04fd306cSNickeau             * due to the section edit button
68*04fd306cSNickeau             */
69*04fd306cSNickeau            global $ACT;
70*04fd306cSNickeau            if ($ACT == "preview") {
71*04fd306cSNickeau                $context = PanelTag::CONTEXT_PREVIEW_ALONE;
72*04fd306cSNickeau            } else {
73*04fd306cSNickeau                // to be able to see the old markup
74*04fd306cSNickeau                $context = $markupTag;
75*04fd306cSNickeau            }
76*04fd306cSNickeau        }
77*04fd306cSNickeau
78*04fd306cSNickeau        $idManager = ExecutionContext::getActualOrCreateFromEnv()->getIdManager();
79*04fd306cSNickeau
80*04fd306cSNickeau        try {
81*04fd306cSNickeau            $id = $tagAttributes->getId();
82*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
83*04fd306cSNickeau            $id = $idManager->generateNewHtmlIdForComponent(self::PANEL_LOGICAL_MARKUP . "-" . $context);
84*04fd306cSNickeau            $tagAttributes->setId($id);
85*04fd306cSNickeau        }
86*04fd306cSNickeau
87*04fd306cSNickeau        /**
88*04fd306cSNickeau         * Old deprecated syntax
89*04fd306cSNickeau         */
90*04fd306cSNickeau        if ($markupTag == PanelTag::TAB_PANEL_MARKUP) {
91*04fd306cSNickeau
92*04fd306cSNickeau            $context = PanelTag::TAB_PANEL_MARKUP;
93*04fd306cSNickeau
94*04fd306cSNickeau            $siblingTag = $callStack->moveToPreviousSiblingTag();
95*04fd306cSNickeau            if ($siblingTag != null) {
96*04fd306cSNickeau                if ($siblingTag->getTagName() === TabsTag::TAG) {
97*04fd306cSNickeau                    $tagAttributes->setComponentAttributeValue(PanelTag::SELECTED, false);
98*04fd306cSNickeau                    while ($descendant = $callStack->next()) {
99*04fd306cSNickeau                        $descendantName = $descendant->getTagName();
100*04fd306cSNickeau                        $descendantPanel = $descendant->getAttribute("panel");
101*04fd306cSNickeau                        $descendantSelected = $descendant->getAttribute(PanelTag::SELECTED);
102*04fd306cSNickeau                        if (
103*04fd306cSNickeau                            $descendantName == syntax_plugin_combo_tab::TAG
104*04fd306cSNickeau                            && $descendantPanel === $id
105*04fd306cSNickeau                            && $descendantSelected === "true") {
106*04fd306cSNickeau                            $tagAttributes->setComponentAttributeValue(PanelTag::SELECTED, true);
107*04fd306cSNickeau                            break;
108*04fd306cSNickeau                        }
109*04fd306cSNickeau                    }
110*04fd306cSNickeau                } else {
111*04fd306cSNickeau                    LogUtility::msg("The direct element above a " . PanelTag::TAB_PANEL_MARKUP . " should be a `tabs` and not a `" . $siblingTag->getTagName() . "`", LogUtility::LVL_MSG_ERROR, "tabs");
112*04fd306cSNickeau                }
113*04fd306cSNickeau            }
114*04fd306cSNickeau        }
115*04fd306cSNickeau
116*04fd306cSNickeau        $id = $idManager->generateNewHtmlIdForComponent(PanelTag::PANEL_LOGICAL_MARKUP);
117*04fd306cSNickeau        return array(
118*04fd306cSNickeau            PluginUtility::CONTEXT => $context,
119*04fd306cSNickeau            TagAttributes::ID_KEY => $id
120*04fd306cSNickeau        );
121*04fd306cSNickeau
122*04fd306cSNickeau    }
123*04fd306cSNickeau
124*04fd306cSNickeau    public static function handleExit(Doku_Handler $handler, int $pos, string $markupTag, string $match): array
125*04fd306cSNickeau    {
126*04fd306cSNickeau
127*04fd306cSNickeau        $callStack = CallStack::createFromHandler($handler);
128*04fd306cSNickeau        $openingTag = $callStack->moveToPreviousCorrespondingOpeningCall();
129*04fd306cSNickeau        if ($openingTag === false) {
130*04fd306cSNickeau            LogUtility::error("An exit panel tag does not have any opening tag and was discarded");
131*04fd306cSNickeau            return [PluginUtility::CONTEXT => "root"];
132*04fd306cSNickeau        }
133*04fd306cSNickeau
134*04fd306cSNickeau        /**
135*04fd306cSNickeau         * Label is Mandatory in the new syntax. We check it
136*04fd306cSNickeau         * (Only the presence of at minimum 1 and not the presence in each panel)
137*04fd306cSNickeau         */
138*04fd306cSNickeau        if ($markupTag !== PanelTag::TAB_PANEL_MARKUP) {
139*04fd306cSNickeau            $labelCall = null;
140*04fd306cSNickeau            while ($actualCall = $callStack->next()) {
141*04fd306cSNickeau                if ($actualCall->getTagName() === syntax_plugin_combo_label::TAG) {
142*04fd306cSNickeau                    $labelCall = $actualCall;
143*04fd306cSNickeau                    break;
144*04fd306cSNickeau                }
145*04fd306cSNickeau            }
146*04fd306cSNickeau            if ($labelCall === null) {
147*04fd306cSNickeau                LogUtility::error("No label was found in the panel (number " . $openingTag->getIdOrDefault() . "). They are mandatory to create tabs or accordion", PanelTag::PANEL_LOGICAL_MARKUP);
148*04fd306cSNickeau            }
149*04fd306cSNickeau        }
150*04fd306cSNickeau
151*04fd306cSNickeau
152*04fd306cSNickeau        /**
153*04fd306cSNickeau         * End section
154*04fd306cSNickeau         */
155*04fd306cSNickeau        $sectionEditing = ExecutionContext::getActualOrCreateFromEnv()
156*04fd306cSNickeau            ->getConfig()
157*04fd306cSNickeau            ->getValue(PanelTag::CONF_ENABLE_SECTION_EDITING, 1);
158*04fd306cSNickeau        if ($sectionEditing) {
159*04fd306cSNickeau            /**
160*04fd306cSNickeau             * Section
161*04fd306cSNickeau             * +1 to go at the line
162*04fd306cSNickeau             */
163*04fd306cSNickeau            $startPosition = $openingTag->getPluginData(PluginUtility::POSITION);
164*04fd306cSNickeau            $id = $openingTag->getAttribute(TagAttributes::ID_KEY);
165*04fd306cSNickeau            $endPosition = $pos + strlen($match) + 1;
166*04fd306cSNickeau            $editButtonCall = EditButton::create("Edit panel $id")
167*04fd306cSNickeau                ->setStartPosition($startPosition)
168*04fd306cSNickeau                ->setEndPosition($endPosition)
169*04fd306cSNickeau                ->toComboCallComboFormat();
170*04fd306cSNickeau            $callStack->moveToEnd();
171*04fd306cSNickeau            $callStack->insertBefore($editButtonCall);
172*04fd306cSNickeau        }
173*04fd306cSNickeau
174*04fd306cSNickeau        /**
175*04fd306cSNickeau         * Add p
176*04fd306cSNickeau         */
177*04fd306cSNickeau        $callStack->moveToEnd();
178*04fd306cSNickeau        $callStack->moveToPreviousCorrespondingOpeningCall();
179*04fd306cSNickeau        $callStack->processEolToEndStack();
180*04fd306cSNickeau        return array(PluginUtility::CONTEXT => $openingTag->getContext());
181*04fd306cSNickeau    }
182*04fd306cSNickeau
183*04fd306cSNickeau    public static function renderEnterXhtml(TagAttributes $tagAttributes, array $data): string
184*04fd306cSNickeau    {
185*04fd306cSNickeau        /**
186*04fd306cSNickeau         * Section (Edit button)
187*04fd306cSNickeau         */
188*04fd306cSNickeau        if (SiteConfig::getConfValue(PanelTag::CONF_ENABLE_SECTION_EDITING, 1)) {
189*04fd306cSNickeau            $position = $data[PluginUtility::POSITION];
190*04fd306cSNickeau            $name = IdManager::getOrCreate()->generateNewHtmlIdForComponent(PanelTag::PANEL_LOGICAL_MARKUP);
191*04fd306cSNickeau            EditButtonManager::getOrCreate()->createAndAddEditButtonToStack($name, $position);
192*04fd306cSNickeau        }
193*04fd306cSNickeau
194*04fd306cSNickeau        $context = $data[PluginUtility::CONTEXT];
195*04fd306cSNickeau        switch ($context) {
196*04fd306cSNickeau            case syntax_plugin_combo_accordion::TAG:
197*04fd306cSNickeau                // A panel in a accordion
198*04fd306cSNickeau                return "<div class=\"card\">";
199*04fd306cSNickeau            case PanelTag::TAB_PANEL_MARKUP: // Old deprecated syntax
200*04fd306cSNickeau            case TabsTag::TAG: // new syntax
201*04fd306cSNickeau
202*04fd306cSNickeau
203*04fd306cSNickeau                try {
204*04fd306cSNickeau                    $ariaLabelledValue = $tagAttributes->getId() . "-tab";
205*04fd306cSNickeau                } catch (ExceptionNotFound $e) {
206*04fd306cSNickeau                    LogUtility::error("No id was found for a panel in the tabs");
207*04fd306cSNickeau                    $ariaLabelledValue = "unknwon-id-tab";
208*04fd306cSNickeau                }
209*04fd306cSNickeau                $tagAttributes
210*04fd306cSNickeau                    ->addClassName("tab-pane fade")
211*04fd306cSNickeau                    ->addOutputAttributeValue("role", "tabpanel")
212*04fd306cSNickeau                    ->addOutputAttributeValue("aria-labelledby", $ariaLabelledValue);
213*04fd306cSNickeau                $selected = PanelTag::getSelectedValue($tagAttributes);
214*04fd306cSNickeau                if ($selected) {
215*04fd306cSNickeau                    $tagAttributes->addClassName("show active");
216*04fd306cSNickeau                }
217*04fd306cSNickeau                return $tagAttributes->toHtmlEnterTag("div");
218*04fd306cSNickeau
219*04fd306cSNickeau            case PanelTag::CONTEXT_PREVIEW_ALONE:
220*04fd306cSNickeau                $aloneAttributes = TagAttributes::createFromCallStackArray(PanelTag::CONTEXT_PREVIEW_ALONE_ATTRIBUTES);
221*04fd306cSNickeau                return TabsTag::openTabPanelsElement($aloneAttributes);
222*04fd306cSNickeau            default:
223*04fd306cSNickeau                LogUtility::log2FrontEnd("The context ($context) is unknown in enter rendering", LogUtility::LVL_MSG_ERROR, PanelTag::PANEL_LOGICAL_MARKUP);
224*04fd306cSNickeau                return "";
225*04fd306cSNickeau        }
226*04fd306cSNickeau    }
227*04fd306cSNickeau
228*04fd306cSNickeau    public static function renderExitXhtml(array $data): string
229*04fd306cSNickeau    {
230*04fd306cSNickeau
231*04fd306cSNickeau        $xhtml = "";
232*04fd306cSNickeau        $context = $data[PluginUtility::CONTEXT];
233*04fd306cSNickeau        switch ($context) {
234*04fd306cSNickeau            case syntax_plugin_combo_accordion::TAG:
235*04fd306cSNickeau                $xhtml .= '</div></div>';
236*04fd306cSNickeau                break;
237*04fd306cSNickeau            case PanelTag::CONTEXT_PREVIEW_ALONE:
238*04fd306cSNickeau                $aloneVariable = TagAttributes::createFromCallStackArray(PanelTag::CONTEXT_PREVIEW_ALONE_ATTRIBUTES);
239*04fd306cSNickeau                $xhtml .= TabsTag::closeTabPanelsElement($aloneVariable);
240*04fd306cSNickeau                break;
241*04fd306cSNickeau        }
242*04fd306cSNickeau
243*04fd306cSNickeau        /**
244*04fd306cSNickeau         * End panel
245*04fd306cSNickeau         */
246*04fd306cSNickeau        $xhtml .= "</div>";
247*04fd306cSNickeau        return $xhtml;
248*04fd306cSNickeau    }
249*04fd306cSNickeau}
250*04fd306cSNickeau
251