1<?php 2/** 3 * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved. 4 * 5 * This source code is licensed under the GPL license found in the 6 * COPYING file in the root directory of this source tree. 7 * 8 * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 9 * @author ComboStrap <support@combostrap.com> 10 * 11 */ 12 13use ComboStrap\Bootstrap; 14use ComboStrap\Xml\XhtmlUtility; 15use ComboStrap\LinkMarkup; 16use ComboStrap\NavBarUtility; 17use ComboStrap\PluginUtility; 18use ComboStrap\XmlTagProcessing; 19 20 21require_once(__DIR__ . '/../vendor/autoload.php'); 22 23 24/** 25 * 26 * See https://getbootstrap.com/docs/4.0/components/collapse/ 27 * 28 * The name of the class must follow a pattern (don't change it) ie syntax_plugin_PluginName_ComponentName 29 */ 30class syntax_plugin_combo_navbarcollapse extends DokuWiki_Syntax_Plugin 31{ 32 const TAG = 'collapse'; 33 const COMPONENT = 'navbarcollapse'; 34 35 /** 36 * Syntax Type. 37 * 38 * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 39 * @see DokuWiki_Syntax_Plugin::getType() 40 */ 41 function getType() 42 { 43 return 'container'; 44 } 45 46 /** 47 * @return array 48 * Allow which kind of plugin inside 49 * 50 * No one of array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 51 * because we manage self the content and we call self the parser 52 */ 53 public function getAllowedTypes() 54 { 55 return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); 56 } 57 58 public function accepts($mode) 59 { 60 61 $accept = syntax_plugin_combo_preformatted::disablePreformatted($mode); 62 63 // P element are not welcome in a navbar 64 if ($mode == "eol") { 65 $accept = false; 66 } 67 68 return $accept; 69 70 } 71 72 73 /** 74 * How Dokuwiki will add P element 75 * 76 * * 'normal' - The plugin can be used inside paragraphs 77 * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 78 * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 79 * 80 * @see DokuWiki_Syntax_Plugin::getPType() 81 */ 82 function getPType() 83 { 84 return 'block'; 85 } 86 87 /** 88 * @see Doku_Parser_Mode::getSort() 89 * 90 * the mode with the lowest sort number will win out 91 * the container (parent) must then have a lower number than the child 92 */ 93 function getSort() 94 { 95 return 100; 96 } 97 98 /** 99 * Create a pattern that will called this plugin 100 * 101 * @param string $mode 102 * @see Doku_Parser_Mode::connectTo() 103 */ 104 function connectTo($mode) 105 { 106 // Only inside a navbar 107 if ($mode == PluginUtility::getModeFromTag(syntax_plugin_combo_menubar::TAG)) { 108 $pattern = XmlTagProcessing::getContainerTagPattern(self::TAG); 109 $this->Lexer->addEntryPattern($pattern, $mode, 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent()); 110 } 111 112 } 113 114 public function postConnect() 115 { 116 117 $this->Lexer->addExitPattern('</' . self::TAG . '>', 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent()); 118 119 } 120 121 /** 122 * 123 * The handle function goal is to parse the matched syntax through the pattern function 124 * and to return the result for use in the renderer 125 * This result is always cached until the page is modified. 126 * @param string $match 127 * @param int $state 128 * @param int $pos 129 * @param Doku_Handler $handler 130 * @return array|bool 131 * @see DokuWiki_Syntax_Plugin::handle() 132 * 133 */ 134 function handle($match, $state, $pos, Doku_Handler $handler) 135 { 136 137 switch ($state) { 138 139 case DOKU_LEXER_ENTER: 140 141 $tagAttributes = PluginUtility::getTagAttributes($match); 142 return array( 143 PluginUtility::STATE => $state, 144 PluginUtility::ATTRIBUTES => $tagAttributes 145 ); 146 147 case DOKU_LEXER_UNMATCHED : 148 149 return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 150 151 152 case DOKU_LEXER_EXIT : 153 154 return array(PluginUtility::STATE => $state); 155 156 157 } 158 159 return array(); 160 161 } 162 163 /** 164 * Render the output 165 * @param string $format 166 * @param Doku_Renderer $renderer 167 * @param array $data - what the function handle() return'ed 168 * @return boolean - rendered correctly? (however, returned value is not used at the moment) 169 * @see DokuWiki_Syntax_Plugin::render() 170 * 171 * 172 */ 173 function render($format, Doku_Renderer $renderer, $data) 174 { 175 $state = $data[PluginUtility::STATE]; 176 switch ($format) { 177 case 'xhtml': 178 /** @var Doku_Renderer_xhtml $renderer */ 179 180 switch ($state) { 181 182 case DOKU_LEXER_ENTER : 183 184 $attributes = $data[PluginUtility::ATTRIBUTES]; 185 186 // The button is the hamburger menu that will be shown 187 $idElementToCollapse = 'navbarcollapse'; 188 $dataNamespace = Bootstrap::getDataNamespace(); 189 $renderer->doc .= "<button class=\"navbar-toggler\" type=\"button\" data{$dataNamespace}-toggle=\"collapse\" data{$dataNamespace}-target=\"#$idElementToCollapse\" aria-controls=\"$idElementToCollapse\" aria-expanded=\"false\" aria-label=\"Toggle navigation\""; 190 if (array_key_exists("order", $attributes)) { 191 $renderer->doc .= ' style="order:' . $attributes["order"] . '"'; 192 unset($attributes["order"]); 193 } 194 $renderer->doc .= '>' . DOKU_LF; 195 $renderer->doc .= '<span class="navbar-toggler-icon"></span>' . DOKU_LF; 196 $renderer->doc .= '</button>' . DOKU_LF; 197 198 199 $classValue = "collapse navbar-collapse"; 200 if (array_key_exists("class", $attributes)) { 201 $attributes["class"] .= " {$classValue}"; 202 } else { 203 $attributes["class"] = "{$classValue}"; 204 } 205 $renderer->doc .= '<div id="' . $idElementToCollapse . '" ' . PluginUtility::array2HTMLAttributesAsString($attributes) . '>'; 206 207 // All element below will collapse 208 break; 209 210 case DOKU_LEXER_UNMATCHED: 211 $renderer->doc .= NavBarUtility::text(PluginUtility::renderUnmatched($data)); 212 break; 213 214 215 case DOKU_LEXER_EXIT : 216 217 $renderer->doc .= '</div>' . DOKU_LF; 218 break; 219 } 220 return true; 221 222 } 223 return false; 224 } 225 226 227 public static function getElementName() 228 { 229 return PluginUtility::getTagName(get_called_class()); 230 } 231 232 233} 234