1<?php 2/** 3 * DokuWiki Syntax Plugin Web Component. 4 * 5 */ 6if (!defined('DOKU_INC')) { 7 die(); 8} 9 10if (!defined('DOKU_PLUGIN')) { 11 define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 12} 13 14 15require_once(DOKU_PLUGIN . 'syntax.php'); 16require_once(DOKU_INC . 'inc/parserutils.php'); 17 18/** 19 * All DokuWiki plugins to extend the parser/rendering mechanism 20 * need to inherit from this class 21 * 22 * The name of the class must follow a pattern (don't change it) 23 * ie: 24 * syntax_plugin_PluginName_ComponentName 25 * 26 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 27 * !!!!!!!!!!! The component name must be the name of the php file !!! 28 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 29 */ 30class syntax_plugin_webcomponent_button extends DokuWiki_Syntax_Plugin 31{ 32 33 34 const INTERNAL_LINK_PATTERN = "\[\[.*?\]\](?!\])"; 35 36 37 /** 38 * Syntax Type. 39 * 40 * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 41 * @see DokuWiki_Syntax_Plugin::getType() 42 */ 43 function getType() 44 { 45 return 'protected'; 46 } 47 48 /** 49 * @return array 50 * Allow which kind of plugin inside 51 * 52 * No one of array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 53 * because we manage self the content and we call self the parser 54 */ 55 public function getAllowedTypes() 56 { 57 return array(); 58 } 59 60 /** 61 * How Dokuwiki will add P element 62 * 63 * * 'normal' - The plugin can be used inside paragraphs 64 * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 65 * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 66 * 67 * @see DokuWiki_Syntax_Plugin::getPType() 68 */ 69 function getPType() 70 { 71 return 'block'; 72 } 73 74 /** 75 * @see Doku_Parser_Mode::getSort() 76 * the mode with the lowest sort number will win out 77 * the lowest in the tree must have the lowest sort number 78 * No idea why it must be low but inside a teaser, it will work 79 * https://www.dokuwiki.org/devel:parser#order_of_adding_modes_important 80 */ 81 function getSort() 82 { 83 return 10; 84 } 85 86 /** 87 * Create a pattern that will called this plugin 88 * 89 * @see Doku_Parser_Mode::connectTo() 90 * @param string $mode 91 */ 92 function connectTo($mode) 93 { 94 95 foreach (self::getTags() as $tag) { 96 97 $pattern = webcomponent::getLookAheadPattern($tag); 98 $this->Lexer->addEntryPattern($pattern, $mode, 'plugin_' . webcomponent::PLUGIN_NAME . '_' . $this->getPluginComponent()); 99 100 } 101 102 } 103 104 public function postConnect() 105 { 106 107 foreach (self::getTags() as $tag) { 108 $this->Lexer->addExitPattern('</' . $tag . '>', 'plugin_' . webcomponent::PLUGIN_NAME . '_' . $this->getPluginComponent()); 109 } 110 111 // Link 112 $this->Lexer->addPattern(self::INTERNAL_LINK_PATTERN, 'plugin_' . webcomponent::PLUGIN_NAME . '_' . $this->getPluginComponent()); 113 114 115 } 116 117 /** 118 * 119 * The handle function goal is to parse the matched syntax through the pattern function 120 * and to return the result for use in the renderer 121 * This result is always cached until the page is modified. 122 * @see DokuWiki_Syntax_Plugin::handle() 123 * 124 * @param string $match 125 * @param int $state 126 * @param int $pos 127 * @param Doku_Handler $handler 128 * @return array|bool 129 */ 130 function handle($match, $state, $pos, Doku_Handler $handler) 131 { 132 133 switch ($state) { 134 135 case DOKU_LEXER_ENTER: 136 137 // Suppress the tag name 138 $match = utf8_substr($match, strlen(self::getTag()) + 1, -1); 139 $parameters = webcomponent::parseMatch($match); 140 return array($state, $parameters); 141 142 case DOKU_LEXER_UNMATCHED : 143 144 return array($state, $match); 145 146 case DOKU_LEXER_MATCHED : 147 148 $parameters = array(); 149 150 if (preg_match('/' . self::INTERNAL_LINK_PATTERN . '/msSi', $match . DOKU_LF)) { 151 // We have a internal link, we parse it (code form the function internallink in handler.php) 152 // 153 // Strip the opening and closing markup 154 $link = preg_replace(array('/^\[\[/', '/\]\]$/u'), '', $match); 155 156 // Split title from URL 157 $link = explode('|', $link, 2); 158 if (!isset($link[1])) { 159 $link[1] = null; 160 } 161 $link[0] = trim($link[0]); 162 // we expect only a local link 163 $parameters['locallink']['pageid'] = $link[0]; 164 $parameters['locallink']['content'] = $link[1]; 165 166 } 167 168 return array($state, $parameters); 169 170 case DOKU_LEXER_EXIT : 171 172 return array($state, ''); 173 174 175 } 176 177 return array(); 178 179 } 180 181 /** 182 * Render the output 183 * @see DokuWiki_Syntax_Plugin::render() 184 * 185 * @param string $mode 186 * @param Doku_Renderer $renderer 187 * @param array $data - what the function handle() return'ed 188 * @return bool 189 */ 190 function render($mode, Doku_Renderer $renderer, $data) 191 { 192 193 switch ($mode) { 194 195 case 'xhtml': { 196 197 /** @var Doku_Renderer_xhtml $renderer */ 198 199 list($state, $parameters) = $data; 200 switch ($state) { 201 202 case DOKU_LEXER_ENTER : 203 break; 204 205 case DOKU_LEXER_UNMATCHED : 206 207 $renderer->doc .= $renderer->_xmlEntities($parameters); 208 break; 209 210 case DOKU_LEXER_MATCHED: 211 212 if (array_key_exists('locallink', $parameters)) { 213 214 $pageid = $parameters['locallink']['pageid']; 215 $content = $parameters['locallink']['content']; 216 $renderer->doc .= '<a href="' . wl($pageid) . '" class="btn btn-primary">' . $renderer->_xmlEntities($content) . '</a>'; 217 218 } 219 break; 220 case DOKU_LEXER_EXIT : 221 222 break; 223 } 224 return true; 225 } 226 227 case 'metadata': 228 229 /** @var Doku_Renderer_metadata $renderer */ 230 231 list($state, $parameters) = $data; 232 switch ($state) { 233 234 case DOKU_LEXER_MATCHED: 235 236 if (array_key_exists('locallink', $parameters)) { 237 238 // To add the link in the backlinks 239 // See: https://www.dokuwiki.org/devel:syntax_plugins#metadata_renderer 240 $pageIdToLinkTo = $parameters['locallink']['pageid']; 241 $renderer->internallink($pageIdToLinkTo); 242 243 } 244 } 245 } 246 return false; 247 } 248 249 250 public static function getTag() 251 { 252 return webcomponent::getTagName(get_called_class()); 253 } 254 255 public static function getTags() 256 { 257 $elements[] = self::getTag(); 258 $elements[] = 'btn'; 259 return $elements; 260 } 261 262 263} 264