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\HtmlUtility; 14use ComboStrap\LinkUtility; 15use ComboStrap\NavBarUtility; 16use ComboStrap\PluginUtility; 17 18 19require_once(__DIR__ . '/../class/PluginUtility.php'); 20require_once(__DIR__ . '/../class/NavBarUtility.php'); 21 22 23/** 24 * 25 * See https://getbootstrap.com/docs/4.0/components/collapse/ 26 * 27 * The name of the class must follow a pattern (don't change it) ie syntax_plugin_PluginName_ComponentName 28 */ 29class syntax_plugin_combo_navbarcollapse extends DokuWiki_Syntax_Plugin 30{ 31 const TAG = 'collapse'; 32 const COMPONENT = 'navbarcollapse'; 33 34 /** 35 * Syntax Type. 36 * 37 * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 38 * @see DokuWiki_Syntax_Plugin::getType() 39 */ 40 function getType() 41 { 42 return 'container'; 43 } 44 45 /** 46 * @return array 47 * Allow which kind of plugin inside 48 * 49 * No one of array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 50 * because we manage self the content and we call self the parser 51 */ 52 public function getAllowedTypes() 53 { 54 return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); 55 } 56 57 /** 58 * We don't accept link as substition 59 * @param string $mode 60 * @return bool 61 */ 62// public function accepts($mode) 63// { 64// $position = strpos($mode, 'link'); 65// if ($position === false){ 66// return parent::accepts($mode); 67// } else { 68// return false; 69// } 70// 71// } 72 73 74 /** 75 * How Dokuwiki will add P element 76 * 77 * * 'normal' - The plugin can be used inside paragraphs 78 * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 79 * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 80 * 81 * @see DokuWiki_Syntax_Plugin::getPType() 82 */ 83 function getPType() 84 { 85 return 'normal'; 86 } 87 88 /** 89 * @see Doku_Parser_Mode::getSort() 90 * 91 * the mode with the lowest sort number will win out 92 * the container (parent) must then have a lower number than the child 93 */ 94 function getSort() 95 { 96 return 100; 97 } 98 99 /** 100 * Create a pattern that will called this plugin 101 * 102 * @param string $mode 103 * @see Doku_Parser_Mode::connectTo() 104 */ 105 function connectTo($mode) 106 { 107 // Only inside a navbar 108 if ($mode == PluginUtility::getModeForComponent(syntax_plugin_combo_navbar::TAG)) { 109 $pattern = PluginUtility::getContainerTagPattern(self::TAG); 110 $this->Lexer->addEntryPattern($pattern, $mode, 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent()); 111 $this->Lexer->addPattern(LinkUtility::LINK_PATTERN, PluginUtility::getModeForComponent($this->getPluginComponent())); 112 } 113 114 } 115 116 public function postConnect() 117 { 118 119 $this->Lexer->addExitPattern('</' . self::TAG . '>', 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent()); 120 121 } 122 123 /** 124 * 125 * The handle function goal is to parse the matched syntax through the pattern function 126 * and to return the result for use in the renderer 127 * This result is always cached until the page is modified. 128 * @param string $match 129 * @param int $state 130 * @param int $pos 131 * @param Doku_Handler $handler 132 * @return array|bool 133 * @see DokuWiki_Syntax_Plugin::handle() 134 * 135 */ 136 function handle($match, $state, $pos, Doku_Handler $handler) 137 { 138 139 switch ($state) { 140 141 case DOKU_LEXER_ENTER: 142 143 $tagAttributes = PluginUtility::getTagAttributes($match); 144 return array($state, $tagAttributes); 145 146 case DOKU_LEXER_UNMATCHED : 147 148 return array($state, $match); 149 150 case DOKU_LEXER_MATCHED: 151 152 $linkAttributes = LinkUtility::getAttributes($match); 153 return array($state, $linkAttributes); 154 155 case DOKU_LEXER_EXIT : 156 157 return array($state, ''); 158 159 160 } 161 162 return array(); 163 164 } 165 166 /** 167 * Render the output 168 * @param string $format 169 * @param Doku_Renderer $renderer 170 * @param array $data - what the function handle() return'ed 171 * @return boolean - rendered correctly? (however, returned value is not used at the moment) 172 * @see DokuWiki_Syntax_Plugin::render() 173 * 174 * 175 */ 176 function render($format, Doku_Renderer $renderer, $data) 177 { 178 list($state, $payload) = $data; 179 switch ($format) { 180 case 'xhtml': 181 /** @var Doku_Renderer_xhtml $renderer */ 182 183 switch ($state) { 184 185 case DOKU_LEXER_ENTER : 186 187 $attributes = $payload; 188 189 // The button is the hamburger menu that will be shown 190 $idElementToCollapse = 'navbarcollapse'; 191 $renderer->doc .= '<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#' . $idElementToCollapse . '" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation"'; 192 if (array_key_exists("order", $attributes)) { 193 $renderer->doc .= ' style="order:' . $attributes["order"]; 194 unset($attributes["order"]); 195 } 196 $renderer->doc .= '"><span class="navbar-toggler-icon"></span></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::array2HTMLAttributes($attributes).'>'; 206 207 // All element below will collapse 208 break; 209 210 case DOKU_LEXER_UNMATCHED: 211 $renderer->doc .= NavBarUtility::text(PluginUtility::escape($payload)); 212 break; 213 214 case DOKU_LEXER_MATCHED: 215 216 /** 217 * Shortcut for a link in a {@link syntax_plugin_combo_navbargroup} 218 */ 219 $html = LinkUtility::renderLinkDefault($renderer,$payload); 220 $renderer->doc .= '<div class="navbar-nav">'.NavBarUtility::switchDokuwiki2BootstrapClass($html).'</div>'; 221 break; 222 223 case DOKU_LEXER_EXIT : 224 225 $renderer->doc .= '</div>' . DOKU_LF; 226 break; 227 } 228 return true; 229 case 'metadata': 230 231 /** 232 * Keep track of the backlinks ie meta['relation']['references'] 233 * @var Doku_Renderer_metadata $renderer 234 */ 235 if ($state == DOKU_LEXER_SPECIAL) { 236 LinkUtility::handleMetadata($renderer, $data); 237 } 238 return true; 239 break; 240 } 241 return false; 242 } 243 244 245 public static function getElementName() 246 { 247 return PluginUtility::getTagName(get_called_class()); 248 } 249 250 251} 252