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; 923723136Sgerardnicouse ComboStrap\MediaLink; 105f891b7eSNickeauuse ComboStrap\LogUtility; 115f891b7eSNickeauuse ComboStrap\PluginUtility; 125f891b7eSNickeauuse ComboStrap\Tag; 1321913ab3SNickeauuse ComboStrap\TagAttributes; 1421913ab3SNickeau 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 { 5721913ab3SNickeau 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 74*9337a630SNickeau $this->Lexer->addEntryPattern(PluginUtility::getContainerTagPattern(self::TAG), $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 755f891b7eSNickeau } 765f891b7eSNickeau 775f891b7eSNickeau public function postConnect() 785f891b7eSNickeau { 79*9337a630SNickeau $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeFromTag($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 } 11921913ab3SNickeau } else { 12021913ab3SNickeau /** 12121913ab3SNickeau * An panel may render alone in preview 12221913ab3SNickeau */ 12321913ab3SNickeau if ($parentTag->getContext() == syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE) { 12421913ab3SNickeau $context = syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE; 12521913ab3SNickeau } 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 : 13921913ab3SNickeau $callStack = CallStack::createFromHandler($handler); 14021913ab3SNickeau $openingTag = $callStack->moveToPreviousCorrespondingOpeningCall(); 1415f891b7eSNickeau $context = $openingTag->getContext(); 14221913ab3SNickeau 14321913ab3SNickeau /** 14421913ab3SNickeau * An image in a label should have no link (ie no anchor) 14521913ab3SNickeau * because a anchor is used for navigation 14621913ab3SNickeau */ 147531e725cSNickeau $callStack->processNoLinkOnImageToEndStack(); 14821913ab3SNickeau 14921913ab3SNickeau $callStack->closeAndResetPointer(); 15021913ab3SNickeau 151531e725cSNickeau 1525f891b7eSNickeau return array( 1535f891b7eSNickeau PluginUtility::STATE => $state, 1545f891b7eSNickeau PluginUtility::CONTEXT => $context, 1555f891b7eSNickeau PluginUtility::ATTRIBUTES => $openingTag->getAttributes() 1565f891b7eSNickeau ); 1575f891b7eSNickeau 1585f891b7eSNickeau 1595f891b7eSNickeau } 1605f891b7eSNickeau return array(); 1615f891b7eSNickeau 1625f891b7eSNickeau } 1635f891b7eSNickeau 1645f891b7eSNickeau /** 1655f891b7eSNickeau * Render the output 1665f891b7eSNickeau * @param string $format 1675f891b7eSNickeau * @param Doku_Renderer $renderer 1685f891b7eSNickeau * @param array $data - what the function handle() return'ed 1695f891b7eSNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 1705f891b7eSNickeau * @see DokuWiki_Syntax_Plugin::render() 1715f891b7eSNickeau * 1725f891b7eSNickeau * 1735f891b7eSNickeau */ 1745f891b7eSNickeau function render($format, Doku_Renderer $renderer, $data) 1755f891b7eSNickeau { 1765f891b7eSNickeau 1775f891b7eSNickeau if ($format == 'xhtml') { 1785f891b7eSNickeau 1795f891b7eSNickeau /** @var Doku_Renderer_xhtml $renderer */ 1805f891b7eSNickeau $state = $data[PluginUtility::STATE]; 1815f891b7eSNickeau switch ($state) { 1825f891b7eSNickeau 1835f891b7eSNickeau case DOKU_LEXER_ENTER: 1845f891b7eSNickeau 1855f891b7eSNickeau $context = $data[PluginUtility::CONTEXT]; 1865f891b7eSNickeau switch ($context) { 1875f891b7eSNickeau case syntax_plugin_combo_accordion::TAG: 1885f891b7eSNickeau $attribute = $data[PluginUtility::ATTRIBUTES]; 1895f891b7eSNickeau $headingId = $attribute[self::HEADING_ID]; 1905f891b7eSNickeau $collapseId = $attribute[self::TARGET_ID]; 1915f891b7eSNickeau $collapsed = $attribute[self::COLLAPSED]; 1925f891b7eSNickeau if ($collapsed == "false") { 1935f891b7eSNickeau $collapsedClass = "collapsed"; 1945f891b7eSNickeau } else { 1955f891b7eSNickeau $collapsedClass = ""; 1965f891b7eSNickeau } 1975f891b7eSNickeau $renderer->doc .= "<div class=\"card-header\" id=\"$headingId\">" . DOKU_LF; 1985f891b7eSNickeau $renderer->doc .= "<h2 class=\"mb-0\">"; 19921913ab3SNickeau $dataNamespace = Bootstrap::getDataNamespace(); 20021913ab3SNickeau $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\">"; 2015f891b7eSNickeau break; 2025f891b7eSNickeau case syntax_plugin_combo_tabs::TAG: 2035f891b7eSNickeau $attributes = $data[PluginUtility::ATTRIBUTES]; 2045f891b7eSNickeau $renderer->doc .= syntax_plugin_combo_tabs::openNavigationalTabElement($attributes); 2055f891b7eSNickeau break; 20621913ab3SNickeau case syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE: 20721913ab3SNickeau $attributes = syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE_ATTRIBUTES; 20821913ab3SNickeau $renderer->doc .= "<ul style=\"list-style-type: none;padding-inline-start: 0;\">"; 20921913ab3SNickeau $renderer->doc .= syntax_plugin_combo_tabs::openNavigationalTabElement($attributes); 21021913ab3SNickeau break; 2115f891b7eSNickeau default: 21221913ab3SNickeau LogUtility::log2FrontEnd("The context ($context) of the label is unknown in enter", LogUtility::LVL_MSG_WARNING, self::TAG); 21321913ab3SNickeau 2145f891b7eSNickeau } 2155f891b7eSNickeau break; 2165f891b7eSNickeau 2175f891b7eSNickeau case DOKU_LEXER_UNMATCHED : 21832b85071SNickeau $renderer->doc .= PluginUtility::renderUnmatched($data); 2195f891b7eSNickeau break; 2205f891b7eSNickeau 2215f891b7eSNickeau case DOKU_LEXER_EXIT: 2225f891b7eSNickeau $context = $data[PluginUtility::CONTEXT]; 2235f891b7eSNickeau switch ($context) { 2245f891b7eSNickeau case syntax_plugin_combo_accordion::TAG: 2255f891b7eSNickeau $attribute = $data[PluginUtility::ATTRIBUTES]; 2265f891b7eSNickeau $collapseId = $attribute[self::TARGET_ID]; 2275f891b7eSNickeau $headingId = $attribute[self::HEADING_ID]; 2285f891b7eSNickeau $collapsed = $attribute[self::COLLAPSED]; 2295f891b7eSNickeau if ($collapsed == "false") { 2305f891b7eSNickeau $showClass = "show"; 2315f891b7eSNickeau } else { 2325f891b7eSNickeau $showClass = ""; 2335f891b7eSNickeau } 2345f891b7eSNickeau $renderer->doc .= "</button></h2></div>"; 23521913ab3SNickeau $dataNamespace = Bootstrap::getDataNamespace(); 23621913ab3SNickeau $renderer->doc .= "<div id=\"$collapseId\" class=\"collapse $showClass\" aria-labelledby=\"$headingId\" data-{$dataNamespace}parent=\"#$headingId\">"; 2375f891b7eSNickeau $renderer->doc .= "<div class=\"card-body\">" . DOKU_LF; 2385f891b7eSNickeau break; 2395f891b7eSNickeau case syntax_plugin_combo_tabs::TAG: 2405f891b7eSNickeau $renderer->doc .= syntax_plugin_combo_tabs::closeNavigationalTabElement(); 2415f891b7eSNickeau break; 24221913ab3SNickeau case syntax_plugin_combo_panel::CONTEXT_PREVIEW_ALONE: 24321913ab3SNickeau $renderer->doc .= syntax_plugin_combo_tabs::closeNavigationalTabElement(); 24421913ab3SNickeau $renderer->doc .= "</ul>"; 24521913ab3SNickeau break; 2465f891b7eSNickeau default: 2475f891b7eSNickeau LogUtility::log2FrontEnd("The context ($context) of the label is unknown in exit", LogUtility::LVL_MSG_WARNING, self::TAG); 2485f891b7eSNickeau 24921913ab3SNickeau 2505f891b7eSNickeau } 2515f891b7eSNickeau break; 2525f891b7eSNickeau 2535f891b7eSNickeau 2545f891b7eSNickeau } 2555f891b7eSNickeau } 2565f891b7eSNickeau // unsupported $mode 2575f891b7eSNickeau return false; 2585f891b7eSNickeau } 2595f891b7eSNickeau 2605f891b7eSNickeau 2615f891b7eSNickeau} 2625f891b7eSNickeau 263