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