1<?php 2 3/** 4 * Mikio Core Syntax Plugin 5 * 6 * @link http://github.com/nomadjimbob/mikioplugin 7 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 8 * @author James Collins <james.collins@outlook.com.au> 9 */ 10if (!defined('DOKU_INC')) { die(); 11} 12if (!defined('DOKU_PLUGIN')) { define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 13} 14 15require_once(dirname(__FILE__).'/../disabled-tags.php'); 16 17define('MIKIO_LEXER_AUTO', 0); 18define('MIKIO_LEXER_ENTER', 1); 19define('MIKIO_LEXER_EXIT', 2); 20define('MIKIO_LEXER_SPECIAL', 3); 21 22class syntax_plugin_mikioplugin_core extends DokuWiki_Syntax_Plugin 23{ 24 public $pattern_entry = ''; 25 public $pattern = ''; 26 public $pattern_exit = ''; 27 public $tag = ''; 28 public $requires_tag = ''; 29 public $hasEndTag = true; 30 public $options = array(); 31 32 protected $tagPrefix = ''; //'mikio-'; 33 protected $classPrefix = 'mikiop-'; 34 protected $elemClass = 'mikiop'; 35 36 private $values = array(); 37 38 39 function __construct() 40 { 41 } 42 43 public function isDisabled() 44 { 45 global $mikio_disabled_tags; 46 47 if (isset($mikio_disabled_tags) === true) { 48 if(array_key_exists($this->tag, $mikio_disabled_tags) === true && $mikio_disabled_tags[$this->tag] === true) { 49 return true; 50 } 51 52 // check requirements 53 if($this->requires_tag !== '') { 54 if(array_key_exists($this->requires_tag, $mikio_disabled_tags) === true && $mikio_disabled_tags[$this->requires_tag] === true) { 55 return true; 56 } 57 } 58 } 59 60 return false; 61 } 62 63 public function getType() 64 { 65 return 'formatting'; 66 } 67 public function getAllowedTypes() 68 { 69 return array('formatting', 'substition', 'disabled', 'paragraphs'); 70 } 71 // public function getAllowedTypes() { return array('formatting', 'substition', 'disabled'); } 72 public function getSort() 73 { 74 return 32; 75 } 76 public function getPType() 77 { 78 return 'stack'; 79 } 80 81 82 public function connectTo($mode) 83 { 84 if($this->isDisabled() == true) { 85 return; 86 } 87 88 if ($this->pattern_entry == '' && $this->tag != '') { 89 if ($this->hasEndTag) { 90 $this->pattern_entry = '<(?i:' . $this->tagPrefix . $this->tag . ')(?=[ >]).*?>(?=.*?</(?i:' . $this->tagPrefix . $this->tag . ')>)'; 91 } else { 92 $this->pattern_entry = '<(?i:' . $this->tagPrefix . $this->tag . ').*?>'; 93 } 94 } 95 96 if ($this->pattern_entry != '') { 97 if ($this->hasEndTag) { 98 $this->Lexer->addEntryPattern($this->pattern_entry, $mode, 'plugin_mikioplugin_' . $this->getPluginComponent()); 99 } else { 100 $this->Lexer->addSpecialPattern($this->pattern_entry, $mode, 'plugin_mikioplugin_' . $this->getPluginComponent()); 101 } 102 } 103 } 104 105 106 public function postConnect() 107 { 108 if ($this->hasEndTag) { 109 if ($this->pattern_exit == '' && $this->tag != '') { 110 $this->pattern_exit = '</(?i:' . $this->tagPrefix . $this->tag . ')>'; 111 } 112 113 if ($this->pattern_exit != '') { 114 $this->Lexer->addExitPattern($this->pattern_exit, 'plugin_mikioplugin_' . $this->getPluginComponent()); 115 } 116 } 117 } 118 119 public function handle($match, $state, $pos, Doku_Handler $handler) 120 { 121 if($this->isDisabled() != true) { 122 switch ($state) { 123 case DOKU_LEXER_ENTER: 124 case DOKU_LEXER_SPECIAL: 125 $match_fix = preg_replace('/\s*=\s*/', '=', trim(substr($match, strlen($this->tagPrefix . $this->tag) + 1, -1))); 126 $optionlist = preg_split('/\s(?=([^"]*"[^"]*")*[^"]*$)/', $match_fix); 127 128 $options = array(); 129 foreach ($optionlist as $item) { 130 $i = strpos($item, '='); 131 if ($i !== false) { 132 $value = substr($item, $i + 1); 133 134 if (substr($value, 0, 1) == '"') { $value = substr($value, 1); 135 } 136 if (substr($value, -1) == '"') { $value = substr($value, 0, -1); 137 } 138 139 $options[substr($item, 0, $i)] = $value; 140 } else { 141 $options[$item] = true; 142 } 143 } 144 145 if (count($this->options) > 0) { 146 $options_clean = $this->cleanOptions($options); 147 } else { 148 $options_clean = $options; 149 } 150 151 $this->values = $options_clean; 152 153 return array($state, $options_clean); 154 155 case DOKU_LEXER_MATCHED: 156 return array($state, $match); 157 158 case DOKU_LEXER_UNMATCHED: 159 return array($state, $match); 160 161 case DOKU_LEXER_EXIT: 162 return array($state, $this->values); 163 } 164 } 165 166 return array(); 167 } 168 169 170 /* 171 * clean element options to only supported attributes, setting defaults if required 172 * 173 * @param $options options passed to element 174 * @return array of options supported with default set 175 */ 176 protected function cleanOptions($data, $options = null) 177 { 178 $optionsCleaned = array(); 179 180 if ($options == null) { $options = $this->options; 181 } 182 183 // Match DokuWiki passed options to syntax options 184 foreach ($data as $optionKey => $optionValue) { 185 foreach ($options as $syntaxKey => $syntaxValue) { 186 if (strcasecmp($optionKey, $syntaxKey) == 0) { 187 if (array_key_exists('type', $options[$syntaxKey])) { 188 $type = $options[$syntaxKey]['type']; 189 190 switch ($type) { 191 case 'boolean': 192 $optionsCleaned[$syntaxKey] = filter_var($optionValue, FILTER_VALIDATE_BOOLEAN); 193 break; 194 case 'number': 195 $optionsCleaned[$syntaxKey] = filter_var($optionValue, FILTER_VALIDATE_INT); 196 break; 197 case 'float': 198 $optionsCleaned[$syntaxKey] = filter_var($optionValue, FILTER_VALIDATE_FLOAT); 199 break; 200 case 'text': 201 $optionsCleaned[$syntaxKey] = $optionValue; 202 break; 203 case 'size': 204 $s = strtolower($optionValue); 205 $i = ''; 206 if (substr($s, -3) == 'rem') { 207 $i = substr($s, 0, -3); 208 $s = 'rem'; 209 } elseif (substr($s, -2) == 'em') { 210 $i = substr($s, 0, -2); 211 $s = 'em'; 212 } elseif (substr($s, -2) == 'px') { 213 $i = substr($s, 0, -2); 214 $s = 'px'; 215 } elseif (substr($s, -1) == '%') { 216 $i = substr($s, 0, -1); 217 $s = '%'; 218 } else { 219 if ($s != 'auto') { 220 $i = filter_var($s, FILTER_VALIDATE_INT); 221 if ($i == '') { $i = '1'; 222 } 223 $s = 'rem'; 224 } 225 } 226 227 $optionsCleaned[$syntaxKey] = $i . $s; 228 break; 229 case 'multisize': 230 $val = ''; 231 $parts = explode(' ', $optionValue); 232 foreach ($parts as &$part) { 233 $s = strtolower($part); 234 $i = ''; 235 if (substr($s, -3) == 'rem') { 236 $i = substr($s, 0, -3); 237 $s = 'rem'; 238 } elseif (substr($s, -2) == 'em') { 239 $i = substr($s, 0, -2); 240 $s = 'em'; 241 } elseif (substr($s, -2) == 'px') { 242 $i = substr($s, 0, -2); 243 $s = 'px'; 244 } elseif (substr($s, -2) == 'fr') { 245 $i = substr($s, 0, -2); 246 $s = 'fr'; 247 } elseif (substr($s, -1) == '%') { 248 $i = substr($s, 0, -1); 249 $s = '%'; 250 } else { 251 if ($s != 'auto') { 252 $i = filter_var($s, FILTER_VALIDATE_INT); 253 if ($i === '') { $i = '1'; 254 } 255 if ($i != 0) { 256 $s = 'rem'; 257 } else { 258 $s = ''; 259 } 260 } 261 } 262 263 $part = $i . $s; 264 } 265 266 $optionsCleaned[$syntaxKey] = implode(' ', $parts); 267 break; 268 case 'color': 269 if (strlen($optionValue) == 3 || strlen($optionValue) == 6) { 270 preg_match('/([[:xdigit:]]{3}){1,2}/', $optionValue, $matches); 271 if (count($matches) > 1) { 272 $optionsCleaned[$syntaxKey] = '#' . $matches[0]; 273 } else { 274 $optionsCleaned[$syntaxKey] = $optionValue; 275 } 276 } else { 277 $optionsCleaned[$syntaxKey] = $optionValue; 278 } 279 break; 280 case 'url': 281 $optionsCleaned[$syntaxKey] = $this->buildLink($optionValue); 282 break; 283 case 'media': 284 $optionsCleaned[$syntaxKey] = $this->buildMediaLink($optionValue); 285 break; 286 case 'choice': 287 if (array_key_exists('data', $options[$syntaxKey])) { 288 foreach ($options[$syntaxKey]['data'] as $choiceKey => $choiceValue) { 289 if (strcasecmp($optionValue, $choiceKey) == 0) { 290 $optionsCleaned[$syntaxKey] = $choiceKey; 291 break; 292 } 293 294 if (is_array($choiceValue)) { 295 foreach ($choiceValue as $choiceItem) { 296 if (strcasecmp($optionValue, $choiceItem) == 0) { 297 $optionsCleaned[$syntaxKey] = $choiceKey; 298 break 2; 299 } 300 } 301 } else { 302 if (strcasecmp($optionValue, $choiceValue) == 0) { 303 $optionsCleaned[$syntaxKey] = $choiceValue; 304 break; 305 } 306 } 307 } 308 } 309 break; 310 case 'set': 311 if (array_key_exists('option', $options[$syntaxKey]) && array_key_exists('data', $options[$syntaxKey])) { 312 $optionsCleaned[$options[$syntaxKey]['option']] = $options[$syntaxKey]['data']; 313 } 314 break; 315 } 316 } 317 318 break; 319 } 320 } 321 } 322 323 $customStyles = []; 324 325 foreach ($data as $optionKey => $optionValue) { 326 if (!array_key_exists($optionKey, $optionsCleaned)) { 327 if($optionValue === true && $this->customStyleExists($optionKey)) { 328 array_push($customStyles, $optionKey); 329 } 330 331 foreach ($options as $syntaxKey => $syntaxValue) { 332 if (array_key_exists('type', $options[$syntaxKey])) { 333 if (array_key_exists('data', $options[$syntaxKey]) && is_array($options[$syntaxKey]['data'])) { 334 foreach ($options[$syntaxKey]['data'] as $choiceKey => $choiceValue) { 335 if (is_array($choiceValue)) { 336 if (in_array($optionKey, $choiceValue)) { 337 $optionsCleaned[$syntaxKey] = $choiceKey; 338 } 339 } else { 340 if (strcasecmp($choiceValue, $optionKey) == 0) { 341 $optionsCleaned[$syntaxKey] = $choiceValue; 342 } 343 } 344 } 345 } 346 } 347 } 348 } 349 } 350 351 if(array_key_exists('type', $options) === true 352 && array_key_exists('type', $optionsCleaned) === false 353 && count($customStyles) > 0) { 354 $optionsCleaned['type'] = $customStyles[0]; 355 } 356 357 // Add in syntax options that are missing 358 foreach ($options as $optionKey => $optionValue) { 359 if (!array_key_exists($optionKey, $optionsCleaned)) { 360 if (array_key_exists('default', $options[$optionKey])) { 361 switch ($options[$optionKey]['type']) { 362 case 'boolean': 363 $optionsCleaned[$optionKey] = filter_var($options[$optionKey]['default'], FILTER_VALIDATE_BOOLEAN); 364 break; 365 case 'number': 366 $optionsCleaned[$optionKey] = filter_var($options[$optionKey]['default'], FILTER_VALIDATE_INT); 367 break; 368 default: 369 $optionsCleaned[$optionKey] = $options[$optionKey]['default']; 370 break; 371 } 372 } 373 } 374 } 375 376 return $optionsCleaned; 377 } 378 379 /* Lexer renderers */ 380 protected function render_lexer_enter(Doku_Renderer $renderer, $data) 381 { 382 } 383 protected function render_lexer_unmatched(Doku_Renderer $renderer, $data) 384 { 385 $renderer->doc .= $renderer->_xmlEntities($data); 386 } 387 protected function render_lexer_exit(Doku_Renderer $renderer, $data) 388 { 389 } 390 protected function render_lexer_special(Doku_Renderer $renderer, $data) 391 { 392 } 393 protected function render_lexer_match(Doku_Renderer $renderer, $data) 394 { 395 } 396 397 /* Renderer */ 398 public function render($mode, Doku_Renderer $renderer, $data) 399 { 400 if ($mode == 'xhtml' && $this->isDisabled() != true) { 401 list($state, $match) = $data; 402 403 switch ($state) { 404 case DOKU_LEXER_ENTER: 405 $this->render_lexer_enter($renderer, $match); 406 return true; 407 408 case DOKU_LEXER_UNMATCHED: 409 $this->render_lexer_unmatched($renderer, $match); 410 return true; 411 412 case DOKU_LEXER_MATCHED: 413 $this->render_lexer_match($renderer, $match); 414 return true; 415 416 case DOKU_LEXER_EXIT: 417 $this->render_lexer_exit($renderer, $match); 418 return true; 419 420 case DOKU_LEXER_SPECIAL: 421 $this->render_lexer_special($renderer, $match); 422 return true; 423 } 424 425 return true; 426 } 427 428 return false; 429 } 430 431 /* 432 * return a class list with mikiop- prefix 433 * 434 * @param $options options of syntax element. Options with key 'class'=true are automatically added 435 * @param $classes classes to build from options as array 436 * @param $inclAttr include class="" in the return string 437 * @param $optionsTemplate allow a different options template instead of $this->options (for findTags) 438 * @return a string of classes from options/classes variable 439 */ 440 public function buildClass($options = null, $classes = null, $inclAttr = false, $optionsTemplate = null) 441 { 442 $s = array(); 443 444 if (is_array($options)) { 445 if ($classes == null) { $classes = array(); 446 } 447 if ($optionsTemplate == null) { $optionsTemplate = $this->options; 448 } 449 450 foreach ($optionsTemplate as $key => $value) { 451 if (array_key_exists('class', $value) && $value['class'] == true) { 452 array_push($classes, $key); 453 } 454 } 455 456 foreach ($classes as $class) { 457 if (array_key_exists($class, $options) && $options[$class] !== false && $options[$class] != '') { 458 $prefix = $this->classPrefix; 459 460 if (array_key_exists($class, $optionsTemplate) && array_key_exists('prefix', $optionsTemplate[$class])) { 461 $prefix .= $optionsTemplate[$class]['prefix']; 462 } 463 464 if (array_key_exists($class, $optionsTemplate) && array_key_exists('classNoSuffix', $optionsTemplate[$class]) && $optionsTemplate[$class]['classNoSuffix'] == true) { 465 $s[] = $prefix . $class; 466 } else { 467 $s[] = $prefix . $class . ($options[$class] !== true ? '-' . $options[$class] : ''); 468 } 469 } 470 } 471 } 472 473 $s = implode(' ', $s); 474 if ($s != '') { $s = ' ' . $s; 475 } 476 477 if ($inclAttr) { $s = ' classes="' . $s . '"'; 478 } 479 480 return $s; 481 } 482 483 484 485 486 /* 487 * build style string 488 * 489 * @param $list style list as key => value. Empty values are not included 490 * @param $inclAttr include style="" in the return string 491 * @return style list string 492 */ 493 public function buildStyle($list, $inclAttr = false) 494 { 495 $s = ''; 496 497 if (is_array($list) && count($list) > 0) { 498 // expand text-decoration 499 if(array_key_exists('text-decoration', $list)) { 500 // Define the possible values for each property 501 $decorations = array('underline', 'overline', 'line-through'); 502 $styles = array('solid', 'double', 'dotted', 'dashed', 'wavy'); 503 // Split the shorthand string into parts 504 $parts = explode(' ', $list['text-decoration']); 505 506 // Initialize the variables to hold the property values 507 $decoration = ''; 508 $style = ''; 509 $color = ''; 510 $thickness = ''; 511 512 // Process each part of the shorthand string 513 foreach ($parts as $part) { 514 if (in_array($part, $decorations)) { 515 $decoration = $part; 516 } elseif (in_array($part, $styles)) { 517 $style = $part; 518 } elseif (preg_match('/^\d+(px|em|rem|%)$/', $part)) { 519 $thickness = $part; 520 } elseif (preg_match('/^#[0-9a-fA-F]{6}$|^[a-zA-Z]+$/', $part)) { 521 $color = $part; 522 } 523 } 524 525 // Build the completed style string 526 unset($list['text-decoration']); 527 if ($decoration) $list['text-decoration'] = trim($decoration); 528 if ($style) $list['text-decoration-style'] = trim($style); 529 if ($color) $list['text-decoration-color'] = trim($color); 530 if ($thickness) $list['text-decoration-thickness'] = trim($thickness); 531 } 532 533 foreach ($list as $key => $value) { 534 if ($value != '') { 535 $s .= $key . ':' . $value . ';'; 536 } 537 } 538 } 539 540 if ($s != '' && $inclAttr) { 541 $s = ' style="' . $s . '"'; 542 } 543 544 return $s; 545 } 546 547 548 public function buildTooltipString($options) 549 { 550 $dataPlacement = 'top'; 551 $dataHtml = false; 552 $title = ''; 553 554 if ($options != null) { 555 if (array_key_exists('tooltip-html-top', $options) && $options['tooltip-html-top'] != '') { 556 $title = $options['tooltip-html-top']; 557 $dataPlacement = 'top'; 558 } 559 560 if (array_key_exists('tooltip-html-left', $options) && $options['tooltip-html-left'] != '') { 561 $title = $options['tooltip-html-left']; 562 $dataPlacement = 'left'; 563 } 564 565 if (array_key_exists('tooltip-html-bottom', $options) && $options['tooltip-html-bottom'] != '') { 566 $title = $options['tooltip-html-bottom']; 567 $dataPlacement = 'bottom'; 568 } 569 570 if (array_key_exists('tooltip-html-right', $options) && $options['tooltip-html-right'] != '') { 571 $title = $options['tooltip-html-right']; 572 $dataPlacement = 'right'; 573 } 574 575 if (array_key_exists('tooltip-top', $options) && $options['tooltip-top'] != '') { 576 $title = $options['tooltip-top']; 577 $dataPlacement = 'top'; 578 } 579 580 if (array_key_exists('tooltip-left', $options) && $options['tooltip-left'] != '') { 581 $title = $options['tooltip-left']; 582 $dataPlacement = 'left'; 583 } 584 585 if (array_key_exists('tooltip-bottom', $options) && $options['tooltip-bottom'] != '') { 586 $title = $options['tooltip-bottom']; 587 $dataPlacement = 'bottom'; 588 } 589 590 if (array_key_exists('tooltip-right', $options) && $options['tooltip-right'] != '') { 591 $title = $options['tooltip-right']; 592 $dataPlacement = 'right'; 593 } 594 595 if (array_key_exists('tooltip-html', $options) && $options['tooltip-html'] != '') { 596 $title = $options['tooltip-html']; 597 $dataPlacement = 'top'; 598 } 599 600 if (array_key_exists('tooltip', $options) && $options['tooltip'] != '') { 601 $title = $options['tooltip']; 602 $dataPlacement = 'top'; 603 } 604 } 605 606 if ($title != '') { 607 return ' data-toggle="tooltip" data-placement="' . $dataPlacement . '" ' . ($dataHtml == true ? 'data-html="true" ' : '') . 'title="' . $title . '" '; 608 } 609 610 return ''; 611 } 612 613 /* 614 * convert the URL to a DokuWiki media link (if required) 615 * 616 * @param $url url to parse 617 * @return url string 618 */ 619 public function buildMediaLink($url) 620 { 621 $i = strpos($url, '?'); 622 if ($i !== false) { $url = substr($url, 0, $i); 623 } 624 625 $url = preg_replace('/[^\da-zA-Z:_.-]+/', '', $url); 626 627 return (tpl_getMediaFile(array($url), false)); 628 } 629 630 631 /* 632 * returns either a url or dokuwiki link 633 * 634 * @param $url link to build from 635 * @return built link 636 */ 637 public function buildLink($url) 638 { 639 $i = strpos($url, '://'); 640 if ($i !== false || substr($url, 0, 1) == '#') { return $url; 641 } 642 643 return wl($url); 644 } 645 646 /* 647 * Call syntax renderer of mikio syntax plugin 648 * 649 * @param $renderer DokuWiki renderer object 650 * @param $className mikio syntax class to call 651 * @param $text unmatched text to pass outside of lexer. Only used when $lexer=MIKIO_LEXER_AUTO 652 * @param $data tag options to pass to syntax class. Runs through cleanOptions to validate first 653 * @param $lexer which lexer to call 654 */ 655 public function syntaxRender(Doku_Renderer $renderer, $className, $text, $data = null, $lexer = MIKIO_LEXER_AUTO) 656 { 657 $className = 'syntax_plugin_mikioplugin_' . str_replace('-', '', $className); 658 659 if (class_exists($className)) { 660 $class = new $className; 661 662 if (!is_array($data)) { $data = array(); 663 } 664 665 666 if (count($class->options) > 0) { 667 $data = $class->cleanOptions($data, $class->options); 668 } 669 670 switch ($lexer) { 671 case MIKIO_LEXER_AUTO: 672 if ($class->hasEndTag) { 673 if (method_exists($class, 'render_lexer_enter')) { $class->render_lexer_enter($renderer, $data); 674 } 675 $renderer->doc .= $text; 676 if (method_exists($class, 'render_lexer_exit')) { $class->render_lexer_exit($renderer, $data); 677 } 678 } else { 679 if (method_exists($class, 'render_lexer_special')) { $class->render_lexer_special($renderer, $data); 680 } 681 } 682 683 break; 684 case MIKIO_LEXER_ENTER: 685 if (method_exists($class, 'render_lexer_enter')) { $class->render_lexer_enter($renderer, $data); 686 } 687 break; 688 case MIKIO_LEXER_EXIT: 689 if (method_exists($class, 'render_lexer_exit')) { $class->render_lexer_exit($renderer, $data); 690 } 691 break; 692 case MIKIO_LEXER_SPECIAL: 693 if (method_exists($class, 'render_lexer_special')) { $class->render_lexer_special($renderer, $data); 694 } 695 break; 696 } 697 } 698 } 699 700 701 protected function callMikioTag($className, $data) 702 { 703 // $className = 'syntax_plugin_mikioplugin_'.$className; 704 705 706 // if(class_exists($className)) { 707 //$class = new $className; 708 if (!plugin_isdisabled('mikioplugin')) { 709 $class = plugin_load('syntax', 'mikioplugin_' . $className); 710 // echo '^^'.$className.'^^'; 711 712 713 if (method_exists($class, 'mikioCall')) { return $class->mikioCall($data); 714 } 715 } 716 717 // } 718 719 return ''; 720 } 721 722 723 protected function callMikioOptionDefault($className, $option) 724 { 725 $className = 'syntax_plugin_mikioplugin_' . $className; 726 727 if (class_exists($className)) { 728 $class = new $className; 729 730 if (array_key_exists($option, $class->options) && array_key_exists('default', $class->options[$option])) { 731 return $class->options[$option]['default']; 732 } 733 } 734 735 return ''; 736 } 737 738 739 protected function buildTooltip($text) 740 { 741 if ($text != '') { 742 return ' data-tooltip="' . $text . '"'; 743 } 744 745 return ''; 746 } 747 748 /* 749 * Create array with passed elements and include them if their values are not empty 750 * 751 * @param ... array items 752 */ 753 protected function arrayRemoveEmpties($items) 754 { 755 $result = array(); 756 757 foreach ($items as $key => $value) { 758 if ($value != '') { 759 $result[$key] = $value; 760 } 761 } 762 763 return $result; 764 } 765 766 public function getFirstArrayKey($data) 767 { 768 if (!function_exists('array_key_first')) { 769 foreach ($data as $key => $unused) { 770 return $key; 771 } 772 } 773 774 return array_key_first($data); 775 } 776 777 778 /* 779 * add common options to options 780 * 781 * @param $typelist common option to add 782 * @param $options save in options 783 */ 784 public function addCommonOptions($typelist) 785 { 786 $types = explode(' ', $typelist); 787 foreach ($types as $type) { 788 if (strcasecmp($type, 'shadow') == 0) { 789 $this->options['shadow'] = array( 790 'type' => 'choice', 791 'data' => array('large' => array('shadow-large', 'shadow-lg'), 'small' => array('shadow-small', 'shadow-sm'), true), 792 'default' => '', 793 'class' => true 794 ); 795 } 796 797 if (strcasecmp($type, 'width') == 0) { 798 $this->options['width'] = array( 799 'type' => 'size', 800 'default' => '' 801 ); 802 } 803 804 if (strcasecmp($type, 'height') == 0) { 805 $this->options['height'] = array( 806 'type' => 'size', 807 'default' => '' 808 ); 809 } 810 811 if (strcasecmp($type, 'text-color') == 0) { 812 $this->options['text-color'] = array( 813 'type' => 'color', 814 'default' => '' 815 ); 816 } 817 818 if (strcasecmp($type, 'type') == 0) { 819 $this->options['type'] = array( 820 'type' => 'text', 821 'data' => array('primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark', 'outline-primary', 'outline-secondary', 'outline-success', 'outline-danger', 'outline-warning', 'outline-info', 'outline-light', 'outline-dark'), 822 'default' => '', 823 'class' => true 824 ); 825 } 826 827 if (strcasecmp($type, 'text-align') == 0) { 828 $this->options['text-align'] = array( 829 'type' => 'choice', 830 'data' => array('left' => array('text-left'), 'center' => array('text-center'), 'right' => array('text-right')), 831 'default' => '', 832 'class' => true 833 ); 834 } 835 836 if (strcasecmp($type, 'align') == 0) { 837 $this->options['align'] = array( 838 'type' => 'choice', 839 'data' => array('left' => array('align-left'), 'center' => array('align-center'), 'right' => array('align-right')), 840 'default' => '', 841 'class' => true 842 ); 843 } 844 845 if (strcasecmp($type, 'tooltip') == 0) { 846 $this->options['tooltip'] = array( 847 'type' => 'text', 848 'default' => '', 849 'class' => true, 850 'classNoSuffix' => true 851 ); 852 } 853 854 if (strcasecmp($type, 'vertical-align') == 0) { 855 $this->options['vertical-align'] = array( 856 'type' => 'choice', 857 'data' => array('top' => array('align-top'), 'middle' => array('align-middle'), 'bottom' => array('align-bottom')), 858 'default' => '', 859 'class' => true 860 ); 861 } 862 863 if (strcasecmp($type, 'links-match') == 0) { 864 $this->options['links-match'] = array( 865 'type' => 'boolean', 866 'default' => 'false', 867 'class' => true 868 ); 869 } 870 } 871 } 872 873 874 /* 875 * Find HTML tags in string. Parse tags options. Used in parsing subtags 876 * 877 * @param $tagName tagName to search for. Name is exclusive 878 * @param $content search within content 879 * @param $options parse options similar to syntax element options 880 * @param $hasEndTag tagName search also looks for an end tag 881 * @return array of tags containing 'options' => array of 'name' => 'value', 'content' => content inside the tag 882 */ 883 protected function findTags($tagName, $content, $options, $hasEndTag = true) 884 { 885 $items = array(); 886 $search = '/<(?i:' . $tagName . ')(.*?)>(.*?)<\/(?i:' . $tagName . ')>/s'; 887 888 if (!$hasEndTag) { 889 $search = '/<(?i:' . $tagName . ')(.*?)>/s'; 890 } 891 892 if (preg_match_all($search, $content, $match)) { 893 if (count($match) >= 2) { 894 for ($i = 0; $i < count($match[1]); $i++) { 895 $item = array('options' => array(), 'content' => $this->render_text($match[2][$i])); 896 897 $optionlist = preg_split('/\s(?=([^"]*"[^"]*")*[^"]*$)/', trim($match[1][$i])); 898 899 foreach ($optionlist as $option) { 900 $j = strpos($option, '='); 901 if ($j !== false) { 902 $value = substr($option, $j + 1); 903 904 if (substr($value, 0, 1) == '"') { $value = substr($value, 1); 905 } 906 if (substr($value, -1) == '"') { $value = substr($value, 0, -1); 907 } 908 909 $item['options'][substr($option, 0, $j)] = $value; 910 } else { 911 $item['options'][$option] = true; 912 } 913 } 914 915 $item['options'] = $this->cleanOptions($item['options'], $options); 916 917 $items[] = $item; 918 } 919 } 920 } 921 922 return $items; 923 } 924 925 /* 926 * Check if a custom style exists in styles.less 927 * 928 * @param $name The style name to search foe 929 * @return true if the style name exists 930 */ 931 protected function customStyleExists($name) 932 { 933 $stylePath = __DIR__.'/../styles/styles.less'; 934 935 if(file_exists($stylePath)) { 936 $styleData = file_get_contents($stylePath); 937 $searchString = '._mikiop-custom-type('.$name.');'; 938 939 return (strpos($styleData, $searchString) !== false); 940 } 941 942 return false; 943 } 944} 945