137748cd8SNickeau<?php 237748cd8SNickeau/** 337748cd8SNickeau * Copyright (c) 2021. ComboStrap, Inc. and its affiliates. All Rights Reserved. 437748cd8SNickeau * 537748cd8SNickeau * This source code is licensed under the GPL license found in the 637748cd8SNickeau * COPYING file in the root directory of this source tree. 737748cd8SNickeau * 837748cd8SNickeau * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 937748cd8SNickeau * @author ComboStrap <support@combostrap.com> 1037748cd8SNickeau * 1137748cd8SNickeau */ 1237748cd8SNickeau 1337748cd8SNickeaunamespace ComboStrap; 1437748cd8SNickeau 1537748cd8SNickeauuse dokuwiki\Extension\SyntaxPlugin; 161fa8c418SNickeauuse syntax_plugin_combo_media; 1737748cd8SNickeau 1837748cd8SNickeau 1937748cd8SNickeau/** 2037748cd8SNickeau * Class Call 2137748cd8SNickeau * @package ComboStrap 2237748cd8SNickeau * 2337748cd8SNickeau * A wrapper around what's called a call 2437748cd8SNickeau * which is an array of information such 2537748cd8SNickeau * the mode, the data 2637748cd8SNickeau * 2737748cd8SNickeau * The {@link CallStack} is the only syntax representation that 2837748cd8SNickeau * is available in DokuWiki 2937748cd8SNickeau */ 3037748cd8SNickeauclass Call 3137748cd8SNickeau{ 3237748cd8SNickeau 3337748cd8SNickeau const INLINE_DISPLAY = "inline"; 3437748cd8SNickeau const BlOCK_DISPLAY = "block"; 3537748cd8SNickeau /** 3637748cd8SNickeau * List of inline components 3737748cd8SNickeau * Used to manage white space before an unmatched string. 3837748cd8SNickeau * The syntax tree of Dokuwiki (ie {@link \Doku_Handler::$calls}) 3937748cd8SNickeau * has only data and no class, for now, we create this 4037748cd8SNickeau * lists manually because this is a hassle to retrieve this information from {@link \DokuWiki_Syntax_Plugin::getType()} 4137748cd8SNickeau */ 4237748cd8SNickeau const INLINE_DOKUWIKI_COMPONENTS = array( 4337748cd8SNickeau /** 4437748cd8SNickeau * Formatting https://www.dokuwiki.org/devel:syntax_plugins#syntax_types 4537748cd8SNickeau * Comes from the {@link \dokuwiki\Parsing\ParserMode\Formatting} class 4637748cd8SNickeau */ 4737748cd8SNickeau "cdata", 4837748cd8SNickeau "unformatted", // ie %% or nowiki 4937748cd8SNickeau "doublequoteclosing", // https://www.dokuwiki.org/config:typography / https://www.dokuwiki.org/wiki:syntax#text_to_html_conversions 5037748cd8SNickeau "doublequoteopening", 5137748cd8SNickeau "singlequoteopening", 5237748cd8SNickeau "singlequoteclosing", 5304fd306cSNickeau "quote_open", 5404fd306cSNickeau "quote_close", 5504fd306cSNickeau "interwikilink", 5637748cd8SNickeau "multiplyentity", 5737748cd8SNickeau "apostrophe", 5804fd306cSNickeau "deleted_open", 5904fd306cSNickeau "deleted_close", 6004fd306cSNickeau "emaillink", 6137748cd8SNickeau "strong", 6237748cd8SNickeau "emphasis", 6337748cd8SNickeau "emphasis_open", 6437748cd8SNickeau "emphasis_close", 6537748cd8SNickeau "underline", 66e4026cd1Sgerardnico "underline_close", 6704fd306cSNickeau "underline_open", 6837748cd8SNickeau "monospace", 6937748cd8SNickeau "subscript", 7004fd306cSNickeau "subscript_open", 7104fd306cSNickeau "subscript_close", 7204fd306cSNickeau "superscript_open", 7304fd306cSNickeau "superscript_close", 7437748cd8SNickeau "superscript", 7537748cd8SNickeau "deleted", 7637748cd8SNickeau "footnote", 7737748cd8SNickeau /** 7837748cd8SNickeau * Others 7937748cd8SNickeau */ 801fa8c418SNickeau "acronym", // abbr 8137748cd8SNickeau "strong_close", 8237748cd8SNickeau "strong_open", 8337748cd8SNickeau "monospace_open", 8437748cd8SNickeau "monospace_close", 8537748cd8SNickeau "doublequoteopening", // ie the character " in "The" 8637748cd8SNickeau "entity", // for instance `...` are transformed in character 8737748cd8SNickeau "linebreak", 8837748cd8SNickeau "externallink", 8937748cd8SNickeau "internallink", 9004fd306cSNickeau "smiley", 9104fd306cSNickeau MediaMarkup::INTERNAL_MEDIA_CALL_NAME, 9204fd306cSNickeau MediaMarkup::EXTERNAL_MEDIA_CALL_NAME, 9337748cd8SNickeau /** 9437748cd8SNickeau * The inline of combo 9537748cd8SNickeau */ 9637748cd8SNickeau \syntax_plugin_combo_link::TAG, 9704fd306cSNickeau IconTag::TAG, 9804fd306cSNickeau NoteTag::TAG_INOTE, 9904fd306cSNickeau ButtonTag::MARKUP_LONG, 10037748cd8SNickeau \syntax_plugin_combo_tooltip::TAG, 10104fd306cSNickeau PipelineTag::TAG, 10204fd306cSNickeau BreadcrumbTag::MARKUP_BLOCK, // only the typo is inline but yeah 10337748cd8SNickeau ); 10437748cd8SNickeau 10537748cd8SNickeau 10637748cd8SNickeau const BLOCK_MARKUP_DOKUWIKI_COMPONENTS = array( 10737748cd8SNickeau "listu_open", // ul 10837748cd8SNickeau "listu_close", 10904fd306cSNickeau "listo_open", 11004fd306cSNickeau "listo_close", 11137748cd8SNickeau "listitem_open", //li 11237748cd8SNickeau "listitem_close", 11337748cd8SNickeau "listcontent_open", // after li ??? 11437748cd8SNickeau "listcontent_close", 11537748cd8SNickeau "table_open", 11637748cd8SNickeau "table_close", 11704fd306cSNickeau "p_open", 11804fd306cSNickeau "p_close", 11904fd306cSNickeau "nest", // seen as enclosing footnotes 12004fd306cSNickeau "hr", 12104fd306cSNickeau "rss" 12204fd306cSNickeau ); 12304fd306cSNickeau 12404fd306cSNickeau /** 12504fd306cSNickeau * Not inline, not block 12604fd306cSNickeau */ 12704fd306cSNickeau const TABLE_MARKUP = array( 12804fd306cSNickeau "tablethead_open", 12904fd306cSNickeau "tablethead_close", 13004fd306cSNickeau "tableheader_open", 13104fd306cSNickeau "tableheader_close", 13204fd306cSNickeau "tablerow_open", 13304fd306cSNickeau "tablerow_close", 13404fd306cSNickeau "tablecell_open", 13504fd306cSNickeau "tablecell_close" 13637748cd8SNickeau ); 13737748cd8SNickeau 1381fa8c418SNickeau /** 1391fa8c418SNickeau * A media is not really an image 1401fa8c418SNickeau * but it may contains one 1411fa8c418SNickeau */ 1421fa8c418SNickeau const IMAGE_TAGS = [ 1431fa8c418SNickeau syntax_plugin_combo_media::TAG, 14404fd306cSNickeau PageImageTag::MARKUP 1451fa8c418SNickeau ]; 1464cadd4f8SNickeau const CANONICAL = "call"; 14704fd306cSNickeau const TABLE_DISPLAY = "table-display"; 1481fa8c418SNickeau 14937748cd8SNickeau private $call; 15037748cd8SNickeau 15137748cd8SNickeau /** 15237748cd8SNickeau * The key identifier in the {@link CallStack} 15337748cd8SNickeau * @var mixed|string 15437748cd8SNickeau */ 15537748cd8SNickeau private $key; 15637748cd8SNickeau 15737748cd8SNickeau /** 15837748cd8SNickeau * Call constructor. 15937748cd8SNickeau * @param $call - the instruction array (ie called a call) 16037748cd8SNickeau */ 16137748cd8SNickeau public function __construct(&$call, $key = "") 16237748cd8SNickeau { 16337748cd8SNickeau $this->call = &$call; 16437748cd8SNickeau $this->key = $key; 16537748cd8SNickeau } 16637748cd8SNickeau 16737748cd8SNickeau /** 16837748cd8SNickeau * Insert a tag above 16937748cd8SNickeau * @param $tagName 17037748cd8SNickeau * @param $state 17104fd306cSNickeau * @param $syntaxComponentName - the name of the dokuwiki syntax component (ie plugin_name) 172c3437056SNickeau * @param array $attribute 1734cadd4f8SNickeau * @param string|null $rawContext 1744cadd4f8SNickeau * @param string|null $content - the parsed content 175c3437056SNickeau * @param string|null $payload - the payload after handler 176c3437056SNickeau * @param int|null $position 17737748cd8SNickeau * @return Call - a call 17837748cd8SNickeau */ 17904fd306cSNickeau 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 18037748cd8SNickeau { 18137748cd8SNickeau $data = array( 18237748cd8SNickeau PluginUtility::ATTRIBUTES => $attribute, 1834cadd4f8SNickeau PluginUtility::CONTEXT => $rawContext, 184c3437056SNickeau PluginUtility::STATE => $state, 18504fd306cSNickeau PluginUtility::TAG => $tagName, 186c3437056SNickeau PluginUtility::POSITION => $position 18737748cd8SNickeau ); 18804fd306cSNickeau if ($payload !== null) { 18937748cd8SNickeau $data[PluginUtility::PAYLOAD] = $payload; 19037748cd8SNickeau } 191c3437056SNickeau $positionInText = $position; 19237748cd8SNickeau 19304fd306cSNickeau if ($syntaxComponentName !== null) { 19404fd306cSNickeau $componentName = PluginUtility::getComponentName($syntaxComponentName); 19504fd306cSNickeau } else { 19604fd306cSNickeau $componentName = PluginUtility::getComponentName($tagName); 19704fd306cSNickeau } 19804fd306cSNickeau $obj = plugin_load('syntax', $componentName); 19904fd306cSNickeau if ($obj === null) { 20004fd306cSNickeau throw new ExceptionRuntimeInternal("The component tag ($componentName) does not exists"); 20104fd306cSNickeau } 20204fd306cSNickeau 20337748cd8SNickeau $call = [ 20437748cd8SNickeau "plugin", 20537748cd8SNickeau array( 20604fd306cSNickeau $componentName, 20737748cd8SNickeau $data, 20837748cd8SNickeau $state, 20937748cd8SNickeau $content 21037748cd8SNickeau ), 21137748cd8SNickeau $positionInText 21237748cd8SNickeau ]; 21337748cd8SNickeau return new Call($call); 21437748cd8SNickeau } 21537748cd8SNickeau 21637748cd8SNickeau /** 21737748cd8SNickeau * Insert a dokuwiki call 21837748cd8SNickeau * @param $callName 21937748cd8SNickeau * @param $array 22037748cd8SNickeau * @param $positionInText 22137748cd8SNickeau * @return Call 22237748cd8SNickeau */ 2234cadd4f8SNickeau public static function createNativeCall($callName, $array = [], $positionInText = null): Call 22437748cd8SNickeau { 22537748cd8SNickeau $call = [ 22637748cd8SNickeau $callName, 22737748cd8SNickeau $array, 22837748cd8SNickeau $positionInText 22937748cd8SNickeau ]; 23037748cd8SNickeau return new Call($call); 23137748cd8SNickeau } 23237748cd8SNickeau 23304fd306cSNickeau public static function createFromInstruction($instruction): Call 23437748cd8SNickeau { 23537748cd8SNickeau return new Call($instruction); 23637748cd8SNickeau } 23737748cd8SNickeau 2384cadd4f8SNickeau /** 2394cadd4f8SNickeau * @param Call $call 2404cadd4f8SNickeau * @return Call 2414cadd4f8SNickeau */ 2424cadd4f8SNickeau public static function createFromCall(Call $call): Call 2434cadd4f8SNickeau { 2444cadd4f8SNickeau return self::createFromInstruction($call->toCallArray()); 2454cadd4f8SNickeau } 2464cadd4f8SNickeau 24737748cd8SNickeau 24837748cd8SNickeau /** 24937748cd8SNickeau * 25037748cd8SNickeau * Return the tag name from a call array 25137748cd8SNickeau * 25237748cd8SNickeau * This is not the logical tag. 25337748cd8SNickeau * This is much more what's called: 25437748cd8SNickeau * * the component name for a plugin 25537748cd8SNickeau * * or the handler name for dokuwiki 25637748cd8SNickeau * 25737748cd8SNickeau * For a plugin, this is equivalent 25837748cd8SNickeau * to the {@link SyntaxPlugin::getPluginComponent()} 25937748cd8SNickeau * 26037748cd8SNickeau * This is not the fully qualified component name: 26137748cd8SNickeau * * with the plugin as prefix such as in {@link Call::getComponentName()} 26237748cd8SNickeau * * or with the `open` and `close` prefix such as `p_close` ... 26337748cd8SNickeau * 26437748cd8SNickeau * @return mixed|string 26537748cd8SNickeau */ 26637748cd8SNickeau public function getTagName() 26737748cd8SNickeau { 26804fd306cSNickeau 26937748cd8SNickeau $mode = $this->call[0]; 27037748cd8SNickeau if ($mode != "plugin") { 27137748cd8SNickeau 27237748cd8SNickeau /** 27337748cd8SNickeau * This is a standard dokuwiki node 27437748cd8SNickeau */ 27537748cd8SNickeau $dokuWikiNodeName = $this->call[0]; 27637748cd8SNickeau 27737748cd8SNickeau /** 27837748cd8SNickeau * The dokwuiki node name has also the open and close notion 27937748cd8SNickeau * We delete this is not in the doc and therefore not logical 28037748cd8SNickeau */ 28137748cd8SNickeau $tagName = str_replace("_close", "", $dokuWikiNodeName); 28204fd306cSNickeau return str_replace("_open", "", $tagName); 28304fd306cSNickeau } 28437748cd8SNickeau 28537748cd8SNickeau /** 28637748cd8SNickeau * This is a plugin node 28737748cd8SNickeau */ 28837748cd8SNickeau $pluginDokuData = $this->call[1]; 28904fd306cSNickeau 29004fd306cSNickeau /** 29104fd306cSNickeau * If the tag is set 29204fd306cSNickeau */ 29304fd306cSNickeau $pluginData = $pluginDokuData[1]; 29404fd306cSNickeau if (isset($pluginData[PluginUtility::TAG])) { 29504fd306cSNickeau return $pluginData[PluginUtility::TAG]; 29604fd306cSNickeau } 29704fd306cSNickeau 29837748cd8SNickeau $component = $pluginDokuData[0]; 29937748cd8SNickeau if (!is_array($component)) { 30037748cd8SNickeau /** 30137748cd8SNickeau * Tag name from class 30237748cd8SNickeau */ 30337748cd8SNickeau $componentNames = explode("_", $component); 30437748cd8SNickeau /** 30537748cd8SNickeau * To take care of 30637748cd8SNickeau * PHP Warning: sizeof(): Parameter must be an array or an object that implements Countable 30737748cd8SNickeau * in lib/plugins/combo/class/Tag.php on line 314 30837748cd8SNickeau */ 30937748cd8SNickeau if (is_array($componentNames)) { 31037748cd8SNickeau $tagName = $componentNames[sizeof($componentNames) - 1]; 31137748cd8SNickeau } else { 31237748cd8SNickeau $tagName = $component; 31337748cd8SNickeau } 31437748cd8SNickeau return $tagName; 31504fd306cSNickeau } 31604fd306cSNickeau 31704fd306cSNickeau // To resolve: explode() expects parameter 2 to be string, array given 31804fd306cSNickeau 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); 31904fd306cSNickeau return ""; 32004fd306cSNickeau 32137748cd8SNickeau 32237748cd8SNickeau } 32337748cd8SNickeau 32437748cd8SNickeau 32537748cd8SNickeau /** 32637748cd8SNickeau * The parser state 32737748cd8SNickeau * @return mixed 32837748cd8SNickeau * May be null (example eol, internallink, ...) 32937748cd8SNickeau */ 33004fd306cSNickeau public 33104fd306cSNickeau function getState() 33237748cd8SNickeau { 33337748cd8SNickeau $mode = $this->call[0]; 3344cadd4f8SNickeau if ($mode !== "plugin") { 33537748cd8SNickeau 33637748cd8SNickeau /** 33737748cd8SNickeau * There is no state because this is a standard 33837748cd8SNickeau * dokuwiki syntax found in {@link \Doku_Renderer_xhtml} 33937748cd8SNickeau * check if this is not a `...._close` or `...._open` 34037748cd8SNickeau * to derive the state 34137748cd8SNickeau */ 34237748cd8SNickeau $mode = $this->call[0]; 34337748cd8SNickeau $lastPositionSepName = strrpos($mode, "_"); 34437748cd8SNickeau $closeOrOpen = substr($mode, $lastPositionSepName + 1); 34537748cd8SNickeau switch ($closeOrOpen) { 34637748cd8SNickeau case "open": 34737748cd8SNickeau return DOKU_LEXER_ENTER; 34837748cd8SNickeau case "close": 34937748cd8SNickeau return DOKU_LEXER_EXIT; 35037748cd8SNickeau default: 35104fd306cSNickeau /** 35204fd306cSNickeau * Let op null, is used 35304fd306cSNickeau * in {@link CallStack::processEolToEndStack()} 35404fd306cSNickeau * and things can break 35504fd306cSNickeau */ 35637748cd8SNickeau return null; 35737748cd8SNickeau } 35837748cd8SNickeau 35937748cd8SNickeau } else { 36037748cd8SNickeau // Plugin 36137748cd8SNickeau $returnedArray = $this->call[1]; 36237748cd8SNickeau if (array_key_exists(2, $returnedArray)) { 36337748cd8SNickeau return $returnedArray[2]; 36437748cd8SNickeau } else { 36537748cd8SNickeau return null; 36637748cd8SNickeau } 36737748cd8SNickeau } 36837748cd8SNickeau } 36937748cd8SNickeau 37037748cd8SNickeau /** 37137748cd8SNickeau * @return mixed the data returned from the {@link DokuWiki_Syntax_Plugin::handle} (ie attributes, payload, ...) 37237748cd8SNickeau */ 37304fd306cSNickeau public 37404fd306cSNickeau function &getPluginData($attribute = null) 37537748cd8SNickeau { 3764cadd4f8SNickeau $data = &$this->call[1][1]; 3774cadd4f8SNickeau if ($attribute === null) { 3784cadd4f8SNickeau return $data; 3794cadd4f8SNickeau } 3804cadd4f8SNickeau return $data[$attribute]; 3814cadd4f8SNickeau 38237748cd8SNickeau } 38337748cd8SNickeau 38437748cd8SNickeau /** 38537748cd8SNickeau * @return mixed the matched content from the {@link DokuWiki_Syntax_Plugin::handle} 38637748cd8SNickeau */ 38704fd306cSNickeau public 38804fd306cSNickeau function getCapturedContent() 38937748cd8SNickeau { 39037748cd8SNickeau $caller = $this->call[0]; 39137748cd8SNickeau switch ($caller) { 39237748cd8SNickeau case "plugin": 39337748cd8SNickeau return $this->call[1][3]; 39437748cd8SNickeau case "internallink": 39537748cd8SNickeau return '[[' . $this->call[1][0] . '|' . $this->call[1][1] . ']]'; 39637748cd8SNickeau case "eol": 39737748cd8SNickeau return DOKU_LF; 39837748cd8SNickeau case "header": 39937748cd8SNickeau case "cdata": 40037748cd8SNickeau return $this->call[1][0]; 40137748cd8SNickeau default: 40237748cd8SNickeau if (isset($this->call[1][0]) && is_string($this->call[1][0])) { 40337748cd8SNickeau return $this->call[1][0]; 40437748cd8SNickeau } else { 40537748cd8SNickeau return ""; 40637748cd8SNickeau } 40737748cd8SNickeau } 40837748cd8SNickeau } 40937748cd8SNickeau 41037748cd8SNickeau 41104fd306cSNickeau /** 41204fd306cSNickeau * 41304fd306cSNickeau */ 41404fd306cSNickeau public 41504fd306cSNickeau function &getAttributes(): ?array 41637748cd8SNickeau { 41737748cd8SNickeau 41804fd306cSNickeau 41904fd306cSNickeau $isPluginCall = $this->isPluginCall(); 42004fd306cSNickeau if (!$isPluginCall) { 42137748cd8SNickeau return $this->call[1]; 42204fd306cSNickeau } else { 42304fd306cSNickeau $data = &$this->getPluginData(); 42404fd306cSNickeau if (!is_array($data)) { 42504fd306cSNickeau 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); 42604fd306cSNickeau $data = []; 42704fd306cSNickeau return $data; 4284cadd4f8SNickeau } 42904fd306cSNickeau if (!isset($data[PluginUtility::ATTRIBUTES])) { 43004fd306cSNickeau $data[PluginUtility::ATTRIBUTES] = []; 43104fd306cSNickeau } 43204fd306cSNickeau $attributes = &$data[PluginUtility::ATTRIBUTES]; 43304fd306cSNickeau if (!is_array($attributes)) { 43404fd306cSNickeau $message = "The attributes value are not an array for the call ($this), the value was wrapped in an array"; 43504fd306cSNickeau LogUtility::error($message, self::CANONICAL); 43604fd306cSNickeau $attributes = [$attributes]; 4374cadd4f8SNickeau } 4384cadd4f8SNickeau return $attributes; 43937748cd8SNickeau } 44037748cd8SNickeau } 44137748cd8SNickeau 44204fd306cSNickeau public 44304fd306cSNickeau function removeAttributes() 44437748cd8SNickeau { 44537748cd8SNickeau 44637748cd8SNickeau $data = &$this->getPluginData(); 44737748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES])) { 44837748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES]); 44937748cd8SNickeau } 45037748cd8SNickeau 45137748cd8SNickeau } 45237748cd8SNickeau 45304fd306cSNickeau public 45404fd306cSNickeau function updateToPluginComponent($component, $state, $attributes = array()) 45537748cd8SNickeau { 45637748cd8SNickeau if ($this->call[0] == "plugin") { 45737748cd8SNickeau $match = $this->call[1][3]; 45837748cd8SNickeau } else { 45937748cd8SNickeau $this->call[0] = "plugin"; 46037748cd8SNickeau $match = ""; 46137748cd8SNickeau } 46237748cd8SNickeau $this->call[1] = array( 46337748cd8SNickeau 0 => $component, 46437748cd8SNickeau 1 => array( 46537748cd8SNickeau PluginUtility::ATTRIBUTES => $attributes, 46637748cd8SNickeau PluginUtility::STATE => $state, 46737748cd8SNickeau ), 46837748cd8SNickeau 2 => $state, 46937748cd8SNickeau 3 => $match 47037748cd8SNickeau ); 47137748cd8SNickeau 47237748cd8SNickeau } 47337748cd8SNickeau 4741fa8c418SNickeau /** 4751fa8c418SNickeau * Does the display has been set 4761fa8c418SNickeau * to override the dokuwiki default 4771fa8c418SNickeau * ({@link Syntax::getPType()} 4781fa8c418SNickeau * 4791fa8c418SNickeau * because an image is by default a inline component 4801fa8c418SNickeau * but can be a block (ie top image of a card) 4811fa8c418SNickeau * @return bool 4821fa8c418SNickeau */ 48304fd306cSNickeau public 48404fd306cSNickeau function isDisplaySet(): bool 4851fa8c418SNickeau { 4861fa8c418SNickeau return isset($this->call[1][1][PluginUtility::DISPLAY]); 4871fa8c418SNickeau } 4881fa8c418SNickeau 48904fd306cSNickeau /** 49004fd306cSNickeau * @return string|null 49104fd306cSNickeau * {@link Call::INLINE_DISPLAY} or {@link Call::BlOCK_DISPLAY} 49204fd306cSNickeau */ 49304fd306cSNickeau public 49404fd306cSNickeau function getDisplay(): ?string 49537748cd8SNickeau { 4961fa8c418SNickeau $mode = $this->getMode(); 4971fa8c418SNickeau if ($mode == "plugin") { 4981fa8c418SNickeau if ($this->isDisplaySet()) { 4991fa8c418SNickeau return $this->call[1][1][PluginUtility::DISPLAY]; 5001fa8c418SNickeau } 5011fa8c418SNickeau } 5021fa8c418SNickeau 50337748cd8SNickeau if ($this->getState() == DOKU_LEXER_UNMATCHED) { 50437748cd8SNickeau /** 50537748cd8SNickeau * Unmatched are content (ie text node in XML/HTML) and have 50637748cd8SNickeau * no display 50737748cd8SNickeau */ 50837748cd8SNickeau return Call::INLINE_DISPLAY; 50937748cd8SNickeau } else { 51037748cd8SNickeau $mode = $this->call[0]; 51137748cd8SNickeau if ($mode == "plugin") { 51237748cd8SNickeau global $DOKU_PLUGINS; 51337748cd8SNickeau $component = $this->getComponentName(); 51437748cd8SNickeau /** 51537748cd8SNickeau * @var SyntaxPlugin $syntaxPlugin 51637748cd8SNickeau */ 51737748cd8SNickeau $syntaxPlugin = $DOKU_PLUGINS['syntax'][$component]; 51837748cd8SNickeau $pType = $syntaxPlugin->getPType(); 51937748cd8SNickeau switch ($pType) { 52037748cd8SNickeau case "normal": 52137748cd8SNickeau return Call::INLINE_DISPLAY; 52237748cd8SNickeau case "block": 52337748cd8SNickeau case "stack": 52437748cd8SNickeau return Call::BlOCK_DISPLAY; 52537748cd8SNickeau default: 52637748cd8SNickeau LogUtility::msg("The ptype (" . $pType . ") is unknown."); 52737748cd8SNickeau return null; 52837748cd8SNickeau } 52937748cd8SNickeau } else { 53037748cd8SNickeau if ($mode == "eol") { 53137748cd8SNickeau /** 53237748cd8SNickeau * Control character 53337748cd8SNickeau * We return it as it's used in the 53437748cd8SNickeau * {@link \syntax_plugin_combo_para::fromEolToParagraphUntilEndOfStack()} 53537748cd8SNickeau * to create the paragraph 53637748cd8SNickeau * This is not a block, nor an inline 53737748cd8SNickeau */ 53837748cd8SNickeau return $mode; 53937748cd8SNickeau } 54037748cd8SNickeau 54137748cd8SNickeau if (in_array($mode, self::INLINE_DOKUWIKI_COMPONENTS)) { 54237748cd8SNickeau return Call::INLINE_DISPLAY; 54337748cd8SNickeau } 54437748cd8SNickeau 54537748cd8SNickeau if (in_array($mode, self::BLOCK_MARKUP_DOKUWIKI_COMPONENTS)) { 54637748cd8SNickeau return Call::BlOCK_DISPLAY; 54737748cd8SNickeau } 54837748cd8SNickeau 54904fd306cSNickeau if (in_array($mode, self::TABLE_MARKUP)) { 55004fd306cSNickeau return Call::TABLE_DISPLAY; 55104fd306cSNickeau } 55204fd306cSNickeau 55304fd306cSNickeau LogUtility::warning("The display of the call with the mode (" . $mode . ") is unknown"); 55437748cd8SNickeau return null; 55537748cd8SNickeau 55637748cd8SNickeau 55737748cd8SNickeau } 55837748cd8SNickeau } 55937748cd8SNickeau 56037748cd8SNickeau } 56137748cd8SNickeau 56237748cd8SNickeau /** 56337748cd8SNickeau * Same as {@link Call::getTagName()} 56437748cd8SNickeau * but fully qualified 56537748cd8SNickeau * @return string 56637748cd8SNickeau */ 56704fd306cSNickeau public 56804fd306cSNickeau function getComponentName() 56937748cd8SNickeau { 57037748cd8SNickeau $mode = $this->call[0]; 57137748cd8SNickeau if ($mode == "plugin") { 57237748cd8SNickeau $pluginDokuData = $this->call[1]; 57337748cd8SNickeau return $pluginDokuData[0]; 57437748cd8SNickeau } else { 57537748cd8SNickeau return $mode; 57637748cd8SNickeau } 57737748cd8SNickeau } 57837748cd8SNickeau 57904fd306cSNickeau public 58004fd306cSNickeau function updateEolToSpace() 58137748cd8SNickeau { 58237748cd8SNickeau $mode = $this->call[0]; 58337748cd8SNickeau if ($mode != "eol") { 58437748cd8SNickeau LogUtility::msg("You can't update a " . $mode . " to a space. It should be a eol", LogUtility::LVL_MSG_WARNING, "support"); 58537748cd8SNickeau } else { 58637748cd8SNickeau $this->call[0] = "cdata"; 58737748cd8SNickeau $this->call[1] = array( 58837748cd8SNickeau 0 => " " 58937748cd8SNickeau ); 59037748cd8SNickeau } 59137748cd8SNickeau 59237748cd8SNickeau } 59337748cd8SNickeau 59404fd306cSNickeau public 59504fd306cSNickeau function &addAttribute($key, $value) 59637748cd8SNickeau { 59737748cd8SNickeau $mode = $this->call[0]; 59837748cd8SNickeau if ($mode == "plugin") { 59937748cd8SNickeau $this->call[1][1][PluginUtility::ATTRIBUTES][$key] = $value; 60004fd306cSNickeau // keep the new reference 60104fd306cSNickeau return $this->call[1][1][PluginUtility::ATTRIBUTES][$key]; 60237748cd8SNickeau } else { 60337748cd8SNickeau LogUtility::msg("You can't add an attribute to the non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING, "support"); 60404fd306cSNickeau $whatever = []; 60504fd306cSNickeau return $whatever; 60637748cd8SNickeau } 60737748cd8SNickeau } 60837748cd8SNickeau 60904fd306cSNickeau public 61004fd306cSNickeau function getContext() 61137748cd8SNickeau { 61237748cd8SNickeau $mode = $this->call[0]; 61304fd306cSNickeau if ($mode === "plugin") { 614*70bbd7f1Sgerardnico return $this->call[1][1][PluginUtility::CONTEXT] ?? null; 61537748cd8SNickeau } else { 61637748cd8SNickeau LogUtility::msg("You can't ask for a context from a non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING, "support"); 61737748cd8SNickeau return null; 61837748cd8SNickeau } 61937748cd8SNickeau } 62037748cd8SNickeau 62137748cd8SNickeau /** 62237748cd8SNickeau * 62337748cd8SNickeau * @return array 62437748cd8SNickeau */ 62504fd306cSNickeau public 62604fd306cSNickeau function toCallArray() 62737748cd8SNickeau { 62837748cd8SNickeau return $this->call; 62937748cd8SNickeau } 63037748cd8SNickeau 63104fd306cSNickeau public 63204fd306cSNickeau function __toString() 63337748cd8SNickeau { 63437748cd8SNickeau $name = $this->key; 63537748cd8SNickeau if (!empty($name)) { 63637748cd8SNickeau $name .= " - "; 63737748cd8SNickeau } 63837748cd8SNickeau $name .= $this->getTagName(); 63904fd306cSNickeau $name .= " - {$this->getStateName()}"; 64037748cd8SNickeau return $name; 64137748cd8SNickeau } 64237748cd8SNickeau 6434cadd4f8SNickeau /** 6444cadd4f8SNickeau * @return string|null 6454cadd4f8SNickeau * 6464cadd4f8SNickeau * If the type returned is a boolean attribute, 6474cadd4f8SNickeau * it means you need to define the expected types 6484cadd4f8SNickeau * in the function {@link TagAttributes::createFromTagMatch()} 6494cadd4f8SNickeau * as third attribute 6504cadd4f8SNickeau */ 65104fd306cSNickeau public 65204fd306cSNickeau function getType(): ?string 65337748cd8SNickeau { 65437748cd8SNickeau if ($this->getState() == DOKU_LEXER_UNMATCHED) { 65537748cd8SNickeau return null; 65637748cd8SNickeau } else { 6574cadd4f8SNickeau return $this->getAttribute(TagAttributes::TYPE_KEY); 65837748cd8SNickeau } 65937748cd8SNickeau } 66037748cd8SNickeau 66137748cd8SNickeau /** 66237748cd8SNickeau * @param $key 66337748cd8SNickeau * @param null $default 6644cadd4f8SNickeau * @return array|string|null 66537748cd8SNickeau */ 66604fd306cSNickeau public 66704fd306cSNickeau function &getAttribute($key, $default = null) 66837748cd8SNickeau { 66904fd306cSNickeau $attributes = &$this->getAttributes(); 67037748cd8SNickeau if (isset($attributes[$key])) { 67137748cd8SNickeau return $attributes[$key]; 6724cadd4f8SNickeau } 67337748cd8SNickeau return $default; 6744cadd4f8SNickeau 67537748cd8SNickeau } 67637748cd8SNickeau 6774cadd4f8SNickeau public 6784cadd4f8SNickeau function getPayload() 67937748cd8SNickeau { 68037748cd8SNickeau $mode = $this->call[0]; 68137748cd8SNickeau if ($mode == "plugin") { 68237748cd8SNickeau return $this->call[1][1][PluginUtility::PAYLOAD]; 68337748cd8SNickeau } else { 68437748cd8SNickeau LogUtility::msg("You can't ask for a payload from a non plugin call mode (" . $mode . ").", LogUtility::LVL_MSG_WARNING, "support"); 68537748cd8SNickeau return null; 68637748cd8SNickeau } 68737748cd8SNickeau } 68837748cd8SNickeau 6894cadd4f8SNickeau public 6904cadd4f8SNickeau function setContext($value) 69137748cd8SNickeau { 69237748cd8SNickeau $this->call[1][1][PluginUtility::CONTEXT] = $value; 69337748cd8SNickeau return $this; 69437748cd8SNickeau } 69537748cd8SNickeau 6964cadd4f8SNickeau public 6974cadd4f8SNickeau function hasAttribute($attributeName): bool 69837748cd8SNickeau { 69937748cd8SNickeau $attributes = $this->getAttributes(); 70037748cd8SNickeau if (isset($attributes[$attributeName])) { 70137748cd8SNickeau return true; 70237748cd8SNickeau } else { 70337748cd8SNickeau if ($this->getType() == $attributeName) { 70437748cd8SNickeau return true; 70537748cd8SNickeau } else { 70637748cd8SNickeau return false; 70737748cd8SNickeau } 70837748cd8SNickeau } 70937748cd8SNickeau } 71037748cd8SNickeau 7114cadd4f8SNickeau public 7124cadd4f8SNickeau function isPluginCall() 71337748cd8SNickeau { 71437748cd8SNickeau return $this->call[0] === "plugin"; 71537748cd8SNickeau } 71637748cd8SNickeau 71737748cd8SNickeau /** 71837748cd8SNickeau * @return mixed|string the position (ie key) in the array 71937748cd8SNickeau */ 7204cadd4f8SNickeau public 7214cadd4f8SNickeau function getKey() 72237748cd8SNickeau { 72337748cd8SNickeau return $this->key; 72437748cd8SNickeau } 72537748cd8SNickeau 7264cadd4f8SNickeau public 72704fd306cSNickeau function &getInstructionCall() 72837748cd8SNickeau { 72937748cd8SNickeau return $this->call; 73037748cd8SNickeau } 73137748cd8SNickeau 7324cadd4f8SNickeau public 7334cadd4f8SNickeau function setState($state) 73437748cd8SNickeau { 73537748cd8SNickeau if ($this->call[0] == "plugin") { 73637748cd8SNickeau // for dokuwiki 73737748cd8SNickeau $this->call[1][2] = $state; 73837748cd8SNickeau // for the combo plugin if any 73937748cd8SNickeau if (isset($this->call[1][1][PluginUtility::STATE])) { 74037748cd8SNickeau $this->call[1][1][PluginUtility::STATE] = $state; 74137748cd8SNickeau } 74237748cd8SNickeau } else { 74337748cd8SNickeau LogUtility::msg("This modification of state is not yet supported for a native call"); 74437748cd8SNickeau } 74537748cd8SNickeau } 74637748cd8SNickeau 74737748cd8SNickeau 74837748cd8SNickeau /** 74937748cd8SNickeau * Return the position of the first matched character in the text file 75037748cd8SNickeau * @return mixed 75137748cd8SNickeau */ 7524cadd4f8SNickeau public 7534cadd4f8SNickeau function getFirstMatchedCharacterPosition() 75437748cd8SNickeau { 75537748cd8SNickeau 75637748cd8SNickeau return $this->call[2]; 75737748cd8SNickeau 75837748cd8SNickeau } 75937748cd8SNickeau 76037748cd8SNickeau /** 76137748cd8SNickeau * Return the position of the last matched character in the text file 76237748cd8SNickeau * 76337748cd8SNickeau * This is the {@link Call::getFirstMatchedCharacterPosition()} 76437748cd8SNickeau * plus the length of the {@link Call::getCapturedContent()} 76537748cd8SNickeau * matched content 76637748cd8SNickeau * @return int|mixed 76737748cd8SNickeau */ 7684cadd4f8SNickeau public 7694cadd4f8SNickeau function getLastMatchedCharacterPosition() 77037748cd8SNickeau { 771*70bbd7f1Sgerardnico $captureContent = $this->getCapturedContent(); 772*70bbd7f1Sgerardnico $length = 0; 773*70bbd7f1Sgerardnico if ($captureContent != null) { 774*70bbd7f1Sgerardnico $length = strlen($captureContent); 775*70bbd7f1Sgerardnico } 776*70bbd7f1Sgerardnico return $this->getFirstMatchedCharacterPosition() + $length; 77737748cd8SNickeau } 77837748cd8SNickeau 77937748cd8SNickeau /** 78037748cd8SNickeau * @param $value string the class string to add 78137748cd8SNickeau * @return Call 78237748cd8SNickeau */ 7834cadd4f8SNickeau public 7844cadd4f8SNickeau function addClassName(string $value): Call 78537748cd8SNickeau { 78637748cd8SNickeau $class = $this->getAttribute("class"); 78737748cd8SNickeau if ($class != null) { 78837748cd8SNickeau $value = "$class $value"; 78937748cd8SNickeau } 79037748cd8SNickeau $this->addAttribute("class", $value); 79137748cd8SNickeau return $this; 79237748cd8SNickeau 79337748cd8SNickeau } 79437748cd8SNickeau 79537748cd8SNickeau /** 79637748cd8SNickeau * @param $key 79737748cd8SNickeau * @return mixed|null - the delete value of null if not found 79837748cd8SNickeau */ 7994cadd4f8SNickeau public 8004cadd4f8SNickeau function removeAttribute($key) 80137748cd8SNickeau { 80237748cd8SNickeau 80337748cd8SNickeau $data = &$this->getPluginData(); 80437748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES][$key])) { 80537748cd8SNickeau $value = $data[PluginUtility::ATTRIBUTES][$key]; 80637748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES][$key]); 80737748cd8SNickeau return $value; 80837748cd8SNickeau } else { 80937748cd8SNickeau // boolean attribute as first attribute 81037748cd8SNickeau if ($this->getType() == $key) { 81137748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY]); 81237748cd8SNickeau return true; 81337748cd8SNickeau } 81437748cd8SNickeau return null; 81537748cd8SNickeau } 81637748cd8SNickeau 81737748cd8SNickeau } 81837748cd8SNickeau 8194cadd4f8SNickeau public 8204cadd4f8SNickeau function setPayload($text) 82137748cd8SNickeau { 82237748cd8SNickeau if ($this->isPluginCall()) { 82337748cd8SNickeau $this->call[1][1][PluginUtility::PAYLOAD] = $text; 82437748cd8SNickeau } else { 82537748cd8SNickeau LogUtility::msg("Setting the payload for a non-native call ($this) is not yet implemented"); 82637748cd8SNickeau } 82737748cd8SNickeau } 82837748cd8SNickeau 82937748cd8SNickeau /** 83037748cd8SNickeau * @return bool true if the call is a text call (same as dom text node) 83137748cd8SNickeau */ 8324cadd4f8SNickeau public 8334cadd4f8SNickeau function isTextCall() 83437748cd8SNickeau { 83537748cd8SNickeau return ( 83637748cd8SNickeau $this->getState() == DOKU_LEXER_UNMATCHED || 83737748cd8SNickeau $this->getTagName() == "cdata" || 83837748cd8SNickeau $this->getTagName() == "acronym" 83937748cd8SNickeau ); 84037748cd8SNickeau } 84137748cd8SNickeau 8424cadd4f8SNickeau public 8434cadd4f8SNickeau function setType($type) 84437748cd8SNickeau { 84537748cd8SNickeau if ($this->isPluginCall()) { 84637748cd8SNickeau $this->call[1][1][PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY] = $type; 84737748cd8SNickeau } else { 84837748cd8SNickeau LogUtility::msg("This is not a plugin call ($this), you can't set the type"); 84937748cd8SNickeau } 85037748cd8SNickeau } 85137748cd8SNickeau 8524cadd4f8SNickeau public 8534cadd4f8SNickeau function addCssStyle($key, $value) 85437748cd8SNickeau { 85537748cd8SNickeau $style = $this->getAttribute("style"); 85637748cd8SNickeau $cssValue = "$key:$value"; 8574cadd4f8SNickeau if ($style !== null) { 85837748cd8SNickeau $cssValue = "$style; $cssValue"; 85937748cd8SNickeau } 86037748cd8SNickeau $this->addAttribute("style", $cssValue); 86137748cd8SNickeau } 86237748cd8SNickeau 8634cadd4f8SNickeau public 8644cadd4f8SNickeau function setSyntaxComponentFromTag($tag) 86537748cd8SNickeau { 86637748cd8SNickeau 86737748cd8SNickeau if ($this->isPluginCall()) { 86837748cd8SNickeau $this->call[1][0] = PluginUtility::getComponentName($tag); 86937748cd8SNickeau } else { 87037748cd8SNickeau LogUtility::msg("The call ($this) is a native call and we don't support yet the modification of the component to ($tag)"); 87137748cd8SNickeau } 87237748cd8SNickeau } 87337748cd8SNickeau 87437748cd8SNickeau 8754cadd4f8SNickeau public 8764cadd4f8SNickeau function setCapturedContent($content) 87737748cd8SNickeau { 87837748cd8SNickeau $tagName = $this->getTagName(); 87937748cd8SNickeau switch ($tagName) { 88037748cd8SNickeau case "cdata": 88137748cd8SNickeau $this->call[1][0] = $content; 88237748cd8SNickeau break; 88337748cd8SNickeau default: 88437748cd8SNickeau LogUtility::msg("Setting the captured content on a call for the tag ($tagName) is not yet implemented", LogUtility::LVL_MSG_ERROR); 88537748cd8SNickeau } 88637748cd8SNickeau } 88737748cd8SNickeau 8881fa8c418SNickeau /** 8891fa8c418SNickeau * Set the display to block or inline 8901fa8c418SNickeau * One of `block` or `inline` 8911fa8c418SNickeau */ 8924cadd4f8SNickeau public 8934cadd4f8SNickeau function setDisplay($display): Call 8941fa8c418SNickeau { 8951fa8c418SNickeau $mode = $this->getMode(); 8961fa8c418SNickeau if ($mode == "plugin") { 8971fa8c418SNickeau $this->call[1][1][PluginUtility::DISPLAY] = $display; 8981fa8c418SNickeau } else { 8991fa8c418SNickeau LogUtility::msg("You can't set a display on a non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING); 9001fa8c418SNickeau } 9011fa8c418SNickeau return $this; 9021fa8c418SNickeau 9031fa8c418SNickeau } 9041fa8c418SNickeau 9051fa8c418SNickeau /** 9061fa8c418SNickeau * The plugin or not 9071fa8c418SNickeau * @return mixed 9081fa8c418SNickeau */ 9094cadd4f8SNickeau private 9104cadd4f8SNickeau function getMode() 9111fa8c418SNickeau { 9121fa8c418SNickeau return $this->call[0]; 9131fa8c418SNickeau } 9141fa8c418SNickeau 9151fa8c418SNickeau /** 9161fa8c418SNickeau * Return if this an unmatched call with space 9171fa8c418SNickeau * in captured content 9181fa8c418SNickeau * @return bool 9191fa8c418SNickeau */ 9204cadd4f8SNickeau public 9214cadd4f8SNickeau function isUnMatchedEmptyCall(): bool 9221fa8c418SNickeau { 9231fa8c418SNickeau if ($this->getState() === DOKU_LEXER_UNMATCHED && trim($this->getCapturedContent()) === "") { 9241fa8c418SNickeau return true; 9251fa8c418SNickeau } 9261fa8c418SNickeau return false; 9271fa8c418SNickeau } 9281fa8c418SNickeau 9294cadd4f8SNickeau public 9304cadd4f8SNickeau function getExitCode() 9314cadd4f8SNickeau { 9324cadd4f8SNickeau $mode = $this->call[0]; 9334cadd4f8SNickeau if ($mode == "plugin") { 934*70bbd7f1Sgerardnico $value = $this->call[1][1][PluginUtility::EXIT_CODE] ?? null; 9354cadd4f8SNickeau if ($value === null) { 9364cadd4f8SNickeau return 0; 9374cadd4f8SNickeau } 9384cadd4f8SNickeau return $value; 9394cadd4f8SNickeau } else { 9404cadd4f8SNickeau LogUtility::msg("You can't ask for the exit code from a non plugin call mode (" . $mode . ").", LogUtility::LVL_MSG_WARNING, "support"); 9414cadd4f8SNickeau return 0; 9424cadd4f8SNickeau } 9434cadd4f8SNickeau } 9444cadd4f8SNickeau 94504fd306cSNickeau public 94604fd306cSNickeau function setAttribute(string $name, $value): Call 9474cadd4f8SNickeau { 9484cadd4f8SNickeau $this->getPluginData()[PluginUtility::ATTRIBUTES][$name] = $value; 9494cadd4f8SNickeau return $this; 9504cadd4f8SNickeau } 9514cadd4f8SNickeau 95204fd306cSNickeau public 95304fd306cSNickeau function setPluginData(string $name, $value): Call 9544cadd4f8SNickeau { 9554cadd4f8SNickeau $this->getPluginData()[$name] = $value; 9564cadd4f8SNickeau return $this; 9574cadd4f8SNickeau } 9584cadd4f8SNickeau 95904fd306cSNickeau public 96004fd306cSNickeau function getIdOrDefault() 96104fd306cSNickeau { 96204fd306cSNickeau $id = $this->getAttribute(TagAttributes::ID_KEY); 96304fd306cSNickeau if ($id !== null) { 96404fd306cSNickeau return $id; 96504fd306cSNickeau } 96604fd306cSNickeau return $this->getAttribute(TagAttributes::GENERATED_ID_KEY); 96704fd306cSNickeau } 96804fd306cSNickeau 96904fd306cSNickeau public 97004fd306cSNickeau function getAttributeAndRemove(string $key) 97104fd306cSNickeau { 97204fd306cSNickeau $value = $this->getAttribute($key); 97304fd306cSNickeau $this->removeAttribute($key); 97404fd306cSNickeau return $value; 97504fd306cSNickeau } 97604fd306cSNickeau 97704fd306cSNickeau private function getStateName(): string 97804fd306cSNickeau { 97904fd306cSNickeau $state = $this->getState(); 98004fd306cSNickeau switch ($state) { 98104fd306cSNickeau case DOKU_LEXER_ENTER: 98204fd306cSNickeau return "enter"; 98304fd306cSNickeau case DOKU_LEXER_EXIT: 98404fd306cSNickeau return "exit"; 98504fd306cSNickeau case DOKU_LEXER_SPECIAL: 98604fd306cSNickeau return "empty"; 98704fd306cSNickeau case DOKU_LEXER_UNMATCHED: 98804fd306cSNickeau return "text"; 98904fd306cSNickeau default: 99004fd306cSNickeau return "unknown " . $state; 99104fd306cSNickeau } 99204fd306cSNickeau } 99304fd306cSNickeau 99437748cd8SNickeau 99537748cd8SNickeau} 996