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