1*04fd306cSNickeau<?php 2*04fd306cSNickeau 3*04fd306cSNickeau 4*04fd306cSNickeauuse ComboStrap\Bootstrap; 5*04fd306cSNickeauuse ComboStrap\BrandButton; 6*04fd306cSNickeauuse ComboStrap\ButtonTag; 7*04fd306cSNickeauuse ComboStrap\CallStack; 8*04fd306cSNickeauuse ComboStrap\LogUtility; 9*04fd306cSNickeauuse ComboStrap\PluginUtility; 10*04fd306cSNickeauuse ComboStrap\TagAttributes; 11*04fd306cSNickeauuse ComboStrap\TagAttribute\Toggle; 12*04fd306cSNickeauuse ComboStrap\XmlTagProcessing; 13*04fd306cSNickeau 14*04fd306cSNickeau 15*04fd306cSNickeauclass syntax_plugin_combo_toggle extends DokuWiki_Syntax_Plugin 16*04fd306cSNickeau{ 17*04fd306cSNickeau 18*04fd306cSNickeau const TAG = "toggle"; 19*04fd306cSNickeau const CANONICAL = self::TAG; 20*04fd306cSNickeau const WIDGET_ATTRIBUTE = "widget"; 21*04fd306cSNickeau 22*04fd306cSNickeau 23*04fd306cSNickeau /** 24*04fd306cSNickeau * Syntax Type. 25*04fd306cSNickeau * 26*04fd306cSNickeau * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 27*04fd306cSNickeau * @see DokuWiki_Syntax_Plugin::getType() 28*04fd306cSNickeau */ 29*04fd306cSNickeau function getType(): string 30*04fd306cSNickeau { 31*04fd306cSNickeau return 'substition'; 32*04fd306cSNickeau } 33*04fd306cSNickeau 34*04fd306cSNickeau /** 35*04fd306cSNickeau * How Dokuwiki will add P element 36*04fd306cSNickeau * 37*04fd306cSNickeau * * 'normal' - The plugin can be used inside paragraphs 38*04fd306cSNickeau * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 39*04fd306cSNickeau * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 40*04fd306cSNickeau * 41*04fd306cSNickeau * @see DokuWiki_Syntax_Plugin::getPType() 42*04fd306cSNickeau */ 43*04fd306cSNickeau function getPType(): string 44*04fd306cSNickeau { 45*04fd306cSNickeau // button or link 46*04fd306cSNickeau return 'normal'; 47*04fd306cSNickeau } 48*04fd306cSNickeau 49*04fd306cSNickeau /** 50*04fd306cSNickeau * @return array 51*04fd306cSNickeau * Allow which kind of plugin inside 52*04fd306cSNickeau * 53*04fd306cSNickeau * array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 54*04fd306cSNickeau * 55*04fd306cSNickeau */ 56*04fd306cSNickeau function getAllowedTypes(): array 57*04fd306cSNickeau { 58*04fd306cSNickeau return array('baseonly', 'formatting', 'substition', 'protected', 'disabled'); 59*04fd306cSNickeau } 60*04fd306cSNickeau 61*04fd306cSNickeau function getSort(): int 62*04fd306cSNickeau { 63*04fd306cSNickeau return 201; 64*04fd306cSNickeau } 65*04fd306cSNickeau 66*04fd306cSNickeau public 67*04fd306cSNickeau function accepts($mode): bool 68*04fd306cSNickeau { 69*04fd306cSNickeau return syntax_plugin_combo_preformatted::disablePreformatted($mode) 70*04fd306cSNickeau && Toggle::disableEntity($mode); 71*04fd306cSNickeau } 72*04fd306cSNickeau 73*04fd306cSNickeau 74*04fd306cSNickeau /** 75*04fd306cSNickeau * Create a pattern that will called this plugin 76*04fd306cSNickeau * 77*04fd306cSNickeau * @param string $mode 78*04fd306cSNickeau * @see Doku_Parser_Mode::connectTo() 79*04fd306cSNickeau */ 80*04fd306cSNickeau function connectTo($mode) 81*04fd306cSNickeau { 82*04fd306cSNickeau 83*04fd306cSNickeau $pattern = XmlTagProcessing::getContainerTagPattern(self::getTag()); 84*04fd306cSNickeau $this->Lexer->addEntryPattern($pattern, $mode, 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent()); 85*04fd306cSNickeau 86*04fd306cSNickeau 87*04fd306cSNickeau } 88*04fd306cSNickeau 89*04fd306cSNickeau function postConnect() 90*04fd306cSNickeau { 91*04fd306cSNickeau 92*04fd306cSNickeau $this->Lexer->addExitPattern('</' . self::getTag() . '>', 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent()); 93*04fd306cSNickeau 94*04fd306cSNickeau } 95*04fd306cSNickeau 96*04fd306cSNickeau function handle($match, $state, $pos, Doku_Handler $handler) 97*04fd306cSNickeau { 98*04fd306cSNickeau 99*04fd306cSNickeau 100*04fd306cSNickeau switch ($state) { 101*04fd306cSNickeau 102*04fd306cSNickeau case DOKU_LEXER_ENTER : 103*04fd306cSNickeau 104*04fd306cSNickeau /** 105*04fd306cSNickeau * Default parameters, type definition and parsing 106*04fd306cSNickeau */ 107*04fd306cSNickeau $defaultParameters[self::WIDGET_ATTRIBUTE] = BrandButton::WIDGET_BUTTON_VALUE; 108*04fd306cSNickeau $knownTypes = ButtonTag::TYPES; 109*04fd306cSNickeau $tagAttributes = TagAttributes::createFromTagMatch($match, $defaultParameters, $knownTypes) 110*04fd306cSNickeau ->setLogicalTag(self::TAG); 111*04fd306cSNickeau 112*04fd306cSNickeau return array( 113*04fd306cSNickeau PluginUtility::STATE => $state, 114*04fd306cSNickeau PluginUtility::ATTRIBUTES => $tagAttributes->toCallStackArray() 115*04fd306cSNickeau ); 116*04fd306cSNickeau 117*04fd306cSNickeau case DOKU_LEXER_UNMATCHED : 118*04fd306cSNickeau return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 119*04fd306cSNickeau 120*04fd306cSNickeau case DOKU_LEXER_EXIT : 121*04fd306cSNickeau 122*04fd306cSNickeau return array( 123*04fd306cSNickeau PluginUtility::STATE => $state 124*04fd306cSNickeau ); 125*04fd306cSNickeau 126*04fd306cSNickeau 127*04fd306cSNickeau } 128*04fd306cSNickeau return array(); 129*04fd306cSNickeau 130*04fd306cSNickeau } 131*04fd306cSNickeau 132*04fd306cSNickeau /** 133*04fd306cSNickeau * Render the output 134*04fd306cSNickeau * @param string $format 135*04fd306cSNickeau * @param Doku_Renderer $renderer 136*04fd306cSNickeau * @param array $data - what the function handle() return 137*04fd306cSNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 138*04fd306cSNickeau * @see DokuWiki_Syntax_Plugin::render() 139*04fd306cSNickeau * 140*04fd306cSNickeau * 141*04fd306cSNickeau */ 142*04fd306cSNickeau function render($format, Doku_Renderer $renderer, $data): bool 143*04fd306cSNickeau { 144*04fd306cSNickeau 145*04fd306cSNickeau if ($format === "xhtml") { 146*04fd306cSNickeau $state = $data[PluginUtility::STATE]; 147*04fd306cSNickeau switch ($state) { 148*04fd306cSNickeau case DOKU_LEXER_ENTER: 149*04fd306cSNickeau 150*04fd306cSNickeau $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]) 151*04fd306cSNickeau ->setLogicalTag(self::CANONICAL); 152*04fd306cSNickeau 153*04fd306cSNickeau $targetId = $tagAttributes->getValueAndRemoveIfPresent("target-id"); 154*04fd306cSNickeau if ($targetId === null) { 155*04fd306cSNickeau $renderer->doc .= LogUtility::wrapInRedForHtml("The target id is mandatory"); 156*04fd306cSNickeau return false; 157*04fd306cSNickeau } 158*04fd306cSNickeau /** 159*04fd306cSNickeau * Snippet 160*04fd306cSNickeau */ 161*04fd306cSNickeau PluginUtility::getSnippetManager()->attachCssInternalStyleSheet(self::CANONICAL); 162*04fd306cSNickeau 163*04fd306cSNickeau $bootstrapNamespace = "bs-"; 164*04fd306cSNickeau if (Bootstrap::getBootStrapMajorVersion() == Bootstrap::BootStrapFourMajorVersion) { 165*04fd306cSNickeau $bootstrapNamespace = ""; 166*04fd306cSNickeau } 167*04fd306cSNickeau /** 168*04fd306cSNickeau * Types 169*04fd306cSNickeau */ 170*04fd306cSNickeau $type = $tagAttributes->getType(); 171*04fd306cSNickeau if ($type !== null) { 172*04fd306cSNickeau $tagAttributes->addClassName("btn-$type"); 173*04fd306cSNickeau } 174*04fd306cSNickeau /** 175*04fd306cSNickeau * Should be in link form for bootstrap 176*04fd306cSNickeau */ 177*04fd306cSNickeau if (substr($targetId, 0, 1) != "#") { 178*04fd306cSNickeau $targetId = "#" . $targetId; 179*04fd306cSNickeau } 180*04fd306cSNickeau $tagAttributes->addComponentAttributeValue("data-{$bootstrapNamespace}toggle", "collapse"); 181*04fd306cSNickeau $tagAttributes->addComponentAttributeValue("data-{$bootstrapNamespace}target", $targetId); 182*04fd306cSNickeau 183*04fd306cSNickeau /** 184*04fd306cSNickeau * Aria 185*04fd306cSNickeau */ 186*04fd306cSNickeau $toggleState = $tagAttributes->getValueAndRemove(Toggle::TOGGLE_STATE, Toggle::TOGGLE_STATE_COLLAPSED); 187*04fd306cSNickeau switch ($toggleState) { 188*04fd306cSNickeau case Toggle::TOGGLE_STATE_EXPANDED: 189*04fd306cSNickeau $tagAttributes->addComponentAttributeValue("aria-expanded", true); 190*04fd306cSNickeau break; 191*04fd306cSNickeau case Toggle::TOGGLE_STATE_COLLAPSED: 192*04fd306cSNickeau $tagAttributes->addComponentAttributeValue("aria-expanded", false); 193*04fd306cSNickeau $tagAttributes->addClassName("collapsed"); 194*04fd306cSNickeau break; 195*04fd306cSNickeau } 196*04fd306cSNickeau 197*04fd306cSNickeau 198*04fd306cSNickeau $targetLabel = $tagAttributes->getValueAndRemoveIfPresent("targetLabel"); 199*04fd306cSNickeau if ($targetLabel === null) { 200*04fd306cSNickeau $targetLabel = "Toggle $targetId"; 201*04fd306cSNickeau } 202*04fd306cSNickeau $tagAttributes->addComponentAttributeValue("aria-label", $targetLabel); 203*04fd306cSNickeau $tagAttributes->addClassName("btn"); 204*04fd306cSNickeau $renderer->doc .= $tagAttributes->toHtmlEnterTag("button"); 205*04fd306cSNickeau break; 206*04fd306cSNickeau case DOKU_LEXER_UNMATCHED: 207*04fd306cSNickeau $renderer->doc .= PluginUtility::renderUnmatched($data); 208*04fd306cSNickeau break; 209*04fd306cSNickeau case DOKU_LEXER_EXIT: 210*04fd306cSNickeau $renderer->doc .= "</button>"; 211*04fd306cSNickeau break; 212*04fd306cSNickeau 213*04fd306cSNickeau } 214*04fd306cSNickeau return true; 215*04fd306cSNickeau } 216*04fd306cSNickeau 217*04fd306cSNickeau // unsupported $mode 218*04fd306cSNickeau return false; 219*04fd306cSNickeau } 220*04fd306cSNickeau 221*04fd306cSNickeau public 222*04fd306cSNickeau static function getTag(): string 223*04fd306cSNickeau { 224*04fd306cSNickeau return self::TAG; 225*04fd306cSNickeau } 226*04fd306cSNickeau 227*04fd306cSNickeau 228*04fd306cSNickeau} 229*04fd306cSNickeau 230