1<?php 2/** 3 * Plugin Icons for DokuWiki 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Giuseppe Di Terlizzi <giuseppe.diterlizzi@gmail.com> 7 * @copyright (C) 2015-2018, Giuseppe Di Terlizzi 8 */ 9 10// must be run within Dokuwiki 11if(!defined('DOKU_INC')) die(); 12 13class syntax_plugin_icons_icon extends DokuWiki_Syntax_Plugin { 14 15 const IS_ICON = null; 16 const IS_FONT_ICON = null; 17 18 protected $pattern = '{{icon>.+?}}'; 19 protected $linkPattern = '\[\[[^\]\r\n]*\|%s\]\]'; 20 21 protected $flags = array(); 22 protected $classes = array(); 23 protected $styles = array(); 24 25 /** 26 * Syntax Type 27 * 28 * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 29 * 30 * @return string 31 */ 32 public function getType() { return 'substition'; } 33 34 /** 35 * Sort for applying this mode 36 * 37 * @return int 38 */ 39 public function getSort() { return 299; } 40 41 /** 42 * @param string $mode 43 */ 44 public function connectTo($mode) { 45 $this->Lexer->addSpecialPattern($this->pattern, $mode, 'plugin_icons_'.$this->getPluginComponent()); 46 $this->Lexer->addSpecialPattern(sprintf($this->linkPattern, $this->pattern), $mode, 'plugin_icons_'.$this->getPluginComponent()); 47 } 48 49 /** 50 * Handler to prepare matched data for the rendering process 51 * 52 * @param string $match The text matched by the patterns 53 * @param int $state The lexer state for the match 54 * @param int $pos The character position of the matched text 55 * @param Doku_Handler $handler The Doku_Handler object 56 * @return bool|array Return an array with all data you want to use in render, false don't add an instruction 57 */ 58 public function handle($match, $state, $pos, Doku_Handler $handler) { 59 60 $url = null; 61 $flags = array(); 62 $title = null; 63 $pack = null; 64 $icon = null; 65 66 $match = substr($match, 2, -2); // strip markup 67 68 @list($match, $title, $title2) = explode('|', $match); 69 70 if (isset($title2)) $title .= '}}'; 71 72 if (isset($title) && preg_match('/'.$this->pattern.'/', $title)) { 73 74 $url = $match; 75 $match = $title; 76 77 $match = substr($match, 2, -2); // strip markup 78 list($match, $title) = explode('|', $match); 79 80 if (isset($title2)) $title = rtrim($title2, '}'); 81 82 } 83 84 $align_left = false; 85 $align_right = false; 86 $align_center = false; 87 $align_flag = ''; 88 89 if (substr($match, 0, 1) == ' ') { 90 $align_right = true; 91 $align_flag = "align=right"; 92 } 93 94 if (substr($match, -1, 1) == ' ') { 95 $align_left = true; 96 $align_flag = "align=left"; 97 } 98 99 if ($align_left && $align_right) { 100 $align_center = true; 101 $align_flag = "align=center"; 102 } 103 104 list($match, $flags) = array_pad(explode('?', trim($match), 2), 2, null); 105 list($pack, $icon) = explode('>', trim($match), 2); 106 107 $flags .= "&$align_flag"; 108 109 return array($pack, $icon, explode('&', rtrim($flags, '&')), $title, $url, $match, $state, $pos); 110 111 } 112 113 /** 114 * Handles the actual output creation. 115 * 116 * @param string $mode output format being rendered 117 * @param Doku_Renderer $renderer the current renderer object 118 * @param array $data data created by handler() 119 * @return boolean rendered correctly? (however, returned value is not used at the moment) 120 */ 121 public function render($mode, Doku_Renderer $renderer, $data) { 122 123 if ($mode !== 'xhtml') return false; 124 125 /** @var Doku_Renderer_xhtml $renderer */ 126 127 list($pack, $icon, $flags, $title, $url) = $data; 128 $this->parseFlags($pack, $icon, $flags); 129 130 if ($this->isIcon()) { 131 132 $icon_size = $this->getFlag('size'); 133 $icon_pack = $this->getFlag('pack'); 134 $icon_base_url = rtrim($this->getConf(sprintf('%sURL', $icon_pack)), '/'); 135 $icon_url = $this->makePath($icon, $icon_size, $icon_base_url); 136 $cached_icon_url = ml($icon_url, array('cache' => 'recache', 'w' => $icon_size, 'h' => $icon_size)); 137 $icon_markup = sprintf('<img src="%s" title="%s" class="%s" style="%s" />', 138 $cached_icon_url, $title, 139 $this->toClassString($this->getClasses()), 140 $this->toInlineStyle($this->getStyles())); 141 142 } else { 143 144 $this->classes[] = $this->getFlag('pack'); 145 $this->classes[] = sprintf('%s-%s', $this->getFlag('pack'), $icon); 146 147 148 $icon_markup = sprintf('<i class="dw-icons %s" style="%s" title="%s"></i>', 149 $this->toClassString($this->getClasses()), 150 $this->toInlineStyle($this->getStyles()), 151 $title); 152 153 154 } 155 156 if (isset($url)) { 157 158 global $conf; 159 global $ID; 160 161 $is_external = false; 162 $exists = false; 163 $link = array(); 164 165 if (preg_match('/^(http?|ftp?|www?)/', $url)) { 166 $is_external = true; 167 } else { 168 resolve_pageid(getNS($ID), $url, $exists); 169 $url = wl($url); 170 } 171 172 $link['target'] = ($is_external) ? $conf['target']['extern'] : $conf['target']['wiki']; 173 $link['style'] = ''; 174 $link['pre'] = ''; 175 $link['suf'] = ''; 176 $link['more'] = ''; 177 $link['class'] = ''; 178 $link['url'] = $url; 179 $link['name'] = $icon_markup; 180 181 if ($exists) { 182 $link['class'] = 'wikilink1'; 183 } else { 184 185 $link['rel'] = 'nofollow'; 186 187 if (! $is_external) { 188 $link['class'] = 'wikilink2'; 189 } 190 191 } 192 193 $renderer->doc .= $renderer->_formatLink($link); 194 return true; 195 196 } 197 198 $renderer->doc .= $icon_markup; 199 return true; 200 201 } 202 203 protected function isIcon() { 204 $class_icon = sprintf('syntax_plugin_icons_%s', $this->getFlag('pack')); 205 return constant("$class_icon::IS_ICON"); 206 } 207 208 protected function isFontIcon() { 209 $class_icon = sprintf('syntax_plugin_icons_%s', $this->getFlag('pack')); 210 return constant("$class_icon::IS_FONT_ICON"); 211 } 212 213 protected function toClassString($things) { 214 return trim(implode(' ', $things), ' '); 215 } 216 217 protected function toInlineStyle($things) { 218 219 $result = ''; 220 221 foreach ($things as $property => $value) { 222 $result .= "$property:$value;"; 223 } 224 225 $result = trim($result, ';'); 226 227 return $result; 228 229 } 230 231 protected function getFlag($name) { 232 return (isset($this->flags[$name]) ? $this->flags[$name] : null); 233 } 234 235 protected function getFlags() { 236 return $this->flags; 237 } 238 239 protected function parseFlags($pack, $icon, $flags) { 240 241 $this->flags = array(); 242 $this->classes = array(); 243 $this->styles = array(); 244 245 $this->flags['pack'] = $pack; 246 $this->flags['icon'] = $icon; 247 248 if ((int) $flags[0] > 0 && ! in_array($flags[0], array('2x', '3x', '4x', '5x'))) { 249 $flags[] = "size=" . $flags[0]; 250 unset($flags[0]); 251 } 252 253 if ($left = array_search('left', $flags)) { 254 $flags[] = 'align=left'; 255 unset($flags[$left]); 256 } 257 258 if ($right = array_search('right', $flags)) { 259 $flags[] = 'align=right'; 260 unset($flags[$right]); 261 } 262 263 if ($center = array_search('center', $flags)) { 264 $flags[] = 'align=center'; 265 unset($flags[$center]); 266 } 267 268 foreach ($flags as $flag) { 269 270 @list($flag, $value) = explode('=', $flag); 271 272 if (! $flag) continue; 273 274 $this->flags[$flag] = $value; 275 276 switch ($flag) { 277 278 case 'size': 279 280 $this->flags[$flag] = (int) $value; 281 282 if ($this->isFontIcon()) { 283 $this->styles['font-size'] = "{$value}px"; 284 } 285 286 break; 287 288 case 'circle': 289 $this->flags[$flag] = true; 290 $this->styles['border-radius'] = '50%'; 291 $this->styles['-moz-border-radius'] = '50%'; 292 $this->styles['-webkit-border-radius'] = '50%'; 293 break; 294 295 case 'border': 296 297 $this->flags[$flag] = true; 298 299 if ($this->flags['pack'] == 'fa') { 300 $this->classes[] = 'fa-border'; 301 } else { 302 $this->styles['border'] = '0.08em solid #EEE'; 303 } 304 305 break; 306 307 case 'borderColor': 308 $this->styles['border-color'] = $value; 309 break; 310 311 case 'padding': 312 $this->styles['padding'] = $value; 313 break; 314 315 case 'background': 316 $this->styles['background-color'] = $value; 317 break; 318 319 case 'color': 320 $this->styles['color'] = $value; 321 break; 322 323 case 'class': 324 $this->classes[] = $value; 325 break; 326 327 case 'align': 328 329 if ($this->isIcon()) { 330 $this->classes[] = "media$value"; 331 } else { 332 333 if ($value == 'center') { 334 $this->styles['text-align'] = 'center'; 335 } else { 336 $this->styles['padding-'.(($value == 'left') ? 'right' : 'left')] = '.2em'; 337 $this->styles['float'] = $value; 338 } 339 340 } 341 342 break; 343 344 case 'rotate': 345 346 if (in_array($value, array(90, 180, 270))) { 347 $this->classes[] = "fa-rotate-$value"; 348 } 349 350 break; 351 352 case 'flip': 353 354 if (in_array($value, array('horizontal', 'vertical'))) { 355 $this->classes[] = "fa-flip-$value"; 356 } 357 358 break; 359 360 case 'pull-left': 361 case 'pullLeft': 362 case 'pull-right': 363 case 'pullRight': 364 case 'spin': 365 case 'pulse': 366 $this->classes[] = "fa-$flag"; 367 break; 368 369 case 'fw': 370 case 'lg': 371 case '2x': 372 case '3x': 373 case '4x': 374 case '5x': 375 376 $this->classes[] = "fa-$flag"; 377 $this->flags['size'] = true; 378 379 unset($this->styles['font-size']); 380 break; 381 382 383 default: 384 $this->classes[] = $flag; 385 386 } 387 388 } 389 390 if (! isset($this->flags['size'])) { 391 392 $this->flags['size'] = (int) $this->getConf('defaultSize'); 393 394 if ($this->isFontIcon()) { 395 $this->styles['font-size'] = $this->getConf('defaultSize') . "px"; 396 } 397 398 } 399 400 if ($this->flags['pack'] == 'icon') { 401 $this->flags['pack'] = $this->getConf('defaultPack'); 402 } 403 404 } 405 406 protected function getStyles() { 407 return $this->styles; 408 } 409 410 protected function getClasses() { 411 return $this->classes; 412 } 413 414 415 public static function makePath($icon, $size, $base_url) { 416 return true; 417 } 418 419} 420