1531e725cSNickeau<?php 2531e725cSNickeau/** 3531e725cSNickeau * DokuWiki Syntax Plugin Combostrap. 4531e725cSNickeau * 5531e725cSNickeau */ 6531e725cSNickeau 7531e725cSNickeauuse ComboStrap\PluginUtility; 8531e725cSNickeau 9531e725cSNickeauif (!defined('DOKU_INC')) { 10531e725cSNickeau die(); 11531e725cSNickeau} 12531e725cSNickeau 1337748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 14531e725cSNickeau 15531e725cSNickeau/** 16531e725cSNickeau * All DokuWiki plugins to extend the parser/rendering mechanism 17531e725cSNickeau * need to inherit from this class 18531e725cSNickeau * 19531e725cSNickeau * The name of the class must follow a pattern (don't change it) 20531e725cSNickeau * ie: 21531e725cSNickeau * syntax_plugin_PluginName_ComponentName 22531e725cSNickeau * 23531e725cSNickeau * See also: doc : 24531e725cSNickeau * https://getbootstrap.com/docs/5.0/components/navbar/ 25531e725cSNickeau * https://material.io/components/app-bars-top 26531e725cSNickeau * 27531e725cSNickeau * Name: 28531e725cSNickeau * * header bar: http://themenectar.com/docs/salient/theme-options/header-navigation 29531e725cSNickeau * * menu bar: https://en.wikipedia.org/wiki/Menu_bar 30531e725cSNickeau * * app bar: https://material.io/components/app-bars-top 31531e725cSNickeau * * navbar: https://getbootstrap.com/docs/5.0/examples/navbars/# 32531e725cSNickeau */ 33531e725cSNickeauclass syntax_plugin_combo_menubar extends DokuWiki_Syntax_Plugin 34531e725cSNickeau{ 35531e725cSNickeau 36531e725cSNickeau const TAG = 'menubar'; 37531e725cSNickeau const OLD_TAG = "navbar"; 38531e725cSNickeau const TAGS = [self::TAG,self::OLD_TAG]; 39531e725cSNickeau 40531e725cSNickeau /** 41531e725cSNickeau * Do we need to add a container 42531e725cSNickeau * @var bool 43531e725cSNickeau */ 44531e725cSNickeau private $containerInside = false; 45531e725cSNickeau 46531e725cSNickeau /** 47531e725cSNickeau * Syntax Type. 48531e725cSNickeau * 49531e725cSNickeau * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 50531e725cSNickeau * @see DokuWiki_Syntax_Plugin::getType() 51531e725cSNickeau */ 52531e725cSNickeau function getType() 53531e725cSNickeau { 54531e725cSNickeau return 'container'; 55531e725cSNickeau } 56531e725cSNickeau 57531e725cSNickeau /** 58531e725cSNickeau * @return array 59531e725cSNickeau * Allow which kind of plugin inside 60531e725cSNickeau * All 61531e725cSNickeau */ 62531e725cSNickeau public function getAllowedTypes() 63531e725cSNickeau { 64531e725cSNickeau return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); 65531e725cSNickeau } 66531e725cSNickeau 67531e725cSNickeau public function accepts($mode) 68531e725cSNickeau { 69531e725cSNickeau 70531e725cSNickeau $accept = syntax_plugin_combo_preformatted::disablePreformatted($mode); 71531e725cSNickeau 72531e725cSNickeau 73531e725cSNickeau // Create P element 74531e725cSNickeau if ($mode == "eol") { 75531e725cSNickeau $accept = false; 76531e725cSNickeau } 77531e725cSNickeau 78531e725cSNickeau return $accept; 79531e725cSNickeau 80531e725cSNickeau } 81531e725cSNickeau 82531e725cSNickeau /** 83531e725cSNickeau * How Dokuwiki will add P element 84531e725cSNickeau * 85531e725cSNickeau * * 'normal' - The plugin can be used inside paragraphs 86531e725cSNickeau * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 87531e725cSNickeau * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 88531e725cSNickeau * 89531e725cSNickeau * @see DokuWiki_Syntax_Plugin::getPType() 90531e725cSNickeau */ 91531e725cSNickeau function getPType() 92531e725cSNickeau { 93531e725cSNickeau return 'block'; 94531e725cSNickeau } 95531e725cSNickeau 96531e725cSNickeau /** 97531e725cSNickeau * @see Doku_Parser_Mode::getSort() 98531e725cSNickeau * 99531e725cSNickeau * the mode with the lowest sort number will win out 100531e725cSNickeau * the container (parent) must then have a lower number than the child 101531e725cSNickeau */ 102531e725cSNickeau function getSort() 103531e725cSNickeau { 104531e725cSNickeau return 100; 105531e725cSNickeau } 106531e725cSNickeau 107531e725cSNickeau /** 108531e725cSNickeau * Create a pattern that will called this plugin 109531e725cSNickeau * 110531e725cSNickeau * @param string $mode 111531e725cSNickeau * @see Doku_Parser_Mode::connectTo() 112531e725cSNickeau */ 113531e725cSNickeau function connectTo($mode) 114531e725cSNickeau { 115531e725cSNickeau 116531e725cSNickeau foreach(self::TAGS as $tag) { 117531e725cSNickeau $pattern = PluginUtility::getContainerTagPattern($tag); 1189337a630SNickeau $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 119531e725cSNickeau } 120531e725cSNickeau 121531e725cSNickeau } 122531e725cSNickeau 123531e725cSNickeau public function postConnect() 124531e725cSNickeau { 125531e725cSNickeau foreach(self::TAGS as $tag) { 1269337a630SNickeau $this->Lexer->addExitPattern('</' . $tag . '>', PluginUtility::getModeFromTag($this->getPluginComponent())); 127531e725cSNickeau } 128531e725cSNickeau 129531e725cSNickeau } 130531e725cSNickeau 131531e725cSNickeau 132531e725cSNickeau /** 133531e725cSNickeau * 134531e725cSNickeau * The handle function goal is to parse the matched syntax through the pattern function 135531e725cSNickeau * and to return the result for use in the renderer 136531e725cSNickeau * This result is always cached until the page is modified. 137531e725cSNickeau * @param string $match 138531e725cSNickeau * @param int $state 139531e725cSNickeau * @param int $pos 140531e725cSNickeau * @param Doku_Handler $handler 141531e725cSNickeau * @return array|bool 142531e725cSNickeau * @see DokuWiki_Syntax_Plugin::handle() 143531e725cSNickeau * 144531e725cSNickeau */ 145531e725cSNickeau function handle($match, $state, $pos, Doku_Handler $handler) 146531e725cSNickeau { 147531e725cSNickeau 148531e725cSNickeau switch ($state) { 149531e725cSNickeau 150531e725cSNickeau case DOKU_LEXER_ENTER: 151531e725cSNickeau 152531e725cSNickeau $tagAttributes = PluginUtility::getTagAttributes($match); 153531e725cSNickeau return array( 154531e725cSNickeau PluginUtility::STATE => $state, 155531e725cSNickeau PluginUtility::ATTRIBUTES => $tagAttributes 156531e725cSNickeau ); 157531e725cSNickeau 158531e725cSNickeau case DOKU_LEXER_UNMATCHED: 159531e725cSNickeau 160531e725cSNickeau return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 161531e725cSNickeau 162531e725cSNickeau case DOKU_LEXER_EXIT : 163531e725cSNickeau 164531e725cSNickeau return array( 165531e725cSNickeau PluginUtility::STATE => $state 166531e725cSNickeau ); 167531e725cSNickeau 168531e725cSNickeau 169531e725cSNickeau } 170531e725cSNickeau 171531e725cSNickeau return array(); 172531e725cSNickeau 173531e725cSNickeau } 174531e725cSNickeau 175531e725cSNickeau /** 176531e725cSNickeau * Render the output 177531e725cSNickeau * @param string $format 178531e725cSNickeau * @param Doku_Renderer $renderer 179531e725cSNickeau * @param array $data - what the function handle() return'ed 180531e725cSNickeau * @return boolean - rendered correctly? (however, returned value is not used at the moment) 181531e725cSNickeau * @see DokuWiki_Syntax_Plugin::render() 182531e725cSNickeau * 183531e725cSNickeau * 184531e725cSNickeau */ 185*4cadd4f8SNickeau function render($format, Doku_Renderer $renderer, $data): bool 186531e725cSNickeau { 187531e725cSNickeau 188531e725cSNickeau if ($format == 'xhtml') { 189531e725cSNickeau 190531e725cSNickeau /** @var Doku_Renderer_xhtml $renderer */ 191531e725cSNickeau $state = $data[PluginUtility::STATE]; 192531e725cSNickeau switch ($state) { 193531e725cSNickeau 194531e725cSNickeau case DOKU_LEXER_ENTER : 195531e725cSNickeau 196531e725cSNickeau $attributes = $data[PluginUtility::ATTRIBUTES]; 197531e725cSNickeau $class = 'navbar'; 198531e725cSNickeau if (array_key_exists("class", $attributes)) { 199531e725cSNickeau $attributes["class"] .= ' ' . $class; 200531e725cSNickeau } else { 201531e725cSNickeau $attributes["class"] = $class; 202531e725cSNickeau } 203531e725cSNickeau 204531e725cSNickeau if (!array_key_exists("background-color", $attributes)) { 205531e725cSNickeau $attributes["background-color"] = 'light'; 206531e725cSNickeau } 207531e725cSNickeau 208531e725cSNickeau /** 209531e725cSNickeau * Without the expand, the flex has a row direction 210531e725cSNickeau * and not a column 211531e725cSNickeau */ 212531e725cSNickeau $breakpoint = "lg"; 213531e725cSNickeau if (array_key_exists("breakpoint", $attributes)) { 214531e725cSNickeau $breakpoint = $attributes["breakpoint"]; 215531e725cSNickeau unset($attributes["breakpoint"]); 216531e725cSNickeau } 217531e725cSNickeau $attributes["class"] .= ' navbar-expand-' . $breakpoint; 218531e725cSNickeau 219531e725cSNickeau // Grab the position 220531e725cSNickeau if (array_key_exists("position", $attributes)) { 221531e725cSNickeau $position = $attributes["position"]; 222531e725cSNickeau if ($position === "top") { 22385e82846SNickeau $fixedTopClass = 'fixed-top'; 22485e82846SNickeau $attributes["class"] .= ' ' . $fixedTopClass . ''; 22585e82846SNickeau $fixedTopSnippetId = self::TAG."-".$fixedTopClass; 22685e82846SNickeau // See http://stackoverflow.com/questions/17181355/boostrap-using-fixed-navbar-and-anchor-tags-to-jump-to-sections 227*4cadd4f8SNickeau PluginUtility::getSnippetManager()->attachInternalJavascriptForSlot($fixedTopSnippetId); 228531e725cSNickeau } 229531e725cSNickeau unset($attributes["position"]); 230531e725cSNickeau } 231531e725cSNickeau 232531e725cSNickeau // Theming 233531e725cSNickeau $theme = "light"; 234531e725cSNickeau if (array_key_exists("theme", $attributes)) { 235531e725cSNickeau $theme = $attributes["theme"]; 236531e725cSNickeau unset($attributes["theme"]); 237531e725cSNickeau } 238531e725cSNickeau $attributes["class"] .= ' navbar-' . $theme; 239531e725cSNickeau 240531e725cSNickeau // Align 241531e725cSNickeau $align = "center"; 242531e725cSNickeau if (array_key_exists("align", $attributes)) { 243531e725cSNickeau $align = $attributes["align"]; 244531e725cSNickeau unset($attributes["align"]); 245531e725cSNickeau } 246531e725cSNickeau 247531e725cSNickeau // Container 248531e725cSNickeau if ($align === "center") { 249531e725cSNickeau $this->containerInside = true; 250531e725cSNickeau } 251531e725cSNickeau 252531e725cSNickeau 253531e725cSNickeau $inlineAttributes = PluginUtility::array2HTMLAttributesAsString($attributes); 254531e725cSNickeau 255531e725cSNickeau $containerTag = ""; 256531e725cSNickeau if ($this->containerInside) { 257531e725cSNickeau $containerTag = '<div class="container">'; 258531e725cSNickeau } 259531e725cSNickeau 260531e725cSNickeau $renderer->doc .= "<nav {$inlineAttributes}>" . DOKU_LF; 261531e725cSNickeau 262531e725cSNickeau // When the top is fixed, the container should be inside the navbar 263531e725cSNickeau $renderer->doc .= "{$containerTag}" . DOKU_LF; 264531e725cSNickeau break; 265531e725cSNickeau 266531e725cSNickeau case DOKU_LEXER_UNMATCHED: 267531e725cSNickeau $renderer->doc .= PluginUtility::renderUnmatched($data); 268531e725cSNickeau break; 269531e725cSNickeau 270531e725cSNickeau case DOKU_LEXER_EXIT : 271531e725cSNickeau $containerTag = ""; 272531e725cSNickeau if ($this->containerInside) { 273531e725cSNickeau $containerTag = '</div>'; 274531e725cSNickeau } 275531e725cSNickeau $renderer->doc .= "{$containerTag}</nav>" . DOKU_LF; 276531e725cSNickeau break; 277531e725cSNickeau } 278531e725cSNickeau return true; 279531e725cSNickeau } 280531e725cSNickeau return false; 281531e725cSNickeau } 282531e725cSNickeau 283531e725cSNickeau 284531e725cSNickeau} 285