1*5f891b7eSNickeau<?php 2*5f891b7eSNickeau 3*5f891b7eSNickeau// implementation of 4*5f891b7eSNickeau// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite 5*5f891b7eSNickeau 6*5f891b7eSNickeau// must be run within Dokuwiki 7*5f891b7eSNickeauuse ComboStrap\HeaderUtility; 8*5f891b7eSNickeauuse ComboStrap\LogUtility; 9*5f891b7eSNickeauuse ComboStrap\TitleUtility; 10*5f891b7eSNickeauuse ComboStrap\PluginUtility; 11*5f891b7eSNickeauuse ComboStrap\StringUtility; 12*5f891b7eSNickeauuse ComboStrap\Tag; 13*5f891b7eSNickeau 14*5f891b7eSNickeaurequire_once(__DIR__ . '/../class/HeaderUtility.php'); 15*5f891b7eSNickeau 16*5f891b7eSNickeauif (!defined('DOKU_INC')) die(); 17*5f891b7eSNickeau 18*5f891b7eSNickeau 19*5f891b7eSNickeauclass syntax_plugin_combo_label extends DokuWiki_Syntax_Plugin 20*5f891b7eSNickeau{ 21*5f891b7eSNickeau 22*5f891b7eSNickeau 23*5f891b7eSNickeau const TAG = "label"; 24*5f891b7eSNickeau 25*5f891b7eSNickeau /** 26*5f891b7eSNickeau * The id of the heading element for a accordion label 27*5f891b7eSNickeau */ 28*5f891b7eSNickeau const HEADING_ID = "headingId"; 29*5f891b7eSNickeau /** 30*5f891b7eSNickeau * The id of the collapsable target 31*5f891b7eSNickeau */ 32*5f891b7eSNickeau const TARGET_ID = "targetId"; 33*5f891b7eSNickeau 34*5f891b7eSNickeau /** 35*5f891b7eSNickeau * An indicator attribute that tells if the accordion is collpased or not 36*5f891b7eSNickeau */ 37*5f891b7eSNickeau const COLLAPSED = "collapsed"; 38*5f891b7eSNickeau 39*5f891b7eSNickeau function getType() 40*5f891b7eSNickeau { 41*5f891b7eSNickeau return 'formatting'; 42*5f891b7eSNickeau } 43*5f891b7eSNickeau 44*5f891b7eSNickeau /** 45*5f891b7eSNickeau * How Dokuwiki will add P element 46*5f891b7eSNickeau * 47*5f891b7eSNickeau * * 'normal' - The plugin can be used inside paragraphs (inline) 48*5f891b7eSNickeau * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 49*5f891b7eSNickeau * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 50*5f891b7eSNickeau * 51*5f891b7eSNickeau * @see DokuWiki_Syntax_Plugin::getPType() 52*5f891b7eSNickeau */ 53*5f891b7eSNickeau function getPType() 54*5f891b7eSNickeau { 55*5f891b7eSNickeau return 'normal'; 56*5f891b7eSNickeau } 57*5f891b7eSNickeau 58*5f891b7eSNickeau function getAllowedTypes() 59*5f891b7eSNickeau { 60*5f891b7eSNickeau return array('substition', 'formatting', 'disabled'); 61*5f891b7eSNickeau } 62*5f891b7eSNickeau 63*5f891b7eSNickeau function getSort() 64*5f891b7eSNickeau { 65*5f891b7eSNickeau return 201; 66*5f891b7eSNickeau } 67*5f891b7eSNickeau 68*5f891b7eSNickeau 69*5f891b7eSNickeau function connectTo($mode) 70*5f891b7eSNickeau { 71*5f891b7eSNickeau 72*5f891b7eSNickeau $this->Lexer->addEntryPattern(PluginUtility::getContainerTagPattern(self::TAG), $mode, PluginUtility::getModeForComponent($this->getPluginComponent())); 73*5f891b7eSNickeau } 74*5f891b7eSNickeau 75*5f891b7eSNickeau public function postConnect() 76*5f891b7eSNickeau { 77*5f891b7eSNickeau $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeForComponent($this->getPluginComponent())); 78*5f891b7eSNickeau } 79*5f891b7eSNickeau 80*5f891b7eSNickeau function handle($match, $state, $pos, Doku_Handler $handler) 81*5f891b7eSNickeau { 82*5f891b7eSNickeau 83*5f891b7eSNickeau switch ($state) { 84*5f891b7eSNickeau 85*5f891b7eSNickeau case DOKU_LEXER_ENTER: 86*5f891b7eSNickeau $tagAttributes = PluginUtility::getTagAttributes($match); 87*5f891b7eSNickeau 88*5f891b7eSNickeau $tag = new Tag(self::TAG, $tagAttributes, $state, $handler); 89*5f891b7eSNickeau $parentTag = $tag->getParent(); 90*5f891b7eSNickeau $context = null; 91*5f891b7eSNickeau if ($parentTag != null) { 92*5f891b7eSNickeau $grandfather = $parentTag->getParent(); 93*5f891b7eSNickeau if ($grandfather != null) { 94*5f891b7eSNickeau $grandFatherName = $grandfather->getName(); 95*5f891b7eSNickeau switch ($grandFatherName) { 96*5f891b7eSNickeau case syntax_plugin_combo_accordion::TAG: 97*5f891b7eSNickeau $id = $parentTag->getAttribute("id"); 98*5f891b7eSNickeau $tagAttributes["id"] = $id; 99*5f891b7eSNickeau $tagAttributes[self::HEADING_ID] = "heading" . ucfirst($id); 100*5f891b7eSNickeau $tagAttributes[self::TARGET_ID] = "collapse" . ucfirst($id); 101*5f891b7eSNickeau $parentAttribute = $parentTag->getAttributes(); 102*5f891b7eSNickeau if (!key_exists(self::COLLAPSED, $parentAttribute)) { 103*5f891b7eSNickeau // Accordion are collapsed by default 104*5f891b7eSNickeau $tagAttributes[self::COLLAPSED] = "true"; 105*5f891b7eSNickeau } else { 106*5f891b7eSNickeau $tagAttributes[self::COLLAPSED] = $parentAttribute[self::COLLAPSED]; 107*5f891b7eSNickeau } 108*5f891b7eSNickeau $context = syntax_plugin_combo_accordion::TAG; 109*5f891b7eSNickeau break; 110*5f891b7eSNickeau case syntax_plugin_combo_tabs::TAG: 111*5f891b7eSNickeau $context = syntax_plugin_combo_tabs::TAG; 112*5f891b7eSNickeau $tagAttributes = $parentTag->getAttributes(); 113*5f891b7eSNickeau break; 114*5f891b7eSNickeau default: 115*5f891b7eSNickeau LogUtility::log2FrontEnd("The label is included in the $grandFatherName component and this is unexpected", LogUtility::LVL_MSG_WARNING, self::TAG); 116*5f891b7eSNickeau } 117*5f891b7eSNickeau } 118*5f891b7eSNickeau } 119*5f891b7eSNickeau 120*5f891b7eSNickeau return array( 121*5f891b7eSNickeau PluginUtility::STATE => $state, 122*5f891b7eSNickeau PluginUtility::ATTRIBUTES => $tagAttributes, 123*5f891b7eSNickeau PluginUtility::CONTEXT => $context 124*5f891b7eSNickeau ); 125*5f891b7eSNickeau 126*5f891b7eSNickeau case DOKU_LEXER_UNMATCHED : 127*5f891b7eSNickeau return array( 128*5f891b7eSNickeau PluginUtility::STATE => $state, 129*5f891b7eSNickeau PluginUtility::PAYLOAD => $match 130*5f891b7eSNickeau ); 131*5f891b7eSNickeau 132*5f891b7eSNickeau case DOKU_LEXER_EXIT : 133*5f891b7eSNickeau $tag = new Tag(self::TAG, array(), $state, $handler); 134*5f891b7eSNickeau $openingTag = $tag->getOpeningTag(); 135*5f891b7eSNickeau $context = $openingTag->getContext(); 136*5f891b7eSNickeau return array( 137*5f891b7eSNickeau PluginUtility::STATE => $state, 138*5f891b7eSNickeau PluginUtility::CONTEXT => $context, 139*5f891b7eSNickeau PluginUtility::ATTRIBUTES => $openingTag->getAttributes() 140*5f891b7eSNickeau ); 141*5f891b7eSNickeau 142*5f891b7eSNickeau 143*5f891b7eSNickeau } 144*5f891b7eSNickeau return array(); 145*5f891b7eSNickeau 146*5f891b7eSNickeau } 147*5f891b7eSNickeau 148*5f891b7eSNickeau /** 149*5f891b7eSNickeau * Render the output 150*5f891b7eSNickeau * @param string $format 151*5f891b7eSNickeau * @param Doku_Renderer $renderer 152*5f891b7eSNickeau * @param array $data - what the function handle() return'ed 153*5f891b7eSNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 154*5f891b7eSNickeau * @see DokuWiki_Syntax_Plugin::render() 155*5f891b7eSNickeau * 156*5f891b7eSNickeau * 157*5f891b7eSNickeau */ 158*5f891b7eSNickeau function render($format, Doku_Renderer $renderer, $data) 159*5f891b7eSNickeau { 160*5f891b7eSNickeau 161*5f891b7eSNickeau if ($format == 'xhtml') { 162*5f891b7eSNickeau 163*5f891b7eSNickeau /** @var Doku_Renderer_xhtml $renderer */ 164*5f891b7eSNickeau $state = $data[PluginUtility::STATE]; 165*5f891b7eSNickeau switch ($state) { 166*5f891b7eSNickeau 167*5f891b7eSNickeau case DOKU_LEXER_ENTER: 168*5f891b7eSNickeau 169*5f891b7eSNickeau $context = $data[PluginUtility::CONTEXT]; 170*5f891b7eSNickeau switch ($context) { 171*5f891b7eSNickeau case syntax_plugin_combo_accordion::TAG: 172*5f891b7eSNickeau $attribute = $data[PluginUtility::ATTRIBUTES]; 173*5f891b7eSNickeau $headingId = $attribute[self::HEADING_ID]; 174*5f891b7eSNickeau $collapseId = $attribute[self::TARGET_ID]; 175*5f891b7eSNickeau $collapsed = $attribute[self::COLLAPSED]; 176*5f891b7eSNickeau if ($collapsed == "false") { 177*5f891b7eSNickeau $collapsedClass = "collapsed"; 178*5f891b7eSNickeau } else { 179*5f891b7eSNickeau $collapsedClass = ""; 180*5f891b7eSNickeau } 181*5f891b7eSNickeau $renderer->doc .= "<div class=\"card-header\" id=\"$headingId\">" . DOKU_LF; 182*5f891b7eSNickeau $renderer->doc .= "<h2 class=\"mb-0\">"; 183*5f891b7eSNickeau $renderer->doc .= "<button class=\"btn btn-link btn-block text-left $collapsedClass\" type=\"button\" data-toggle=\"collapse\" data-target=\"#$collapseId\" aria-expanded=\"true\" aria-controls=\"$collapseId\">"; 184*5f891b7eSNickeau break; 185*5f891b7eSNickeau case syntax_plugin_combo_tabs::TAG: 186*5f891b7eSNickeau $attributes = $data[PluginUtility::ATTRIBUTES]; 187*5f891b7eSNickeau $renderer->doc .= syntax_plugin_combo_tabs::openNavigationalTabElement($attributes); 188*5f891b7eSNickeau break; 189*5f891b7eSNickeau default: 190*5f891b7eSNickeau LogUtility::log2FrontEnd("The context ($context) of the label is unknown in exit", LogUtility::LVL_MSG_WARNING, self::TAG); 191*5f891b7eSNickeau } 192*5f891b7eSNickeau break; 193*5f891b7eSNickeau 194*5f891b7eSNickeau case DOKU_LEXER_UNMATCHED : 195*5f891b7eSNickeau $renderer->doc .= PluginUtility::escape($data[PluginUtility::PAYLOAD]); 196*5f891b7eSNickeau break; 197*5f891b7eSNickeau 198*5f891b7eSNickeau case DOKU_LEXER_EXIT: 199*5f891b7eSNickeau $context = $data[PluginUtility::CONTEXT]; 200*5f891b7eSNickeau switch ($context) { 201*5f891b7eSNickeau case syntax_plugin_combo_accordion::TAG: 202*5f891b7eSNickeau $attribute = $data[PluginUtility::ATTRIBUTES]; 203*5f891b7eSNickeau $collapseId = $attribute[self::TARGET_ID]; 204*5f891b7eSNickeau $headingId = $attribute[self::HEADING_ID]; 205*5f891b7eSNickeau $collapsed = $attribute[self::COLLAPSED]; 206*5f891b7eSNickeau if ($collapsed == "false") { 207*5f891b7eSNickeau $showClass = "show"; 208*5f891b7eSNickeau } else { 209*5f891b7eSNickeau $showClass = ""; 210*5f891b7eSNickeau } 211*5f891b7eSNickeau $renderer->doc .= "</button></h2></div>"; 212*5f891b7eSNickeau $renderer->doc .= "<div id=\"$collapseId\" class=\"collapse $showClass\" aria-labelledby=\"$headingId\" data-parent=\"#$headingId\">"; 213*5f891b7eSNickeau $renderer->doc .= "<div class=\"card-body\">" . DOKU_LF; 214*5f891b7eSNickeau break; 215*5f891b7eSNickeau case syntax_plugin_combo_tabs::TAG: 216*5f891b7eSNickeau $renderer->doc .= syntax_plugin_combo_tabs::closeNavigationalTabElement(); 217*5f891b7eSNickeau break; 218*5f891b7eSNickeau default: 219*5f891b7eSNickeau LogUtility::log2FrontEnd("The context ($context) of the label is unknown in exit", LogUtility::LVL_MSG_WARNING, self::TAG); 220*5f891b7eSNickeau 221*5f891b7eSNickeau } 222*5f891b7eSNickeau break; 223*5f891b7eSNickeau 224*5f891b7eSNickeau 225*5f891b7eSNickeau } 226*5f891b7eSNickeau } 227*5f891b7eSNickeau // unsupported $mode 228*5f891b7eSNickeau return false; 229*5f891b7eSNickeau } 230*5f891b7eSNickeau 231*5f891b7eSNickeau 232*5f891b7eSNickeau} 233*5f891b7eSNickeau 234