1*531e725cSNickeau<?php 2*531e725cSNickeau/** 3*531e725cSNickeau * DokuWiki Syntax Plugin Combostrap. 4*531e725cSNickeau * 5*531e725cSNickeau */ 6*531e725cSNickeau 7*531e725cSNickeauuse ComboStrap\PluginUtility; 8*531e725cSNickeau 9*531e725cSNickeauif (!defined('DOKU_INC')) { 10*531e725cSNickeau die(); 11*531e725cSNickeau} 12*531e725cSNickeau 13*531e725cSNickeaurequire_once(__DIR__ . '/../class/PluginUtility.php'); 14*531e725cSNickeau 15*531e725cSNickeau/** 16*531e725cSNickeau * All DokuWiki plugins to extend the parser/rendering mechanism 17*531e725cSNickeau * need to inherit from this class 18*531e725cSNickeau * 19*531e725cSNickeau * The name of the class must follow a pattern (don't change it) 20*531e725cSNickeau * ie: 21*531e725cSNickeau * syntax_plugin_PluginName_ComponentName 22*531e725cSNickeau * 23*531e725cSNickeau * See also: doc : 24*531e725cSNickeau * https://getbootstrap.com/docs/5.0/components/navbar/ 25*531e725cSNickeau * https://material.io/components/app-bars-top 26*531e725cSNickeau * 27*531e725cSNickeau * Name: 28*531e725cSNickeau * * header bar: http://themenectar.com/docs/salient/theme-options/header-navigation 29*531e725cSNickeau * * menu bar: https://en.wikipedia.org/wiki/Menu_bar 30*531e725cSNickeau * * app bar: https://material.io/components/app-bars-top 31*531e725cSNickeau * * navbar: https://getbootstrap.com/docs/5.0/examples/navbars/# 32*531e725cSNickeau */ 33*531e725cSNickeauclass syntax_plugin_combo_menubar extends DokuWiki_Syntax_Plugin 34*531e725cSNickeau{ 35*531e725cSNickeau 36*531e725cSNickeau const TAG = 'menubar'; 37*531e725cSNickeau const OLD_TAG = "navbar"; 38*531e725cSNickeau const TAGS = [self::TAG,self::OLD_TAG]; 39*531e725cSNickeau 40*531e725cSNickeau /** 41*531e725cSNickeau * Do we need to add a container 42*531e725cSNickeau * @var bool 43*531e725cSNickeau */ 44*531e725cSNickeau private $containerInside = false; 45*531e725cSNickeau 46*531e725cSNickeau /** 47*531e725cSNickeau * Syntax Type. 48*531e725cSNickeau * 49*531e725cSNickeau * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 50*531e725cSNickeau * @see DokuWiki_Syntax_Plugin::getType() 51*531e725cSNickeau */ 52*531e725cSNickeau function getType() 53*531e725cSNickeau { 54*531e725cSNickeau return 'container'; 55*531e725cSNickeau } 56*531e725cSNickeau 57*531e725cSNickeau /** 58*531e725cSNickeau * @return array 59*531e725cSNickeau * Allow which kind of plugin inside 60*531e725cSNickeau * All 61*531e725cSNickeau */ 62*531e725cSNickeau public function getAllowedTypes() 63*531e725cSNickeau { 64*531e725cSNickeau return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); 65*531e725cSNickeau } 66*531e725cSNickeau 67*531e725cSNickeau public function accepts($mode) 68*531e725cSNickeau { 69*531e725cSNickeau 70*531e725cSNickeau $accept = syntax_plugin_combo_preformatted::disablePreformatted($mode); 71*531e725cSNickeau 72*531e725cSNickeau 73*531e725cSNickeau // Create P element 74*531e725cSNickeau if ($mode == "eol") { 75*531e725cSNickeau $accept = false; 76*531e725cSNickeau } 77*531e725cSNickeau 78*531e725cSNickeau return $accept; 79*531e725cSNickeau 80*531e725cSNickeau } 81*531e725cSNickeau 82*531e725cSNickeau /** 83*531e725cSNickeau * How Dokuwiki will add P element 84*531e725cSNickeau * 85*531e725cSNickeau * * 'normal' - The plugin can be used inside paragraphs 86*531e725cSNickeau * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 87*531e725cSNickeau * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 88*531e725cSNickeau * 89*531e725cSNickeau * @see DokuWiki_Syntax_Plugin::getPType() 90*531e725cSNickeau */ 91*531e725cSNickeau function getPType() 92*531e725cSNickeau { 93*531e725cSNickeau return 'block'; 94*531e725cSNickeau } 95*531e725cSNickeau 96*531e725cSNickeau /** 97*531e725cSNickeau * @see Doku_Parser_Mode::getSort() 98*531e725cSNickeau * 99*531e725cSNickeau * the mode with the lowest sort number will win out 100*531e725cSNickeau * the container (parent) must then have a lower number than the child 101*531e725cSNickeau */ 102*531e725cSNickeau function getSort() 103*531e725cSNickeau { 104*531e725cSNickeau return 100; 105*531e725cSNickeau } 106*531e725cSNickeau 107*531e725cSNickeau /** 108*531e725cSNickeau * Create a pattern that will called this plugin 109*531e725cSNickeau * 110*531e725cSNickeau * @param string $mode 111*531e725cSNickeau * @see Doku_Parser_Mode::connectTo() 112*531e725cSNickeau */ 113*531e725cSNickeau function connectTo($mode) 114*531e725cSNickeau { 115*531e725cSNickeau 116*531e725cSNickeau foreach(self::TAGS as $tag) { 117*531e725cSNickeau $pattern = PluginUtility::getContainerTagPattern($tag); 118*531e725cSNickeau $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeForComponent($this->getPluginComponent())); 119*531e725cSNickeau } 120*531e725cSNickeau 121*531e725cSNickeau } 122*531e725cSNickeau 123*531e725cSNickeau public function postConnect() 124*531e725cSNickeau { 125*531e725cSNickeau foreach(self::TAGS as $tag) { 126*531e725cSNickeau $this->Lexer->addExitPattern('</' . $tag . '>', PluginUtility::getModeForComponent($this->getPluginComponent())); 127*531e725cSNickeau } 128*531e725cSNickeau 129*531e725cSNickeau } 130*531e725cSNickeau 131*531e725cSNickeau 132*531e725cSNickeau /** 133*531e725cSNickeau * 134*531e725cSNickeau * The handle function goal is to parse the matched syntax through the pattern function 135*531e725cSNickeau * and to return the result for use in the renderer 136*531e725cSNickeau * This result is always cached until the page is modified. 137*531e725cSNickeau * @param string $match 138*531e725cSNickeau * @param int $state 139*531e725cSNickeau * @param int $pos 140*531e725cSNickeau * @param Doku_Handler $handler 141*531e725cSNickeau * @return array|bool 142*531e725cSNickeau * @see DokuWiki_Syntax_Plugin::handle() 143*531e725cSNickeau * 144*531e725cSNickeau */ 145*531e725cSNickeau function handle($match, $state, $pos, Doku_Handler $handler) 146*531e725cSNickeau { 147*531e725cSNickeau 148*531e725cSNickeau switch ($state) { 149*531e725cSNickeau 150*531e725cSNickeau case DOKU_LEXER_ENTER: 151*531e725cSNickeau 152*531e725cSNickeau $tagAttributes = PluginUtility::getTagAttributes($match); 153*531e725cSNickeau return array( 154*531e725cSNickeau PluginUtility::STATE => $state, 155*531e725cSNickeau PluginUtility::ATTRIBUTES => $tagAttributes 156*531e725cSNickeau ); 157*531e725cSNickeau 158*531e725cSNickeau case DOKU_LEXER_UNMATCHED: 159*531e725cSNickeau 160*531e725cSNickeau return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 161*531e725cSNickeau 162*531e725cSNickeau case DOKU_LEXER_EXIT : 163*531e725cSNickeau 164*531e725cSNickeau return array( 165*531e725cSNickeau PluginUtility::STATE => $state 166*531e725cSNickeau ); 167*531e725cSNickeau 168*531e725cSNickeau 169*531e725cSNickeau } 170*531e725cSNickeau 171*531e725cSNickeau return array(); 172*531e725cSNickeau 173*531e725cSNickeau } 174*531e725cSNickeau 175*531e725cSNickeau /** 176*531e725cSNickeau * Render the output 177*531e725cSNickeau * @param string $format 178*531e725cSNickeau * @param Doku_Renderer $renderer 179*531e725cSNickeau * @param array $data - what the function handle() return'ed 180*531e725cSNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 181*531e725cSNickeau * @see DokuWiki_Syntax_Plugin::render() 182*531e725cSNickeau * 183*531e725cSNickeau * 184*531e725cSNickeau */ 185*531e725cSNickeau function render($format, Doku_Renderer $renderer, $data) 186*531e725cSNickeau { 187*531e725cSNickeau 188*531e725cSNickeau if ($format == 'xhtml') { 189*531e725cSNickeau 190*531e725cSNickeau /** @var Doku_Renderer_xhtml $renderer */ 191*531e725cSNickeau $state = $data[PluginUtility::STATE]; 192*531e725cSNickeau switch ($state) { 193*531e725cSNickeau 194*531e725cSNickeau case DOKU_LEXER_ENTER : 195*531e725cSNickeau 196*531e725cSNickeau $attributes = $data[PluginUtility::ATTRIBUTES]; 197*531e725cSNickeau $class = 'navbar'; 198*531e725cSNickeau if (array_key_exists("class", $attributes)) { 199*531e725cSNickeau $attributes["class"] .= ' ' . $class; 200*531e725cSNickeau } else { 201*531e725cSNickeau $attributes["class"] = $class; 202*531e725cSNickeau } 203*531e725cSNickeau 204*531e725cSNickeau if (!array_key_exists("background-color", $attributes)) { 205*531e725cSNickeau $attributes["background-color"] = 'light'; 206*531e725cSNickeau } 207*531e725cSNickeau 208*531e725cSNickeau /** 209*531e725cSNickeau * Without the expand, the flex has a row direction 210*531e725cSNickeau * and not a column 211*531e725cSNickeau */ 212*531e725cSNickeau $breakpoint = "lg"; 213*531e725cSNickeau if (array_key_exists("breakpoint", $attributes)) { 214*531e725cSNickeau $breakpoint = $attributes["breakpoint"]; 215*531e725cSNickeau unset($attributes["breakpoint"]); 216*531e725cSNickeau } 217*531e725cSNickeau $attributes["class"] .= ' navbar-expand-' . $breakpoint; 218*531e725cSNickeau 219*531e725cSNickeau // Grab the position 220*531e725cSNickeau if (array_key_exists("position", $attributes)) { 221*531e725cSNickeau $position = $attributes["position"]; 222*531e725cSNickeau if ($position === "top") { 223*531e725cSNickeau $attributes["class"] .= ' fixed-top'; 224*531e725cSNickeau } 225*531e725cSNickeau unset($attributes["position"]); 226*531e725cSNickeau } 227*531e725cSNickeau 228*531e725cSNickeau // Theming 229*531e725cSNickeau $theme = "light"; 230*531e725cSNickeau if (array_key_exists("theme", $attributes)) { 231*531e725cSNickeau $theme = $attributes["theme"]; 232*531e725cSNickeau unset($attributes["theme"]); 233*531e725cSNickeau } 234*531e725cSNickeau $attributes["class"] .= ' navbar-' . $theme; 235*531e725cSNickeau 236*531e725cSNickeau // Align 237*531e725cSNickeau $align = "center"; 238*531e725cSNickeau if (array_key_exists("align", $attributes)) { 239*531e725cSNickeau $align = $attributes["align"]; 240*531e725cSNickeau unset($attributes["align"]); 241*531e725cSNickeau } 242*531e725cSNickeau 243*531e725cSNickeau // Container 244*531e725cSNickeau if ($align === "center") { 245*531e725cSNickeau $this->containerInside = true; 246*531e725cSNickeau } 247*531e725cSNickeau 248*531e725cSNickeau 249*531e725cSNickeau $inlineAttributes = PluginUtility::array2HTMLAttributesAsString($attributes); 250*531e725cSNickeau 251*531e725cSNickeau $containerTag = ""; 252*531e725cSNickeau if ($this->containerInside) { 253*531e725cSNickeau $containerTag = '<div class="container">'; 254*531e725cSNickeau } 255*531e725cSNickeau 256*531e725cSNickeau $renderer->doc .= "<nav {$inlineAttributes}>" . DOKU_LF; 257*531e725cSNickeau 258*531e725cSNickeau // When the top is fixed, the container should be inside the navbar 259*531e725cSNickeau $renderer->doc .= "{$containerTag}" . DOKU_LF; 260*531e725cSNickeau break; 261*531e725cSNickeau 262*531e725cSNickeau case DOKU_LEXER_UNMATCHED: 263*531e725cSNickeau $renderer->doc .= PluginUtility::renderUnmatched($data); 264*531e725cSNickeau break; 265*531e725cSNickeau 266*531e725cSNickeau case DOKU_LEXER_EXIT : 267*531e725cSNickeau $containerTag = ""; 268*531e725cSNickeau if ($this->containerInside) { 269*531e725cSNickeau $containerTag = '</div>'; 270*531e725cSNickeau } 271*531e725cSNickeau $renderer->doc .= "{$containerTag}</nav>" . DOKU_LF; 272*531e725cSNickeau break; 273*531e725cSNickeau } 274*531e725cSNickeau return true; 275*531e725cSNickeau } 276*531e725cSNickeau return false; 277*531e725cSNickeau } 278*531e725cSNickeau 279*531e725cSNickeau 280*531e725cSNickeau} 281