1<?php 2/** 3 * Copyright (c) 2021. ComboStrap, Inc. and its affiliates. All Rights Reserved. 4 * 5 * This source code is licensed under the GPL license found in the 6 * COPYING file in the root directory of this source tree. 7 * 8 * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 9 * @author ComboStrap <support@combostrap.com> 10 * 11 */ 12 13namespace ComboStrap; 14 15use dokuwiki\Extension\SyntaxPlugin; 16use syntax_plugin_combo_media; 17 18 19/** 20 * Class Call 21 * @package ComboStrap 22 * 23 * A wrapper around what's called a call 24 * which is an array of information such 25 * the mode, the data 26 * 27 * The {@link CallStack} is the only syntax representation that 28 * is available in DokuWiki 29 */ 30class Call 31{ 32 33 const INLINE_DISPLAY = "inline"; 34 const BlOCK_DISPLAY = "block"; 35 /** 36 * List of inline components 37 * Used to manage white space before an unmatched string. 38 * The syntax tree of Dokuwiki (ie {@link \Doku_Handler::$calls}) 39 * has only data and no class, for now, we create this 40 * lists manually because this is a hassle to retrieve this information from {@link \DokuWiki_Syntax_Plugin::getType()} 41 */ 42 const INLINE_DOKUWIKI_COMPONENTS = array( 43 /** 44 * Formatting https://www.dokuwiki.org/devel:syntax_plugins#syntax_types 45 * Comes from the {@link \dokuwiki\Parsing\ParserMode\Formatting} class 46 */ 47 "cdata", 48 "unformatted", // ie %% or nowiki 49 "doublequoteclosing", // https://www.dokuwiki.org/config:typography / https://www.dokuwiki.org/wiki:syntax#text_to_html_conversions 50 "doublequoteopening", 51 "singlequoteopening", 52 "singlequoteclosing", 53 "quote_open", 54 "quote_close", 55 "interwikilink", 56 "multiplyentity", 57 "apostrophe", 58 "deleted_open", 59 "deleted_close", 60 "emaillink", 61 "strong", 62 "emphasis", 63 "emphasis_open", 64 "emphasis_close", 65 "underline", 66 "underline_close", 67 "underline_open", 68 "monospace", 69 "subscript", 70 "subscript_open", 71 "subscript_close", 72 "superscript_open", 73 "superscript_close", 74 "superscript", 75 "deleted", 76 "footnote", 77 /** 78 * Others 79 */ 80 "acronym", // abbr 81 "strong_close", 82 "strong_open", 83 "monospace_open", 84 "monospace_close", 85 "doublequoteopening", // ie the character " in "The" 86 "entity", // for instance `...` are transformed in character 87 "linebreak", 88 "externallink", 89 "internallink", 90 "smiley", 91 MediaMarkup::INTERNAL_MEDIA_CALL_NAME, 92 MediaMarkup::EXTERNAL_MEDIA_CALL_NAME, 93 /** 94 * The inline of combo 95 */ 96 \syntax_plugin_combo_link::TAG, 97 IconTag::TAG, 98 NoteTag::TAG_INOTE, 99 ButtonTag::MARKUP_LONG, 100 \syntax_plugin_combo_tooltip::TAG, 101 PipelineTag::TAG, 102 BreadcrumbTag::MARKUP_BLOCK, // only the typo is inline but yeah 103 ); 104 105 106 const BLOCK_MARKUP_DOKUWIKI_COMPONENTS = array( 107 "listu_open", // ul 108 "listu_close", 109 "listo_open", 110 "listo_close", 111 "listitem_open", //li 112 "listitem_close", 113 "listcontent_open", // after li ??? 114 "listcontent_close", 115 "table_open", 116 "table_close", 117 "p_open", 118 "p_close", 119 "nest", // seen as enclosing footnotes 120 "hr", 121 "rss" 122 ); 123 124 /** 125 * Not inline, not block 126 */ 127 const TABLE_MARKUP = array( 128 "tablethead_open", 129 "tablethead_close", 130 "tableheader_open", 131 "tableheader_close", 132 "tablerow_open", 133 "tablerow_close", 134 "tablecell_open", 135 "tablecell_close", 136 "tableheader", 137 "table_align", 138 "table_row", 139 "tablecell", 140 "table_start", 141 "table_end" 142 ); 143 144 /** 145 * A media is not really an image 146 * but it may contains one 147 */ 148 const IMAGE_TAGS = [ 149 syntax_plugin_combo_media::TAG, 150 PageImageTag::MARKUP 151 ]; 152 const CANONICAL = "call"; 153 const TABLE_DISPLAY = "table-display"; 154 155 private $call; 156 157 /** 158 * The key identifier in the {@link CallStack} 159 * @var mixed|string 160 */ 161 private $key; 162 163 /** 164 * Call constructor. 165 * @param $call - the instruction array (ie called a call) 166 */ 167 public function __construct(&$call, $key = "") 168 { 169 $this->call = &$call; 170 $this->key = $key; 171 } 172 173 /** 174 * Insert a tag above 175 * @param $tagName 176 * @param $state 177 * @param $syntaxComponentName - the name of the dokuwiki syntax component (ie plugin_name) 178 * @param array $attribute 179 * @param string|null $rawContext 180 * @param string|null $content - the parsed content 181 * @param string|null $payload - the payload after handler 182 * @param int|null $position 183 * @return Call - a call 184 */ 185 public static function createComboCall($tagName, $state, array $attribute = array(), string $rawContext = null, string $content = null, string $payload = null, int $position = null, string $syntaxComponentName = null): Call 186 { 187 $data = array( 188 PluginUtility::ATTRIBUTES => $attribute, 189 PluginUtility::CONTEXT => $rawContext, 190 PluginUtility::STATE => $state, 191 PluginUtility::TAG => $tagName, 192 PluginUtility::POSITION => $position 193 ); 194 if ($payload !== null) { 195 $data[PluginUtility::PAYLOAD] = $payload; 196 } 197 $positionInText = $position; 198 199 if ($syntaxComponentName !== null) { 200 $componentName = PluginUtility::getComponentName($syntaxComponentName); 201 } else { 202 $componentName = PluginUtility::getComponentName($tagName); 203 } 204 $obj = plugin_load('syntax', $componentName); 205 if ($obj === null) { 206 throw new ExceptionRuntimeInternal("The component tag ($componentName) does not exists"); 207 } 208 209 $call = [ 210 "plugin", 211 array( 212 $componentName, 213 $data, 214 $state, 215 $content 216 ), 217 $positionInText 218 ]; 219 return new Call($call); 220 } 221 222 /** 223 * Insert a dokuwiki call 224 * @param $callName 225 * @param $array 226 * @param $positionInText 227 * @return Call 228 */ 229 public static function createNativeCall($callName, $array = [], $positionInText = null): Call 230 { 231 $call = [ 232 $callName, 233 $array, 234 $positionInText 235 ]; 236 return new Call($call); 237 } 238 239 public static function createFromInstruction($instruction): Call 240 { 241 return new Call($instruction); 242 } 243 244 /** 245 * @param Call $call 246 * @return Call 247 */ 248 public static function createFromCall(Call $call): Call 249 { 250 return self::createFromInstruction($call->toCallArray()); 251 } 252 253 254 /** 255 * 256 * Return the tag name from a call array 257 * 258 * This is not the logical tag. 259 * This is much more what's called: 260 * * the component name for a plugin 261 * * or the handler name for dokuwiki 262 * 263 * For a plugin, this is equivalent 264 * to the {@link SyntaxPlugin::getPluginComponent()} 265 * 266 * This is not the fully qualified component name: 267 * * with the plugin as prefix such as in {@link Call::getComponentName()} 268 * * or with the `open` and `close` prefix such as `p_close` ... 269 * 270 * @return mixed|string 271 */ 272 public function getTagName() 273 { 274 275 $mode = $this->call[0]; 276 if ($mode != "plugin") { 277 278 /** 279 * This is a standard dokuwiki node 280 */ 281 $dokuWikiNodeName = $this->call[0]; 282 283 /** 284 * The dokwuiki node name has also the open and close notion 285 * We delete this is not in the doc and therefore not logical 286 */ 287 $tagName = str_replace("_close", "", $dokuWikiNodeName); 288 return str_replace("_open", "", $tagName); 289 } 290 291 /** 292 * This is a plugin node 293 */ 294 $pluginDokuData = $this->call[1]; 295 296 /** 297 * If the tag is set 298 */ 299 $pluginData = $pluginDokuData[1]; 300 if (isset($pluginData[PluginUtility::TAG])) { 301 return $pluginData[PluginUtility::TAG]; 302 } 303 304 $component = $pluginDokuData[0]; 305 if (!is_array($component)) { 306 /** 307 * Tag name from class 308 */ 309 $componentNames = explode("_", $component); 310 /** 311 * To take care of 312 * PHP Warning: sizeof(): Parameter must be an array or an object that implements Countable 313 * in lib/plugins/combo/class/Tag.php on line 314 314 */ 315 if (is_array($componentNames)) { 316 $tagName = $componentNames[sizeof($componentNames) - 1]; 317 } else { 318 $tagName = $component; 319 } 320 return $tagName; 321 } 322 323 // To resolve: explode() expects parameter 2 to be string, array given 324 LogUtility::msg("The call (" . print_r($this->call, true) . ") has an array and not a string as component (" . print_r($component, true) . "). Page: " . MarkupPath::createFromRequestedPage(), LogUtility::LVL_MSG_ERROR); 325 return ""; 326 327 328 } 329 330 331 /** 332 * The parser state 333 * @return mixed 334 * May be null (example eol, internallink, ...) 335 */ 336 public 337 function getState() 338 { 339 $mode = $this->call[0]; 340 if ($mode !== "plugin") { 341 342 /** 343 * There is no state because this is a standard 344 * dokuwiki syntax found in {@link \Doku_Renderer_xhtml} 345 * check if this is not a `...._close` or `...._open` 346 * to derive the state 347 */ 348 $mode = $this->call[0]; 349 $lastPositionSepName = strrpos($mode, "_"); 350 $closeOrOpen = substr($mode, $lastPositionSepName + 1); 351 switch ($closeOrOpen) { 352 case "open": 353 return DOKU_LEXER_ENTER; 354 case "close": 355 return DOKU_LEXER_EXIT; 356 default: 357 /** 358 * Let op null, is used 359 * in {@link CallStack::processEolToEndStack()} 360 * and things can break 361 */ 362 return null; 363 } 364 365 } else { 366 // Plugin 367 $returnedArray = $this->call[1]; 368 if (array_key_exists(2, $returnedArray)) { 369 return $returnedArray[2]; 370 } else { 371 return null; 372 } 373 } 374 } 375 376 /** 377 * @return mixed the data returned from the {@link DokuWiki_Syntax_Plugin::handle} (ie attributes, payload, ...) 378 * It may be any type. Array, scalar 379 */ 380 public 381 function &getPluginData($attribute = null) 382 { 383 $data = &$this->call[1][1]; 384 if ($attribute === null) { 385 return $data; 386 } 387 return $data[$attribute]; 388 389 } 390 391 /** 392 * @return mixed the matched content from the {@link DokuWiki_Syntax_Plugin::handle} 393 */ 394 public 395 function getCapturedContent() 396 { 397 $caller = $this->call[0]; 398 switch ($caller) { 399 case "plugin": 400 return $this->call[1][3]; 401 case "internallink": 402 return '[[' . $this->call[1][0] . '|' . $this->call[1][1] . ']]'; 403 case "eol": 404 return DOKU_LF; 405 case "header": 406 case "cdata": 407 return $this->call[1][0]; 408 default: 409 if (isset($this->call[1][0]) && is_string($this->call[1][0])) { 410 return $this->call[1][0]; 411 } else { 412 return ""; 413 } 414 } 415 } 416 417 418 /** 419 * Return the attributes of a call 420 */ 421 public 422 function &getAttributes(): array 423 { 424 425 $isPluginCall = $this->isPluginCall(); 426 if (!$isPluginCall) { 427 return $this->call[1]; 428 } 429 430 $data = &$this->getPluginData(); 431 if (!is_array($data)) { 432 LogUtility::error("The handle data is not an array for the call ($this), correct the returned data from the handle syntax plugin function", self::CANONICAL); 433 // We discard, it may be a third party plugin 434 // The log will throw an error if it's on our hand 435 $data = []; 436 return $data; 437 } 438 if (!isset($data[PluginUtility::ATTRIBUTES])) { 439 $data[PluginUtility::ATTRIBUTES] = []; 440 } 441 $attributes = &$data[PluginUtility::ATTRIBUTES]; 442 if (!is_array($attributes)) { 443 $message = "The attributes value are not an array for the call ($this), the value was wrapped in an array"; 444 LogUtility::error($message, self::CANONICAL); 445 $attributes = [$attributes]; 446 } 447 return $attributes; 448 } 449 450 public 451 function removeAttributes() 452 { 453 454 $data = &$this->getPluginData(); 455 if (isset($data[PluginUtility::ATTRIBUTES])) { 456 unset($data[PluginUtility::ATTRIBUTES]); 457 } 458 459 } 460 461 public 462 function updateToPluginComponent($component, $state, $attributes = array()) 463 { 464 if ($this->call[0] == "plugin") { 465 $match = $this->call[1][3]; 466 } else { 467 $this->call[0] = "plugin"; 468 $match = ""; 469 } 470 $this->call[1] = array( 471 0 => $component, 472 1 => array( 473 PluginUtility::ATTRIBUTES => $attributes, 474 PluginUtility::STATE => $state, 475 ), 476 2 => $state, 477 3 => $match 478 ); 479 480 } 481 482 /** 483 * Does the display has been set 484 * to override the dokuwiki default 485 * ({@link Syntax::getPType()} 486 * 487 * because an image is by default a inline component 488 * but can be a block (ie top image of a card) 489 * @return bool 490 */ 491 public 492 function isDisplaySet(): bool 493 { 494 return isset($this->call[1][1][PluginUtility::DISPLAY]); 495 } 496 497 /** 498 * @return string|null 499 * {@link Call::INLINE_DISPLAY} or {@link Call::BlOCK_DISPLAY} 500 */ 501 public 502 function getDisplay(): ?string 503 { 504 $mode = $this->getMode(); 505 if ($mode == "plugin") { 506 if ($this->isDisplaySet()) { 507 return $this->call[1][1][PluginUtility::DISPLAY]; 508 } 509 } 510 511 if ($this->getState() == DOKU_LEXER_UNMATCHED) { 512 /** 513 * Unmatched are content (ie text node in XML/HTML) and have 514 * no display 515 */ 516 return Call::INLINE_DISPLAY; 517 } else { 518 $mode = $this->call[0]; 519 if ($mode == "plugin") { 520 global $DOKU_PLUGINS; 521 $component = $this->getComponentName(); 522 /** 523 * @var SyntaxPlugin $syntaxPlugin 524 */ 525 $syntaxPlugin = $DOKU_PLUGINS['syntax'][$component]; 526 if ($syntaxPlugin === null) { 527 // not a syntax plugin (ie frontmatter) 528 return null; 529 } 530 $pType = $syntaxPlugin->getPType(); 531 switch ($pType) { 532 // https://www.dokuwiki.org/devel:syntax_plugins#syntax_types 533 case "substition": 534 case "normal": 535 return Call::INLINE_DISPLAY; 536 case "block": 537 case "stack": 538 return Call::BlOCK_DISPLAY; 539 default: 540 LogUtility::msg("The ptype (" . $pType . ") is unknown."); 541 return null; 542 } 543 } else { 544 if ($mode == "eol") { 545 /** 546 * Control character 547 * We return it as it's used in the 548 * {@link \syntax_plugin_combo_para::fromEolToParagraphUntilEndOfStack()} 549 * to create the paragraph 550 * This is not a block, nor an inline 551 */ 552 return $mode; 553 } 554 555 if (in_array($mode, self::INLINE_DOKUWIKI_COMPONENTS)) { 556 return Call::INLINE_DISPLAY; 557 } 558 559 if (in_array($mode, self::BLOCK_MARKUP_DOKUWIKI_COMPONENTS)) { 560 return Call::BlOCK_DISPLAY; 561 } 562 563 if (in_array($mode, self::TABLE_MARKUP)) { 564 return Call::TABLE_DISPLAY; 565 } 566 567 LogUtility::warning("The display of the call with the mode (" . $mode . ") is unknown"); 568 return null; 569 570 571 } 572 } 573 574 } 575 576 /** 577 * Same as {@link Call::getTagName()} 578 * but fully qualified 579 * @return string 580 */ 581 public 582 function getComponentName() 583 { 584 $mode = $this->call[0]; 585 if ($mode == "plugin") { 586 $pluginDokuData = $this->call[1]; 587 return $pluginDokuData[0]; 588 } else { 589 return $mode; 590 } 591 } 592 593 public 594 function updateEolToSpace() 595 { 596 $mode = $this->call[0]; 597 if ($mode != "eol") { 598 LogUtility::msg("You can't update a " . $mode . " to a space. It should be a eol", LogUtility::LVL_MSG_WARNING, "support"); 599 } else { 600 $this->call[0] = "cdata"; 601 $this->call[1] = array( 602 0 => " " 603 ); 604 } 605 606 } 607 608 public 609 function &addAttribute($key, $value) 610 { 611 $mode = $this->call[0]; 612 if ($mode == "plugin") { 613 $this->call[1][1][PluginUtility::ATTRIBUTES][$key] = $value; 614 // keep the new reference 615 return $this->call[1][1][PluginUtility::ATTRIBUTES][$key]; 616 } else { 617 LogUtility::msg("You can't add an attribute to the non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING, "support"); 618 $whatever = []; 619 return $whatever; 620 } 621 } 622 623 public 624 function getContext() 625 { 626 $mode = $this->call[0]; 627 if ($mode === "plugin") { 628 return $this->call[1][1][PluginUtility::CONTEXT] ?? null; 629 } else { 630 LogUtility::msg("You can't ask for a context from a non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING, "support"); 631 return null; 632 } 633 } 634 635 /** 636 * 637 * @return array 638 */ 639 public 640 function toCallArray() 641 { 642 return $this->call; 643 } 644 645 public 646 function __toString() 647 { 648 $name = $this->key; 649 if (!empty($name)) { 650 $name .= " - "; 651 } 652 $name .= $this->getTagName(); 653 $name .= " - {$this->getStateName()}"; 654 return $name; 655 } 656 657 /** 658 * @return string|null 659 * 660 * If the type returned is a boolean attribute, 661 * it means you need to define the expected types 662 * in the function {@link TagAttributes::createFromTagMatch()} 663 * as third attribute 664 */ 665 public 666 function getType(): ?string 667 { 668 if ($this->getState() == DOKU_LEXER_UNMATCHED) { 669 return null; 670 } else { 671 return $this->getAttribute(TagAttributes::TYPE_KEY); 672 } 673 } 674 675 /** 676 * @param $key 677 * @param null $default 678 * @return array|string|null 679 */ 680 public 681 function &getAttribute($key, $default = null) 682 { 683 $attributes = &$this->getAttributes(); 684 if (isset($attributes[$key])) { 685 return $attributes[$key]; 686 } 687 return $default; 688 689 } 690 691 public 692 function getPayload() 693 { 694 $mode = $this->call[0]; 695 if ($mode == "plugin") { 696 return $this->call[1][1][PluginUtility::PAYLOAD]; 697 } else { 698 LogUtility::msg("You can't ask for a payload from a non plugin call mode (" . $mode . ").", LogUtility::LVL_MSG_WARNING, "support"); 699 return null; 700 } 701 } 702 703 public 704 function setContext($value) 705 { 706 $this->call[1][1][PluginUtility::CONTEXT] = $value; 707 return $this; 708 } 709 710 public 711 function hasAttribute($attributeName): bool 712 { 713 $attributes = $this->getAttributes(); 714 if (isset($attributes[$attributeName])) { 715 return true; 716 } else { 717 if ($this->getType() == $attributeName) { 718 return true; 719 } else { 720 return false; 721 } 722 } 723 } 724 725 public 726 function isPluginCall() 727 { 728 return $this->call[0] === "plugin"; 729 } 730 731 /** 732 * @return mixed|string the position (ie key) in the array 733 */ 734 public 735 function getKey() 736 { 737 return $this->key; 738 } 739 740 public 741 function &getInstructionCall() 742 { 743 return $this->call; 744 } 745 746 public 747 function setState($state) 748 { 749 if ($this->call[0] == "plugin") { 750 // for dokuwiki 751 $this->call[1][2] = $state; 752 // for the combo plugin if any 753 if (isset($this->call[1][1][PluginUtility::STATE])) { 754 $this->call[1][1][PluginUtility::STATE] = $state; 755 } 756 } else { 757 LogUtility::msg("This modification of state is not yet supported for a native call"); 758 } 759 } 760 761 762 /** 763 * Return the position of the first matched character in the text file 764 * @return mixed 765 */ 766 public 767 function getFirstMatchedCharacterPosition() 768 { 769 770 return $this->call[2]; 771 772 } 773 774 /** 775 * Return the position of the last matched character in the text file 776 * 777 * This is the {@link Call::getFirstMatchedCharacterPosition()} 778 * plus the length of the {@link Call::getCapturedContent()} 779 * matched content 780 * @return int|mixed 781 */ 782 public 783 function getLastMatchedCharacterPosition() 784 { 785 $captureContent = $this->getCapturedContent(); 786 $length = 0; 787 if ($captureContent != null) { 788 $length = strlen($captureContent); 789 } 790 return $this->getFirstMatchedCharacterPosition() + $length; 791 } 792 793 /** 794 * @param $value string the class string to add 795 * @return Call 796 */ 797 public 798 function addClassName(string $value): Call 799 { 800 $class = $this->getAttribute("class"); 801 if ($class != null) { 802 $value = "$class $value"; 803 } 804 $this->addAttribute("class", $value); 805 return $this; 806 807 } 808 809 /** 810 * @param $key 811 * @return mixed|null - the delete value of null if not found 812 */ 813 public 814 function removeAttribute($key) 815 { 816 817 $data = &$this->getPluginData(); 818 if (isset($data[PluginUtility::ATTRIBUTES][$key])) { 819 $value = $data[PluginUtility::ATTRIBUTES][$key]; 820 unset($data[PluginUtility::ATTRIBUTES][$key]); 821 return $value; 822 } else { 823 // boolean attribute as first attribute 824 if ($this->getType() == $key) { 825 unset($data[PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY]); 826 return true; 827 } 828 return null; 829 } 830 831 } 832 833 public 834 function setPayload($text) 835 { 836 if ($this->isPluginCall()) { 837 $this->call[1][1][PluginUtility::PAYLOAD] = $text; 838 } else { 839 LogUtility::msg("Setting the payload for a non-native call ($this) is not yet implemented"); 840 } 841 } 842 843 /** 844 * @return bool true if the call is a text call (same as dom text node) 845 */ 846 public 847 function isTextCall() 848 { 849 return ( 850 $this->getState() == DOKU_LEXER_UNMATCHED || 851 $this->getTagName() == "cdata" || 852 $this->getTagName() == "acronym" 853 ); 854 } 855 856 public 857 function setType($type) 858 { 859 if ($this->isPluginCall()) { 860 $this->call[1][1][PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY] = $type; 861 } else { 862 LogUtility::msg("This is not a plugin call ($this), you can't set the type"); 863 } 864 } 865 866 public 867 function addCssStyle($key, $value) 868 { 869 $style = $this->getAttribute("style"); 870 $cssValue = "$key:$value"; 871 if ($style !== null) { 872 $cssValue = "$style; $cssValue"; 873 } 874 $this->addAttribute("style", $cssValue); 875 } 876 877 public 878 function setSyntaxComponentFromTag($tag) 879 { 880 881 if ($this->isPluginCall()) { 882 $this->call[1][0] = PluginUtility::getComponentName($tag); 883 } else { 884 LogUtility::msg("The call ($this) is a native call and we don't support yet the modification of the component to ($tag)"); 885 } 886 } 887 888 889 public 890 function setCapturedContent($content) 891 { 892 $tagName = $this->getTagName(); 893 switch ($tagName) { 894 case "cdata": 895 $this->call[1][0] = $content; 896 break; 897 default: 898 LogUtility::msg("Setting the captured content on a call for the tag ($tagName) is not yet implemented", LogUtility::LVL_MSG_ERROR); 899 } 900 } 901 902 /** 903 * Set the display to block or inline 904 * One of `block` or `inline` 905 */ 906 public 907 function setDisplay($display): Call 908 { 909 $mode = $this->getMode(); 910 if ($mode == "plugin") { 911 $this->call[1][1][PluginUtility::DISPLAY] = $display; 912 } else { 913 LogUtility::msg("You can't set a display on a non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING); 914 } 915 return $this; 916 917 } 918 919 /** 920 * The plugin or not 921 * @return mixed 922 */ 923 private 924 function getMode() 925 { 926 return $this->call[0]; 927 } 928 929 /** 930 * Return if this an unmatched call with space 931 * in captured content 932 * @return bool 933 */ 934 public 935 function isUnMatchedEmptyCall(): bool 936 { 937 if ($this->getState() === DOKU_LEXER_UNMATCHED && trim($this->getCapturedContent()) === "") { 938 return true; 939 } 940 return false; 941 } 942 943 public 944 function getExitCode() 945 { 946 $mode = $this->call[0]; 947 if ($mode == "plugin") { 948 $value = $this->call[1][1][PluginUtility::EXIT_CODE] ?? null; 949 if ($value === null) { 950 return 0; 951 } 952 return $value; 953 } else { 954 LogUtility::msg("You can't ask for the exit code from a non plugin call mode (" . $mode . ").", LogUtility::LVL_MSG_WARNING, "support"); 955 return 0; 956 } 957 } 958 959 public 960 function setAttribute(string $name, $value): Call 961 { 962 $this->getAttributes()[$name] = $value; 963 return $this; 964 } 965 966 public 967 function setPluginData(string $name, $value): Call 968 { 969 $this->getPluginData()[$name] = $value; 970 return $this; 971 } 972 973 public 974 function getIdOrDefault() 975 { 976 $id = $this->getAttribute(TagAttributes::ID_KEY); 977 if ($id !== null) { 978 return $id; 979 } 980 return $this->getAttribute(TagAttributes::GENERATED_ID_KEY); 981 } 982 983 public 984 function getAttributeAndRemove(string $key) 985 { 986 $value = $this->getAttribute($key); 987 $this->removeAttribute($key); 988 return $value; 989 } 990 991 private function getStateName(): string 992 { 993 $state = $this->getState(); 994 switch ($state) { 995 case DOKU_LEXER_ENTER: 996 return "enter"; 997 case DOKU_LEXER_EXIT: 998 return "exit"; 999 case DOKU_LEXER_SPECIAL: 1000 return "empty"; 1001 case DOKU_LEXER_UNMATCHED: 1002 return "text"; 1003 default: 1004 return "unknown " . $state; 1005 } 1006 } 1007 1008 1009} 1010