1<?php 2/** 3 * DokuWiki Syntax Plugin Combostrap. 4 * 5 */ 6 7use ComboStrap\HtmlUtility; 8use ComboStrap\LinkUtility; 9use ComboStrap\NavBarUtility; 10use ComboStrap\PluginUtility; 11 12if (!defined('DOKU_INC')) { 13 die(); 14} 15 16require_once(__DIR__ . '/../class/PluginUtility.php'); 17require_once(__DIR__ . '/../class/LinkUtility.php'); 18require_once(__DIR__ . '/../class/HtmlUtility.php'); 19 20/** 21 * All DokuWiki plugins to extend the parser/rendering mechanism 22 * need to inherit from this class 23 * 24 * The name of the class must follow a pattern (don't change it) 25 * ie: 26 * syntax_plugin_PluginName_ComponentName 27 * 28 * A navbar group is a navbar nav 29 */ 30class syntax_plugin_combo_navbargroup extends DokuWiki_Syntax_Plugin 31{ 32 33 const TAG = "group"; 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 * All 50 */ 51 public function getAllowedTypes() 52 { 53 return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); 54 } 55 56 /** 57 * How Dokuwiki will add P element 58 * 59 * * 'normal' - The plugin can be used inside paragraphs 60 * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 61 * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 62 * 63 * @see DokuWiki_Syntax_Plugin::getPType() 64 */ 65 function getPType() 66 { 67 return 'normal'; 68 } 69 70 /** 71 * @see Doku_Parser_Mode::getSort() 72 * 73 * the mode with the lowest sort number will win out 74 * the container (parent) must then have a lower number than the child 75 */ 76 function getSort() 77 { 78 return 100; 79 } 80 81 /** 82 * Create a pattern that will called this plugin 83 * 84 * @param string $mode 85 * @see Doku_Parser_Mode::connectTo() 86 */ 87 function connectTo($mode) 88 { 89 /** 90 * Only inside a navbar or collapse element 91 */ 92 $authorizedMode = [ 93 PluginUtility::getModeForComponent(syntax_plugin_combo_navbarcollapse::COMPONENT), 94 PluginUtility::getModeForComponent(syntax_plugin_combo_navbar::COMPONENT) 95 ]; 96 97 98 if (in_array($mode, $authorizedMode)) { 99 100 $pattern = PluginUtility::getContainerTagPattern(self::TAG); 101 $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeForComponent($this->getPluginComponent())); 102 $this->Lexer->addPattern(LinkUtility::LINK_PATTERN, PluginUtility::getModeForComponent($this->getPluginComponent())); 103 104 } 105 106 } 107 108 public function postConnect() 109 { 110 $this->Lexer->addExitPattern('</' . self::TAG . '>', 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent()); 111 112 } 113 114 /** 115 * 116 * The handle function goal is to parse the matched syntax through the pattern function 117 * and to return the result for use in the renderer 118 * This result is always cached until the page is modified. 119 * @param string $match 120 * @param int $state 121 * @param int $pos 122 * @param Doku_Handler $handler 123 * @return array|bool 124 * @see DokuWiki_Syntax_Plugin::handle() 125 * 126 */ 127 function handle($match, $state, $pos, Doku_Handler $handler) 128 { 129 130 switch ($state) { 131 132 case DOKU_LEXER_ENTER: 133 134 // Suppress the component name 135 $tagAttributes = PluginUtility::getTagAttributes($match); 136 return array($state, $tagAttributes); 137 138 case DOKU_LEXER_UNMATCHED: 139 return array($state, $match); 140 141 case DOKU_LEXER_MATCHED: 142 143 $linkAttributes = LinkUtility::getAttributes($match); 144 return array($state, $linkAttributes); 145 146 case DOKU_LEXER_EXIT : 147 148 return array($state, ''); 149 150 151 } 152 153 return array(); 154 155 } 156 157 /** 158 * Render the output 159 * @param string $format 160 * @param Doku_Renderer $renderer 161 * @param array $data - what the function handle() return'ed 162 * @return boolean - rendered correctly? (however, returned value is not used at the moment) 163 * @see DokuWiki_Syntax_Plugin::render() 164 * 165 * 166 */ 167 function render($format, Doku_Renderer $renderer, $data) 168 { 169 170 list($state, $payload) = $data; 171 if ($format == 'xhtml') { 172 173 /** @var Doku_Renderer_xhtml $renderer */ 174 175 switch ($state) { 176 177 case DOKU_LEXER_ENTER : 178 // https://getbootstrap.com/docs/4.0/components/navbar/#toggler splits the navbar-nav to another element 179 // navbar-nav implementation 180 181 $classValue = "navbar-nav"; 182 if (array_key_exists("class", $payload)) { 183 $payload["class"] .= " {$classValue}"; 184 } else { 185 $payload["class"] = $classValue; 186 } 187 188 if (array_key_exists("expand", $payload)) { 189 if ($payload["expand"]=="true") { 190 $payload["class"] .= " mr-auto"; 191 } 192 unset($payload["expand"]); 193 } 194 195 $inlineAttributes = PluginUtility::array2HTMLAttributes($payload); 196 $renderer->doc .= "<ul {$inlineAttributes}>" . DOKU_LF; 197 break; 198 case DOKU_LEXER_UNMATCHED : 199 200 $renderer->doc .= NavBarUtility::text(PluginUtility::escape($payload)); 201 break; 202 203 case DOKU_LEXER_MATCHED: 204 205 $html = LinkUtility::renderAsAnchorElement($renderer, $payload); 206 $renderer->doc .= '<li class="nav-item">'.NavBarUtility::switchDokuwiki2BootstrapClass($html).'</li>'; 207 break; 208 209 case DOKU_LEXER_EXIT : 210 $renderer->doc .= '</ul>' . DOKU_LF; 211 break; 212 } 213 return true; 214 } else if ($format == 'metadata' && $state == DOKU_LEXER_MATCHED) { 215 216 /** 217 * Keep track of the backlinks ie meta['relation']['references'] 218 * @var Doku_Renderer_metadata $renderer 219 */ 220 LinkUtility::handleMetadata($renderer, $payload); 221 return true; 222 223 } 224 return false; 225 } 226 227 228} 229