1<?php 2/** 3 * Mikio Core Syntax Plugin 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author James Collins <james.collins@outlook.com.au> 7 */ 8 9if (!defined('DOKU_INC')) die(); 10if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 11 12 13class syntax_plugin_mikioplugin_core extends DokuWiki_Syntax_Plugin { 14 public $pattern_entry = ''; 15 public $pattern = ''; 16 public $pattern_exit = ''; 17 public $tag = ''; 18 public $noEndTag = false; 19 public $defaults = array(); 20 public $options = array(); 21 public $privateOptions = false; 22 public $values = array(); 23 public $incClasses = array('shadow', 'shadow-none', 'shadow-sm', 'shadow-lg', 'w-25', 'w-50', 'w-75', 'w-100', 'w-auto', 'h-25', 'h-50', 'h-75', 'h-100', 'h-auto', 'text-left', 'text-center', 'text-right', 'text-justify', 'text-wrap', 'text-nowrap', 'text-truncate', 'text-break', 'text-lowercase', 'text-uppercase', 'text-capitalize', 'font-weight-bold', 'font-weight-bolder', 'font-weight-normal', 'font-weight-light', 'font-weight-lighter', 'font-italic', 'text-monospace', 'text-reset', 'text-muted', 'text-decoration-none', 'text-primary', 'text-secondary', 'text-success', 'text-danger', 'text-warning', 'text-info', 'text-light'. 'text-dark', 'text-body', 'text-white', 'text-black', 'text-white-50', 'text-black-50', 'bg-primary', 'bg-secondary', 'bg-success', 'bg-danger', 'bg-warning', 'bg-info', 'bg-light', 'bg-dark', 'bg-white', 'bg-transparent', 'border', 'border-top', 'border-right', 'border-bottom', 'border-left', 'border-0', 'border-top-0', 'border-right-0', 'border-bottom-0', 'border-left-0', 'border-primary', 'border-secondary', 'border-success', 'border-danger', 'border-warning', 'border-info', 'border-light', 'border-dark', 'border-white', 'rounded', 'rounded-top', 'rounded-right', 'rounded-bottom', 'rounded-left', 'rounded-circle', 'rounded-pill', 'rounded-0', 'rounded-sm', 'rounded-lg', 'clearfix', 'align-baseline', 'align-top', 'align-middle', 'align-bottom', 'align-text-top', 'align-text-bottom', 'sm-1', 'sm-2', 'sm-3', 'sm-4', 'sm-5', 'sm-6', 'sm-7', 'sm-8', 'sm-9', 'sm-10', 'sm-11', 'sm-12', 'md-1', 'md-2', 'md-3', 'md-4', 'md-5', 'md-6', 'md-7', 'md-8', 'md-9', 'md-10', 'md-11', 'md-12', 'lg-1', 'lg-2', 'lg-3', 'lg-4', 'lg-5', 'lg-6', 'lg-7', 'lg-8', 'lg-9', 'lg-10', 'lg-11', 'lg-12'); 24 public $incOptions = array('width', 'min-width', 'max-width', 'height', 'min-height', 'max-height', 'overflow', 'tooltip', 'tooltip-html', 'tooltop-left', 'tooltip-top', 'tooltip-right', 'tooltip-bottom', 'tooltip-html-top', 'tooltip-html-left', 'tooltip-html-right', 'tooltip-html-bottom'); 25 26 27 function __construct() { 28 if($this->tag != '') { 29 if(count($this->incClasses) > 0 && !$this->privateOptions) { 30 $this->options = array_merge($this->options, $this->incClasses, $this->incOptions); 31 } 32 } 33 } 34 35 public function getType() { 36 return 'formatting'; 37 } 38 39 40 public function getAllowedTypes() { return array('formatting', 'substition', 'disabled'); } 41 public function getSort(){ return 32; } 42 43 44 public function connectTo($mode) { 45 if($this->pattern_entry == '' && $this->tag != '') { 46 if($this->noEndTag) { 47 $this->pattern_entry = '<(?:' . strtoupper($this->tag) . '|' . strtolower($this->tag) . ').*?>'; 48 } else { 49 $this->pattern_entry = '<(?:' . strtoupper($this->tag) . '|' . strtolower($this->tag) . ')(?=[ >]).*?>(?=.*?</(?:' . strtoupper($this->tag) . '|' . strtolower($this->tag) . ')>)'; 50 } 51 } 52 53 if($this->pattern_entry != '') { 54 if($this->noEndTag) { 55 $this->Lexer->addSpecialPattern($this->pattern_entry, $mode, 'plugin_mikioplugin_'.$this->getPluginComponent()); 56 } else { 57 $this->Lexer->addEntryPattern($this->pattern_entry, $mode, 'plugin_mikioplugin_'.$this->getPluginComponent()); 58 } 59 } 60 61 // if($this->pattern != '') { 62 // $this->Lexer->addPattern($this->pattern, 'plugin_mikioplugin_'.$this->getPluginComponent()); 63 // } 64 } 65 66 67 public function postConnect() { 68 if(!$this->noEndTag) { 69 if($this->pattern_exit == '' && $this->tag != '') { 70 $this->pattern_exit = '</(?:' . strtoupper($this->tag) . '|' . strtolower($this->tag) . ')>'; 71 } 72 73 if($this->pattern_exit != '') { 74 $this->Lexer->addExitPattern($this->pattern_exit, 'plugin_mikioplugin_'.$this->getPluginComponent()); 75 } 76 } 77 } 78 79 public function handle($match, $state, $pos, Doku_Handler $handler){ 80 if($this->tag == '') return array($state, $match); 81 82 switch($state) { 83 case DOKU_LEXER_ENTER: 84 case DOKU_LEXER_SPECIAL: 85 $optionlist = preg_split('/\s(?=([^"]*"[^"]*")*[^"]*$)/', substr($match, strlen($this->tag) + 1, -1)); 86 87 $options = array(); 88 foreach($optionlist as $item) { 89 $i = strpos($item, '='); 90 if($i !== false) { 91 $value = substr($item, $i + 1); 92 93 if(substr($value, 0, 1) == '"') $value = substr($value, 1); 94 if(substr($value, -1) == '"') $value = substr($value, 0, -1); 95 96 $options[substr($item, 0, $i)] = $value; 97 } else { 98 $options[$item] = true; 99 } 100 } 101 102 $options_clean = $this->cleanOptions($options); 103 104 $this->values = $options_clean; 105 106 return array($state, $options_clean); 107 108 case DOKU_LEXER_MATCHED: 109 return array($state, $match); 110 111 case DOKU_LEXER_UNMATCHED: 112 return array($state, $match); 113 114 case DOKU_LEXER_EXIT: 115 return array($state, $this->values); 116 } 117 118 return array(); 119 } 120 121 122 public function cleanOptions($options) { 123 $options_clean = array(); 124 125 if(!$this->privateOptions) { 126 foreach($this->options as $item => $value) { 127 if(is_string($value)) { 128 if(array_key_exists($value, $options)) { 129 $options_clean[$value] = $options[$value]; 130 } else { 131 $options_clean[$value] = false; 132 } 133 } else if(is_array($value)) { 134 foreach($value as $avalue) { 135 if(array_key_exists($avalue, $options)) { 136 $options_clean[$item] = $avalue; 137 } 138 } 139 } 140 } 141 142 foreach($this->defaults as $item => $value) { 143 if(array_key_exists($item, $options_clean) == false) { 144 $options_clean[$item] = $value; 145 } 146 } 147 } else { 148 $options_clean = $options; 149 array_shift($options_clean); 150 } 151 152 return $options_clean; 153 } 154 155 156 public function render_lexer_enter(Doku_Renderer $renderer, $data) { 157 158 } 159 160 161 public function render_lexer_unmatched(Doku_Renderer $renderer, $data) { 162 $renderer->doc .= $renderer->_xmlEntities($data); 163 } 164 165 166 public function render_lexer_exit(Doku_Renderer $renderer, $data) { 167 168 } 169 170 171 public function render_lexer_special(Doku_Renderer $renderer, $data) { 172 173 } 174 175 176 public function render_lexer_match(Doku_Renderer $renderer, $data) { 177 178 } 179 180 181 public function render($mode, Doku_Renderer $renderer, $data) { 182 if($mode == 'xhtml'){ 183 list($state,$match) = $data; 184 185 switch ($state) { 186 case DOKU_LEXER_ENTER: 187 $this->render_lexer_enter($renderer, $match); 188 return true; 189 190 case DOKU_LEXER_UNMATCHED : 191 $this->render_lexer_unmatched($renderer, $match); 192 return true; 193 194 case DOKU_LEXER_MATCHED: 195 $this->render_lexer_match($renderer, $match); 196 return true; 197 198 case DOKU_LEXER_EXIT : 199 $this->render_lexer_exit($renderer, $match); 200 return true; 201 202 case DOKU_LEXER_SPECIAL: 203 $this->render_lexer_special($renderer, $match); 204 return true; 205 } 206 207 return true; 208 } 209 210 return false; 211 } 212 213 214 public function buildClassString($options=null, $classes=null, $prefix='') { 215 $s = array(); 216 217 if($options != null) { 218 if($classes != null) { 219 foreach($classes as $item) { 220 if(array_key_exists($item, $options) && $options[$item] !== false) { 221 $classname = $item; 222 223 if(is_string($options[$item])) { 224 $classname = $options[$item]; 225 } 226 227 if(is_string($prefix)) { 228 $classname = $prefix . $classname; 229 } else if(is_array($prefix)) { 230 foreach($prefix as $pitem => $pvalue) { 231 if(is_string($pvalue)) { 232 if($pvalue == $item) { 233 if(is_string($options[$item])) { 234 $classname = $pitem . $options[$item]; 235 } else { 236 $classname = $pitem . $item; 237 } 238 } 239 } 240 241 if(is_array($pvalue)) { 242 foreach($pvalue as $ppitem) { 243 if($ppitem == $item) { 244 if(is_string($options[$item])) { 245 $classname = $pitem . $options[$item]; 246 } else { 247 $classname = $pitem . $item; 248 } 249 } 250 } 251 } 252 } 253 } 254 255 $s[] = $classname; 256 } 257 } 258 } 259 260 foreach($this->incClasses as $item => $value) { 261 if(array_key_exists($value, $options) && $options[$value] == true) { 262 $pre = substr($value, 0, 3); 263 if($pre == 'sm-' || $pre == 'md-' || $pre == 'lg-') $value = 'col-' . $value; 264 265 $s[] = $value; 266 } 267 } 268 } 269 270 $s = ' ' . implode(' ', $s); 271 return $s; 272 } 273 274 public function buildStyleString($options, $ignore=null, $append='') { 275 $s = array(); 276 277 if($options != null) { 278 foreach($options as $item => $value) { 279 if($value != false && ($ignore == null || (is_string($ignore) && $ignore != $item) || (is_array($ignore) && in_array($item, $ignore) == false))) { 280 switch($item) { 281 case 'width': 282 $s[] = 'width:' . $value; 283 break; 284 case 'height': 285 $s[] = 'height:' . $value; 286 break; 287 case 'min-width': 288 $s[] = 'min-width:' . $value; 289 break; 290 case 'min-height': 291 $s[] = 'min-height:' . $value; 292 break; 293 case 'max-width': 294 $s[] = 'max-width:' . $value; 295 break; 296 case 'max-height': 297 $s[] = 'max-height:' . $value; 298 break; 299 case 'overflow': 300 $s[] = 'overflow:' . $value; 301 break; 302 } 303 } 304 } 305 } 306 307 $s = implode(';', $s) . '; ' . $append; 308 309 if($s != '') $s = ' style="' . $s . '" '; 310 311 return $s; 312 } 313 314 public function buildTooltipString($options) { 315 $dataPlacement = 'top'; 316 $dataHtml = false; 317 $title = ''; 318 319 if($options != null) { 320 if(array_key_exists('tooltip-html-top', $options) && $options['tooltip-html-top'] != '') { 321 $title = $options['tooltip-html-top']; 322 $dataPlacement = 'top'; 323 } 324 325 if(array_key_exists('tooltip-html-left', $options) && $options['tooltip-html-left'] != '') { 326 $title = $options['tooltip-html-left']; 327 $dataPlacement = 'left'; 328 } 329 330 if(array_key_exists('tooltip-html-bottom', $options) && $options['tooltip-html-bottom'] != '') { 331 $title = $options['tooltip-html-bottom']; 332 $dataPlacement = 'bottom'; 333 } 334 335 if(array_key_exists('tooltip-html-right', $options) && $options['tooltip-html-right'] != '') { 336 $title = $options['tooltip-html-right']; 337 $dataPlacement = 'right'; 338 } 339 340 if(array_key_exists('tooltip-top', $options) && $options['tooltip-top'] != '') { 341 $title = $options['tooltip-top']; 342 $dataPlacement = 'top'; 343 } 344 345 if(array_key_exists('tooltip-left', $options) && $options['tooltip-left'] != '') { 346 $title = $options['tooltip-left']; 347 $dataPlacement = 'left'; 348 } 349 350 if(array_key_exists('tooltip-bottom', $options) && $options['tooltip-bottom'] != '') { 351 $title = $options['tooltip-bottom']; 352 $dataPlacement = 'bottom'; 353 } 354 355 if(array_key_exists('tooltip-right', $options) && $options['tooltip-right'] != '') { 356 $title = $options['tooltip-right']; 357 $dataPlacement = 'right'; 358 } 359 360 if(array_key_exists('tooltip-html', $options) && $options['tooltip-html'] != '') { 361 $title = $options['tooltip-html']; 362 $dataPlacement = 'top'; 363 } 364 365 if(array_key_exists('tooltip', $options) && $options['tooltip'] != '') { 366 $title = $options['tooltip']; 367 $dataPlacement = 'top'; 368 } 369 } 370 371 if($title != '') { 372 return ' data-toggle="tooltip" data-placement="' . $dataPlacement . '" ' . ($dataHtml == true ? 'data-html="true" ' : '') . 'title="' . $title . '" '; 373 } 374 375 return ''; 376 } 377 378 public function getMediaFile($str) { 379 $i = strpos($str, '?'); 380 if($i !== false) $str = substr($str, 0, $i); 381 382 $str = preg_replace('/[^\da-zA-Z:_.]+/', '', $str); 383 384 return(tpl_getMediaFile(array($str), false)); 385 } 386 387 388 public function getLink($str) { 389 $i = strpos($str, '://'); 390 if($i !== false) return $str; 391 392 return wl($str); 393 } 394 395 396 public function setAttr(&$attrList, $attr, $data, $newAttrName='', $newAttrVal='') { 397 if(array_key_exists($attr, $data) && $data[$attr] !== false) { 398 $value = $data[$attr]; 399 400 if($newAttrName != '') $attr = $newAttrName; 401 if($newAttrVal != '') { 402 $newAttrVal = str_ireplace('%%VALUE%%', $value, $newAttrVal); 403 if(stripos($newAttrVal, '%%MEDIA%%') !== false) { 404 $newAttrVal = str_ireplace('%%MEDIA%%', $this->getMediaFile($value), $newAttrVal); 405 } 406 407 $value = $newAttrVal; 408 } 409 410 $attrList[$attr] = $value; 411 } 412 } 413 414 415 public function listAttr($attrName, $attrs) { 416 $s = ''; 417 418 if(count($attrs) > 0) { 419 foreach($attrs as $item => $value) { 420 $s .= $item . ':' . $value . ';'; 421 } 422 423 $s = $attrName . '="' . $s . '" '; 424 } 425 426 return $s; 427 } 428 429 430 public function syntaxRender(Doku_Renderer $renderer, $className, $text, $data=null) { 431 $class = new $className; 432 433 if(!is_array($data)) $data = array(); 434 435 $data = $class->cleanOptions($data); 436 $class->values = $data; 437 438 if($class->noEndTag) { 439 $class->render_lexer_special($renderer, $data); 440 } else { 441 $class->render_lexer_enter($renderer, $data); 442 $renderer->doc .= $text; 443 $class->render_lexer_exit($renderer, null); 444 } 445 } 446 447 public function getFirstArrayKey($data) { 448 if(!function_exists('array_key_first')) { 449 foreach($data as $key => $unused) { 450 return $key; 451 } 452 } 453 454 return array_key_first($data); 455 } 456}