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; 171fa8c418SNickeauuse syntax_plugin_combo_pageimage; 1837748cd8SNickeau 1937748cd8SNickeau 2037748cd8SNickeau/** 2137748cd8SNickeau * Class Call 2237748cd8SNickeau * @package ComboStrap 2337748cd8SNickeau * 2437748cd8SNickeau * A wrapper around what's called a call 2537748cd8SNickeau * which is an array of information such 2637748cd8SNickeau * the mode, the data 2737748cd8SNickeau * 2837748cd8SNickeau * The {@link CallStack} is the only syntax representation that 2937748cd8SNickeau * is available in DokuWiki 3037748cd8SNickeau */ 3137748cd8SNickeauclass Call 3237748cd8SNickeau{ 3337748cd8SNickeau 3437748cd8SNickeau const INLINE_DISPLAY = "inline"; 3537748cd8SNickeau const BlOCK_DISPLAY = "block"; 3637748cd8SNickeau /** 3737748cd8SNickeau * List of inline components 3837748cd8SNickeau * Used to manage white space before an unmatched string. 3937748cd8SNickeau * The syntax tree of Dokuwiki (ie {@link \Doku_Handler::$calls}) 4037748cd8SNickeau * has only data and no class, for now, we create this 4137748cd8SNickeau * lists manually because this is a hassle to retrieve this information from {@link \DokuWiki_Syntax_Plugin::getType()} 4237748cd8SNickeau */ 4337748cd8SNickeau const INLINE_DOKUWIKI_COMPONENTS = array( 4437748cd8SNickeau /** 4537748cd8SNickeau * Formatting https://www.dokuwiki.org/devel:syntax_plugins#syntax_types 4637748cd8SNickeau * Comes from the {@link \dokuwiki\Parsing\ParserMode\Formatting} class 4737748cd8SNickeau */ 4837748cd8SNickeau "cdata", 4937748cd8SNickeau "unformatted", // ie %% or nowiki 5037748cd8SNickeau "doublequoteclosing", // https://www.dokuwiki.org/config:typography / https://www.dokuwiki.org/wiki:syntax#text_to_html_conversions 5137748cd8SNickeau "doublequoteopening", 5237748cd8SNickeau "singlequoteopening", 5337748cd8SNickeau "singlequoteclosing", 5437748cd8SNickeau "multiplyentity", 5537748cd8SNickeau "apostrophe", 5637748cd8SNickeau "strong", 5737748cd8SNickeau "emphasis", 5837748cd8SNickeau "emphasis_open", 5937748cd8SNickeau "emphasis_close", 6037748cd8SNickeau "underline", 61e4026cd1Sgerardnico "underline_close", 6237748cd8SNickeau "monospace", 6337748cd8SNickeau "subscript", 6437748cd8SNickeau "superscript", 6537748cd8SNickeau "deleted", 6637748cd8SNickeau "footnote", 6737748cd8SNickeau /** 6837748cd8SNickeau * Others 6937748cd8SNickeau */ 701fa8c418SNickeau "acronym", // abbr 7137748cd8SNickeau "strong_close", 7237748cd8SNickeau "strong_open", 7337748cd8SNickeau "monospace_open", 7437748cd8SNickeau "monospace_close", 7537748cd8SNickeau "doublequoteopening", // ie the character " in "The" 7637748cd8SNickeau "entity", // for instance `...` are transformed in character 7737748cd8SNickeau "linebreak", 7837748cd8SNickeau "externallink", 7937748cd8SNickeau "internallink", 8037748cd8SNickeau MediaLink::INTERNAL_MEDIA_CALL_NAME, 8137748cd8SNickeau MediaLink::EXTERNAL_MEDIA_CALL_NAME, 8237748cd8SNickeau /** 8337748cd8SNickeau * The inline of combo 8437748cd8SNickeau */ 8537748cd8SNickeau \syntax_plugin_combo_link::TAG, 8637748cd8SNickeau \syntax_plugin_combo_icon::TAG, 8737748cd8SNickeau \syntax_plugin_combo_inote::TAG, 8837748cd8SNickeau \syntax_plugin_combo_button::TAG, 8937748cd8SNickeau \syntax_plugin_combo_tooltip::TAG, 9037748cd8SNickeau \syntax_plugin_combo_pipeline::TAG, 9137748cd8SNickeau ); 9237748cd8SNickeau 9337748cd8SNickeau 9437748cd8SNickeau const BLOCK_MARKUP_DOKUWIKI_COMPONENTS = array( 9537748cd8SNickeau "listu_open", // ul 9637748cd8SNickeau "listu_close", 9737748cd8SNickeau "listitem_open", //li 9837748cd8SNickeau "listitem_close", 9937748cd8SNickeau "listcontent_open", // after li ??? 10037748cd8SNickeau "listcontent_close", 10137748cd8SNickeau "table_open", 10237748cd8SNickeau "table_close", 10337748cd8SNickeau ); 10437748cd8SNickeau 1051fa8c418SNickeau /** 1061fa8c418SNickeau * A media is not really an image 1071fa8c418SNickeau * but it may contains one 1081fa8c418SNickeau */ 1091fa8c418SNickeau const IMAGE_TAGS = [ 1101fa8c418SNickeau syntax_plugin_combo_media::TAG, 1111fa8c418SNickeau syntax_plugin_combo_pageimage::TAG 1121fa8c418SNickeau ]; 113*4cadd4f8SNickeau const CANONICAL = "call"; 1141fa8c418SNickeau 11537748cd8SNickeau private $call; 11637748cd8SNickeau 11737748cd8SNickeau /** 11837748cd8SNickeau * The key identifier in the {@link CallStack} 11937748cd8SNickeau * @var mixed|string 12037748cd8SNickeau */ 12137748cd8SNickeau private $key; 12237748cd8SNickeau 12337748cd8SNickeau /** 12437748cd8SNickeau * Call constructor. 12537748cd8SNickeau * @param $call - the instruction array (ie called a call) 12637748cd8SNickeau */ 12737748cd8SNickeau public function __construct(&$call, $key = "") 12837748cd8SNickeau { 12937748cd8SNickeau $this->call = &$call; 13037748cd8SNickeau $this->key = $key; 13137748cd8SNickeau } 13237748cd8SNickeau 13337748cd8SNickeau /** 13437748cd8SNickeau * Insert a tag above 13537748cd8SNickeau * @param $tagName 13637748cd8SNickeau * @param $state 137c3437056SNickeau * @param array $attribute 138*4cadd4f8SNickeau * @param string|null $rawContext 139*4cadd4f8SNickeau * @param string|null $content - the parsed content 140c3437056SNickeau * @param string|null $payload - the payload after handler 141c3437056SNickeau * @param int|null $position 14237748cd8SNickeau * @return Call - a call 14337748cd8SNickeau */ 144*4cadd4f8SNickeau public static function createComboCall($tagName, $state, array $attribute = array(), string $rawContext = null, string $content = null, string $payload = null, int $position = null): Call 14537748cd8SNickeau { 14637748cd8SNickeau $data = array( 14737748cd8SNickeau PluginUtility::ATTRIBUTES => $attribute, 148*4cadd4f8SNickeau PluginUtility::CONTEXT => $rawContext, 149c3437056SNickeau PluginUtility::STATE => $state, 150c3437056SNickeau PluginUtility::POSITION => $position 15137748cd8SNickeau ); 15237748cd8SNickeau if ($payload != null) { 15337748cd8SNickeau $data[PluginUtility::PAYLOAD] = $payload; 15437748cd8SNickeau } 155c3437056SNickeau $positionInText = $position; 15637748cd8SNickeau 15737748cd8SNickeau $call = [ 15837748cd8SNickeau "plugin", 15937748cd8SNickeau array( 16037748cd8SNickeau PluginUtility::getComponentName($tagName), 16137748cd8SNickeau $data, 16237748cd8SNickeau $state, 16337748cd8SNickeau $content 16437748cd8SNickeau ), 16537748cd8SNickeau $positionInText 16637748cd8SNickeau ]; 16737748cd8SNickeau return new Call($call); 16837748cd8SNickeau } 16937748cd8SNickeau 17037748cd8SNickeau /** 17137748cd8SNickeau * Insert a dokuwiki call 17237748cd8SNickeau * @param $callName 17337748cd8SNickeau * @param $array 17437748cd8SNickeau * @param $positionInText 17537748cd8SNickeau * @return Call 17637748cd8SNickeau */ 177*4cadd4f8SNickeau public static function createNativeCall($callName, $array = [], $positionInText = null): Call 17837748cd8SNickeau { 17937748cd8SNickeau $call = [ 18037748cd8SNickeau $callName, 18137748cd8SNickeau $array, 18237748cd8SNickeau $positionInText 18337748cd8SNickeau ]; 18437748cd8SNickeau return new Call($call); 18537748cd8SNickeau } 18637748cd8SNickeau 18737748cd8SNickeau public static function createFromInstruction($instruction) 18837748cd8SNickeau { 18937748cd8SNickeau return new Call($instruction); 19037748cd8SNickeau } 19137748cd8SNickeau 192*4cadd4f8SNickeau /** 193*4cadd4f8SNickeau * @param Call $call 194*4cadd4f8SNickeau * @return Call 195*4cadd4f8SNickeau */ 196*4cadd4f8SNickeau public static function createFromCall(Call $call): Call 197*4cadd4f8SNickeau { 198*4cadd4f8SNickeau return self::createFromInstruction($call->toCallArray()); 199*4cadd4f8SNickeau } 200*4cadd4f8SNickeau 20137748cd8SNickeau 20237748cd8SNickeau /** 20337748cd8SNickeau * 20437748cd8SNickeau * Return the tag name from a call array 20537748cd8SNickeau * 20637748cd8SNickeau * This is not the logical tag. 20737748cd8SNickeau * This is much more what's called: 20837748cd8SNickeau * * the component name for a plugin 20937748cd8SNickeau * * or the handler name for dokuwiki 21037748cd8SNickeau * 21137748cd8SNickeau * For a plugin, this is equivalent 21237748cd8SNickeau * to the {@link SyntaxPlugin::getPluginComponent()} 21337748cd8SNickeau * 21437748cd8SNickeau * This is not the fully qualified component name: 21537748cd8SNickeau * * with the plugin as prefix such as in {@link Call::getComponentName()} 21637748cd8SNickeau * * or with the `open` and `close` prefix such as `p_close` ... 21737748cd8SNickeau * 21837748cd8SNickeau * @return mixed|string 21937748cd8SNickeau */ 22037748cd8SNickeau public function getTagName() 22137748cd8SNickeau { 22237748cd8SNickeau $mode = $this->call[0]; 22337748cd8SNickeau if ($mode != "plugin") { 22437748cd8SNickeau 22537748cd8SNickeau /** 22637748cd8SNickeau * This is a standard dokuwiki node 22737748cd8SNickeau */ 22837748cd8SNickeau $dokuWikiNodeName = $this->call[0]; 22937748cd8SNickeau 23037748cd8SNickeau /** 23137748cd8SNickeau * The dokwuiki node name has also the open and close notion 23237748cd8SNickeau * We delete this is not in the doc and therefore not logical 23337748cd8SNickeau */ 23437748cd8SNickeau $tagName = str_replace("_close", "", $dokuWikiNodeName); 23537748cd8SNickeau $tagName = str_replace("_open", "", $tagName); 23637748cd8SNickeau 23737748cd8SNickeau } else { 23837748cd8SNickeau 23937748cd8SNickeau /** 24037748cd8SNickeau * This is a plugin node 24137748cd8SNickeau */ 24237748cd8SNickeau $pluginDokuData = $this->call[1]; 24337748cd8SNickeau $component = $pluginDokuData[0]; 24437748cd8SNickeau if (!is_array($component)) { 24537748cd8SNickeau /** 24637748cd8SNickeau * Tag name from class 24737748cd8SNickeau */ 24837748cd8SNickeau $componentNames = explode("_", $component); 24937748cd8SNickeau /** 25037748cd8SNickeau * To take care of 25137748cd8SNickeau * PHP Warning: sizeof(): Parameter must be an array or an object that implements Countable 25237748cd8SNickeau * in lib/plugins/combo/class/Tag.php on line 314 25337748cd8SNickeau */ 25437748cd8SNickeau if (is_array($componentNames)) { 25537748cd8SNickeau $tagName = $componentNames[sizeof($componentNames) - 1]; 25637748cd8SNickeau } else { 25737748cd8SNickeau $tagName = $component; 25837748cd8SNickeau } 25937748cd8SNickeau } else { 26037748cd8SNickeau // To resolve: explode() expects parameter 2 to be string, array given 261c3437056SNickeau LogUtility::msg("The call (" . print_r($this->call, true) . ") has an array and not a string as component (" . print_r($component, true) . "). Page: " . Page::createPageFromRequestedPage(), LogUtility::LVL_MSG_ERROR); 26237748cd8SNickeau $tagName = ""; 26337748cd8SNickeau } 26437748cd8SNickeau 26537748cd8SNickeau 26637748cd8SNickeau } 26737748cd8SNickeau return $tagName; 26837748cd8SNickeau 26937748cd8SNickeau } 27037748cd8SNickeau 27137748cd8SNickeau 27237748cd8SNickeau /** 27337748cd8SNickeau * The parser state 27437748cd8SNickeau * @return mixed 27537748cd8SNickeau * May be null (example eol, internallink, ...) 27637748cd8SNickeau */ 27737748cd8SNickeau public function getState() 27837748cd8SNickeau { 27937748cd8SNickeau $mode = $this->call[0]; 280*4cadd4f8SNickeau if ($mode !== "plugin") { 28137748cd8SNickeau 28237748cd8SNickeau /** 28337748cd8SNickeau * There is no state because this is a standard 28437748cd8SNickeau * dokuwiki syntax found in {@link \Doku_Renderer_xhtml} 28537748cd8SNickeau * check if this is not a `...._close` or `...._open` 28637748cd8SNickeau * to derive the state 28737748cd8SNickeau */ 28837748cd8SNickeau $mode = $this->call[0]; 28937748cd8SNickeau $lastPositionSepName = strrpos($mode, "_"); 29037748cd8SNickeau $closeOrOpen = substr($mode, $lastPositionSepName + 1); 29137748cd8SNickeau switch ($closeOrOpen) { 29237748cd8SNickeau case "open": 29337748cd8SNickeau return DOKU_LEXER_ENTER; 29437748cd8SNickeau case "close": 29537748cd8SNickeau return DOKU_LEXER_EXIT; 29637748cd8SNickeau default: 29737748cd8SNickeau return null; 29837748cd8SNickeau } 29937748cd8SNickeau 30037748cd8SNickeau } else { 30137748cd8SNickeau // Plugin 30237748cd8SNickeau $returnedArray = $this->call[1]; 30337748cd8SNickeau if (array_key_exists(2, $returnedArray)) { 30437748cd8SNickeau return $returnedArray[2]; 30537748cd8SNickeau } else { 30637748cd8SNickeau return null; 30737748cd8SNickeau } 30837748cd8SNickeau } 30937748cd8SNickeau } 31037748cd8SNickeau 31137748cd8SNickeau /** 31237748cd8SNickeau * @return mixed the data returned from the {@link DokuWiki_Syntax_Plugin::handle} (ie attributes, payload, ...) 31337748cd8SNickeau */ 314*4cadd4f8SNickeau public function &getPluginData($attribute = null) 31537748cd8SNickeau { 316*4cadd4f8SNickeau $data = &$this->call[1][1]; 317*4cadd4f8SNickeau if ($attribute === null) { 318*4cadd4f8SNickeau return $data; 319*4cadd4f8SNickeau } 320*4cadd4f8SNickeau return $data[$attribute]; 321*4cadd4f8SNickeau 32237748cd8SNickeau } 32337748cd8SNickeau 32437748cd8SNickeau /** 32537748cd8SNickeau * @return mixed the matched content from the {@link DokuWiki_Syntax_Plugin::handle} 32637748cd8SNickeau */ 32737748cd8SNickeau public function getCapturedContent() 32837748cd8SNickeau { 32937748cd8SNickeau $caller = $this->call[0]; 33037748cd8SNickeau switch ($caller) { 33137748cd8SNickeau case "plugin": 33237748cd8SNickeau return $this->call[1][3]; 33337748cd8SNickeau case "internallink": 33437748cd8SNickeau return '[[' . $this->call[1][0] . '|' . $this->call[1][1] . ']]'; 33537748cd8SNickeau case "eol": 33637748cd8SNickeau return DOKU_LF; 33737748cd8SNickeau case "header": 33837748cd8SNickeau case "cdata": 33937748cd8SNickeau return $this->call[1][0]; 34037748cd8SNickeau default: 34137748cd8SNickeau if (isset($this->call[1][0]) && is_string($this->call[1][0])) { 34237748cd8SNickeau return $this->call[1][0]; 34337748cd8SNickeau } else { 34437748cd8SNickeau return ""; 34537748cd8SNickeau } 34637748cd8SNickeau } 34737748cd8SNickeau } 34837748cd8SNickeau 34937748cd8SNickeau 350*4cadd4f8SNickeau public function getAttributes(): ?array 35137748cd8SNickeau { 35237748cd8SNickeau 35337748cd8SNickeau $tagName = $this->getTagName(); 35437748cd8SNickeau switch ($tagName) { 35537748cd8SNickeau case MediaLink::INTERNAL_MEDIA_CALL_NAME: 35637748cd8SNickeau return $this->call[1]; 35737748cd8SNickeau default: 35837748cd8SNickeau $data = $this->getPluginData(); 35937748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES])) { 360*4cadd4f8SNickeau $attributes = $data[PluginUtility::ATTRIBUTES]; 361*4cadd4f8SNickeau if (!is_array($attributes)) { 362*4cadd4f8SNickeau $message = "The attributes value are not an array for the call ($this)"; 363*4cadd4f8SNickeau if (PluginUtility::isDevOrTest()) { 364*4cadd4f8SNickeau throw new ExceptionComboRuntime($message, self::CANONICAL); 365*4cadd4f8SNickeau } 366*4cadd4f8SNickeau LogUtility::msg($message); 367*4cadd4f8SNickeau return null; 368*4cadd4f8SNickeau } 369*4cadd4f8SNickeau return $attributes; 37037748cd8SNickeau } else { 37137748cd8SNickeau return null; 37237748cd8SNickeau } 37337748cd8SNickeau } 37437748cd8SNickeau } 37537748cd8SNickeau 37637748cd8SNickeau public function removeAttributes() 37737748cd8SNickeau { 37837748cd8SNickeau 37937748cd8SNickeau $data = &$this->getPluginData(); 38037748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES])) { 38137748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES]); 38237748cd8SNickeau } 38337748cd8SNickeau 38437748cd8SNickeau } 38537748cd8SNickeau 38637748cd8SNickeau public function updateToPluginComponent($component, $state, $attributes = array()) 38737748cd8SNickeau { 38837748cd8SNickeau if ($this->call[0] == "plugin") { 38937748cd8SNickeau $match = $this->call[1][3]; 39037748cd8SNickeau } else { 39137748cd8SNickeau $this->call[0] = "plugin"; 39237748cd8SNickeau $match = ""; 39337748cd8SNickeau } 39437748cd8SNickeau $this->call[1] = array( 39537748cd8SNickeau 0 => $component, 39637748cd8SNickeau 1 => array( 39737748cd8SNickeau PluginUtility::ATTRIBUTES => $attributes, 39837748cd8SNickeau PluginUtility::STATE => $state, 39937748cd8SNickeau ), 40037748cd8SNickeau 2 => $state, 40137748cd8SNickeau 3 => $match 40237748cd8SNickeau ); 40337748cd8SNickeau 40437748cd8SNickeau } 40537748cd8SNickeau 4061fa8c418SNickeau /** 4071fa8c418SNickeau * Does the display has been set 4081fa8c418SNickeau * to override the dokuwiki default 4091fa8c418SNickeau * ({@link Syntax::getPType()} 4101fa8c418SNickeau * 4111fa8c418SNickeau * because an image is by default a inline component 4121fa8c418SNickeau * but can be a block (ie top image of a card) 4131fa8c418SNickeau * @return bool 4141fa8c418SNickeau */ 4151fa8c418SNickeau public function isDisplaySet(): bool 4161fa8c418SNickeau { 4171fa8c418SNickeau return isset($this->call[1][1][PluginUtility::DISPLAY]); 4181fa8c418SNickeau } 4191fa8c418SNickeau 42037748cd8SNickeau public function getDisplay() 42137748cd8SNickeau { 4221fa8c418SNickeau $mode = $this->getMode(); 4231fa8c418SNickeau if ($mode == "plugin") { 4241fa8c418SNickeau if ($this->isDisplaySet()) { 4251fa8c418SNickeau return $this->call[1][1][PluginUtility::DISPLAY]; 4261fa8c418SNickeau } 4271fa8c418SNickeau } 4281fa8c418SNickeau 42937748cd8SNickeau if ($this->getState() == DOKU_LEXER_UNMATCHED) { 43037748cd8SNickeau /** 43137748cd8SNickeau * Unmatched are content (ie text node in XML/HTML) and have 43237748cd8SNickeau * no display 43337748cd8SNickeau */ 43437748cd8SNickeau return Call::INLINE_DISPLAY; 43537748cd8SNickeau } else { 43637748cd8SNickeau $mode = $this->call[0]; 43737748cd8SNickeau if ($mode == "plugin") { 43837748cd8SNickeau global $DOKU_PLUGINS; 43937748cd8SNickeau $component = $this->getComponentName(); 44037748cd8SNickeau /** 44137748cd8SNickeau * @var SyntaxPlugin $syntaxPlugin 44237748cd8SNickeau */ 44337748cd8SNickeau $syntaxPlugin = $DOKU_PLUGINS['syntax'][$component]; 44437748cd8SNickeau $pType = $syntaxPlugin->getPType(); 44537748cd8SNickeau switch ($pType) { 44637748cd8SNickeau case "normal": 44737748cd8SNickeau return Call::INLINE_DISPLAY; 44837748cd8SNickeau case "block": 44937748cd8SNickeau case "stack": 45037748cd8SNickeau return Call::BlOCK_DISPLAY; 45137748cd8SNickeau default: 45237748cd8SNickeau LogUtility::msg("The ptype (" . $pType . ") is unknown."); 45337748cd8SNickeau return null; 45437748cd8SNickeau } 45537748cd8SNickeau } else { 45637748cd8SNickeau if ($mode == "eol") { 45737748cd8SNickeau /** 45837748cd8SNickeau * Control character 45937748cd8SNickeau * We return it as it's used in the 46037748cd8SNickeau * {@link \syntax_plugin_combo_para::fromEolToParagraphUntilEndOfStack()} 46137748cd8SNickeau * to create the paragraph 46237748cd8SNickeau * This is not a block, nor an inline 46337748cd8SNickeau */ 46437748cd8SNickeau return $mode; 46537748cd8SNickeau } 46637748cd8SNickeau 46737748cd8SNickeau if (in_array($mode, self::INLINE_DOKUWIKI_COMPONENTS)) { 46837748cd8SNickeau return Call::INLINE_DISPLAY; 46937748cd8SNickeau } 47037748cd8SNickeau 47137748cd8SNickeau if (in_array($mode, self::BLOCK_MARKUP_DOKUWIKI_COMPONENTS)) { 47237748cd8SNickeau return Call::BlOCK_DISPLAY; 47337748cd8SNickeau } 47437748cd8SNickeau 47537748cd8SNickeau LogUtility::msg("The display of the call with the mode " . $mode . " is unknown"); 47637748cd8SNickeau return null; 47737748cd8SNickeau 47837748cd8SNickeau 47937748cd8SNickeau } 48037748cd8SNickeau } 48137748cd8SNickeau 48237748cd8SNickeau } 48337748cd8SNickeau 48437748cd8SNickeau /** 48537748cd8SNickeau * Same as {@link Call::getTagName()} 48637748cd8SNickeau * but fully qualified 48737748cd8SNickeau * @return string 48837748cd8SNickeau */ 48937748cd8SNickeau public function getComponentName() 49037748cd8SNickeau { 49137748cd8SNickeau $mode = $this->call[0]; 49237748cd8SNickeau if ($mode == "plugin") { 49337748cd8SNickeau $pluginDokuData = $this->call[1]; 49437748cd8SNickeau return $pluginDokuData[0]; 49537748cd8SNickeau } else { 49637748cd8SNickeau return $mode; 49737748cd8SNickeau } 49837748cd8SNickeau } 49937748cd8SNickeau 50037748cd8SNickeau public function updateEolToSpace() 50137748cd8SNickeau { 50237748cd8SNickeau $mode = $this->call[0]; 50337748cd8SNickeau if ($mode != "eol") { 50437748cd8SNickeau LogUtility::msg("You can't update a " . $mode . " to a space. It should be a eol", LogUtility::LVL_MSG_WARNING, "support"); 50537748cd8SNickeau } else { 50637748cd8SNickeau $this->call[0] = "cdata"; 50737748cd8SNickeau $this->call[1] = array( 50837748cd8SNickeau 0 => " " 50937748cd8SNickeau ); 51037748cd8SNickeau } 51137748cd8SNickeau 51237748cd8SNickeau } 51337748cd8SNickeau 51437748cd8SNickeau public function addAttribute($key, $value) 51537748cd8SNickeau { 51637748cd8SNickeau $mode = $this->call[0]; 51737748cd8SNickeau if ($mode == "plugin") { 51837748cd8SNickeau $this->call[1][1][PluginUtility::ATTRIBUTES][$key] = $value; 51937748cd8SNickeau } else { 52037748cd8SNickeau LogUtility::msg("You can't add an attribute to the non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING, "support"); 52137748cd8SNickeau } 52237748cd8SNickeau } 52337748cd8SNickeau 52437748cd8SNickeau public function getContext() 52537748cd8SNickeau { 52637748cd8SNickeau $mode = $this->call[0]; 52737748cd8SNickeau if ($mode == "plugin") { 52837748cd8SNickeau return $this->call[1][1][PluginUtility::CONTEXT]; 52937748cd8SNickeau } else { 53037748cd8SNickeau LogUtility::msg("You can't ask for a context from a non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING, "support"); 53137748cd8SNickeau return null; 53237748cd8SNickeau } 53337748cd8SNickeau } 53437748cd8SNickeau 53537748cd8SNickeau /** 53637748cd8SNickeau * 53737748cd8SNickeau * @return array 53837748cd8SNickeau */ 53937748cd8SNickeau public function toCallArray() 54037748cd8SNickeau { 54137748cd8SNickeau return $this->call; 54237748cd8SNickeau } 54337748cd8SNickeau 54437748cd8SNickeau public function __toString() 54537748cd8SNickeau { 54637748cd8SNickeau $name = $this->key; 54737748cd8SNickeau if (!empty($name)) { 54837748cd8SNickeau $name .= " - "; 54937748cd8SNickeau } 55037748cd8SNickeau $name .= $this->getTagName(); 55137748cd8SNickeau return $name; 55237748cd8SNickeau } 55337748cd8SNickeau 554*4cadd4f8SNickeau /** 555*4cadd4f8SNickeau * @return string|null 556*4cadd4f8SNickeau * 557*4cadd4f8SNickeau * If the type returned is a boolean attribute, 558*4cadd4f8SNickeau * it means you need to define the expected types 559*4cadd4f8SNickeau * in the function {@link TagAttributes::createFromTagMatch()} 560*4cadd4f8SNickeau * as third attribute 561*4cadd4f8SNickeau */ 562*4cadd4f8SNickeau public function getType(): ?string 56337748cd8SNickeau { 56437748cd8SNickeau if ($this->getState() == DOKU_LEXER_UNMATCHED) { 56537748cd8SNickeau return null; 56637748cd8SNickeau } else { 567*4cadd4f8SNickeau return $this->getAttribute(TagAttributes::TYPE_KEY); 56837748cd8SNickeau } 56937748cd8SNickeau } 57037748cd8SNickeau 57137748cd8SNickeau /** 57237748cd8SNickeau * @param $key 57337748cd8SNickeau * @param null $default 574*4cadd4f8SNickeau * @return array|string|null 57537748cd8SNickeau */ 57637748cd8SNickeau public function getAttribute($key, $default = null) 57737748cd8SNickeau { 57837748cd8SNickeau $attributes = $this->getAttributes(); 57937748cd8SNickeau if (isset($attributes[$key])) { 58037748cd8SNickeau return $attributes[$key]; 581*4cadd4f8SNickeau } 58237748cd8SNickeau return $default; 583*4cadd4f8SNickeau 58437748cd8SNickeau } 58537748cd8SNickeau 586*4cadd4f8SNickeau public 587*4cadd4f8SNickeau function getPayload() 58837748cd8SNickeau { 58937748cd8SNickeau $mode = $this->call[0]; 59037748cd8SNickeau if ($mode == "plugin") { 59137748cd8SNickeau return $this->call[1][1][PluginUtility::PAYLOAD]; 59237748cd8SNickeau } else { 59337748cd8SNickeau LogUtility::msg("You can't ask for a payload from a non plugin call mode (" . $mode . ").", LogUtility::LVL_MSG_WARNING, "support"); 59437748cd8SNickeau return null; 59537748cd8SNickeau } 59637748cd8SNickeau } 59737748cd8SNickeau 598*4cadd4f8SNickeau public 599*4cadd4f8SNickeau function setContext($value) 60037748cd8SNickeau { 60137748cd8SNickeau $this->call[1][1][PluginUtility::CONTEXT] = $value; 60237748cd8SNickeau return $this; 60337748cd8SNickeau } 60437748cd8SNickeau 605*4cadd4f8SNickeau public 606*4cadd4f8SNickeau function hasAttribute($attributeName): bool 60737748cd8SNickeau { 60837748cd8SNickeau $attributes = $this->getAttributes(); 60937748cd8SNickeau if (isset($attributes[$attributeName])) { 61037748cd8SNickeau return true; 61137748cd8SNickeau } else { 61237748cd8SNickeau if ($this->getType() == $attributeName) { 61337748cd8SNickeau return true; 61437748cd8SNickeau } else { 61537748cd8SNickeau return false; 61637748cd8SNickeau } 61737748cd8SNickeau } 61837748cd8SNickeau } 61937748cd8SNickeau 620*4cadd4f8SNickeau public 621*4cadd4f8SNickeau function isPluginCall() 62237748cd8SNickeau { 62337748cd8SNickeau return $this->call[0] === "plugin"; 62437748cd8SNickeau } 62537748cd8SNickeau 62637748cd8SNickeau /** 62737748cd8SNickeau * @return mixed|string the position (ie key) in the array 62837748cd8SNickeau */ 629*4cadd4f8SNickeau public 630*4cadd4f8SNickeau function getKey() 63137748cd8SNickeau { 63237748cd8SNickeau return $this->key; 63337748cd8SNickeau } 63437748cd8SNickeau 635*4cadd4f8SNickeau public 636*4cadd4f8SNickeau function &getCall() 63737748cd8SNickeau { 63837748cd8SNickeau return $this->call; 63937748cd8SNickeau } 64037748cd8SNickeau 641*4cadd4f8SNickeau public 642*4cadd4f8SNickeau function setState($state) 64337748cd8SNickeau { 64437748cd8SNickeau if ($this->call[0] == "plugin") { 64537748cd8SNickeau // for dokuwiki 64637748cd8SNickeau $this->call[1][2] = $state; 64737748cd8SNickeau // for the combo plugin if any 64837748cd8SNickeau if (isset($this->call[1][1][PluginUtility::STATE])) { 64937748cd8SNickeau $this->call[1][1][PluginUtility::STATE] = $state; 65037748cd8SNickeau } 65137748cd8SNickeau } else { 65237748cd8SNickeau LogUtility::msg("This modification of state is not yet supported for a native call"); 65337748cd8SNickeau } 65437748cd8SNickeau } 65537748cd8SNickeau 65637748cd8SNickeau 65737748cd8SNickeau /** 65837748cd8SNickeau * Return the position of the first matched character in the text file 65937748cd8SNickeau * @return mixed 66037748cd8SNickeau */ 661*4cadd4f8SNickeau public 662*4cadd4f8SNickeau function getFirstMatchedCharacterPosition() 66337748cd8SNickeau { 66437748cd8SNickeau 66537748cd8SNickeau return $this->call[2]; 66637748cd8SNickeau 66737748cd8SNickeau } 66837748cd8SNickeau 66937748cd8SNickeau /** 67037748cd8SNickeau * Return the position of the last matched character in the text file 67137748cd8SNickeau * 67237748cd8SNickeau * This is the {@link Call::getFirstMatchedCharacterPosition()} 67337748cd8SNickeau * plus the length of the {@link Call::getCapturedContent()} 67437748cd8SNickeau * matched content 67537748cd8SNickeau * @return int|mixed 67637748cd8SNickeau */ 677*4cadd4f8SNickeau public 678*4cadd4f8SNickeau function getLastMatchedCharacterPosition() 67937748cd8SNickeau { 68037748cd8SNickeau return $this->getFirstMatchedCharacterPosition() + strlen($this->getCapturedContent()); 68137748cd8SNickeau } 68237748cd8SNickeau 68337748cd8SNickeau /** 68437748cd8SNickeau * @param $value string the class string to add 68537748cd8SNickeau * @return Call 68637748cd8SNickeau */ 687*4cadd4f8SNickeau public 688*4cadd4f8SNickeau function addClassName(string $value): Call 68937748cd8SNickeau { 69037748cd8SNickeau $class = $this->getAttribute("class"); 69137748cd8SNickeau if ($class != null) { 69237748cd8SNickeau $value = "$class $value"; 69337748cd8SNickeau } 69437748cd8SNickeau $this->addAttribute("class", $value); 69537748cd8SNickeau return $this; 69637748cd8SNickeau 69737748cd8SNickeau } 69837748cd8SNickeau 69937748cd8SNickeau /** 70037748cd8SNickeau * @param $key 70137748cd8SNickeau * @return mixed|null - the delete value of null if not found 70237748cd8SNickeau */ 703*4cadd4f8SNickeau public 704*4cadd4f8SNickeau function removeAttribute($key) 70537748cd8SNickeau { 70637748cd8SNickeau 70737748cd8SNickeau $data = &$this->getPluginData(); 70837748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES][$key])) { 70937748cd8SNickeau $value = $data[PluginUtility::ATTRIBUTES][$key]; 71037748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES][$key]); 71137748cd8SNickeau return $value; 71237748cd8SNickeau } else { 71337748cd8SNickeau // boolean attribute as first attribute 71437748cd8SNickeau if ($this->getType() == $key) { 71537748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY]); 71637748cd8SNickeau return true; 71737748cd8SNickeau } 71837748cd8SNickeau return null; 71937748cd8SNickeau } 72037748cd8SNickeau 72137748cd8SNickeau } 72237748cd8SNickeau 723*4cadd4f8SNickeau public 724*4cadd4f8SNickeau function setPayload($text) 72537748cd8SNickeau { 72637748cd8SNickeau if ($this->isPluginCall()) { 72737748cd8SNickeau $this->call[1][1][PluginUtility::PAYLOAD] = $text; 72837748cd8SNickeau } else { 72937748cd8SNickeau LogUtility::msg("Setting the payload for a non-native call ($this) is not yet implemented"); 73037748cd8SNickeau } 73137748cd8SNickeau } 73237748cd8SNickeau 73337748cd8SNickeau /** 73437748cd8SNickeau * @return bool true if the call is a text call (same as dom text node) 73537748cd8SNickeau */ 736*4cadd4f8SNickeau public 737*4cadd4f8SNickeau function isTextCall() 73837748cd8SNickeau { 73937748cd8SNickeau return ( 74037748cd8SNickeau $this->getState() == DOKU_LEXER_UNMATCHED || 74137748cd8SNickeau $this->getTagName() == "cdata" || 74237748cd8SNickeau $this->getTagName() == "acronym" 74337748cd8SNickeau ); 74437748cd8SNickeau } 74537748cd8SNickeau 746*4cadd4f8SNickeau public 747*4cadd4f8SNickeau function setType($type) 74837748cd8SNickeau { 74937748cd8SNickeau if ($this->isPluginCall()) { 75037748cd8SNickeau $this->call[1][1][PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY] = $type; 75137748cd8SNickeau } else { 75237748cd8SNickeau LogUtility::msg("This is not a plugin call ($this), you can't set the type"); 75337748cd8SNickeau } 75437748cd8SNickeau } 75537748cd8SNickeau 756*4cadd4f8SNickeau public 757*4cadd4f8SNickeau function addCssStyle($key, $value) 75837748cd8SNickeau { 75937748cd8SNickeau $style = $this->getAttribute("style"); 76037748cd8SNickeau $cssValue = "$key:$value"; 761*4cadd4f8SNickeau if ($style !== null) { 76237748cd8SNickeau $cssValue = "$style; $cssValue"; 76337748cd8SNickeau } 76437748cd8SNickeau $this->addAttribute("style", $cssValue); 76537748cd8SNickeau } 76637748cd8SNickeau 767*4cadd4f8SNickeau public 768*4cadd4f8SNickeau function setSyntaxComponentFromTag($tag) 76937748cd8SNickeau { 77037748cd8SNickeau 77137748cd8SNickeau if ($this->isPluginCall()) { 77237748cd8SNickeau $this->call[1][0] = PluginUtility::getComponentName($tag); 77337748cd8SNickeau } else { 77437748cd8SNickeau LogUtility::msg("The call ($this) is a native call and we don't support yet the modification of the component to ($tag)"); 77537748cd8SNickeau } 77637748cd8SNickeau } 77737748cd8SNickeau 77837748cd8SNickeau /** 77937748cd8SNickeau * @param Page $page 78037748cd8SNickeau * @return Call 78137748cd8SNickeau */ 782*4cadd4f8SNickeau public 783*4cadd4f8SNickeau function render(Page $page) 78437748cd8SNickeau { 78537748cd8SNickeau return $this->renderFromData(TemplateUtility::getMetadataDataFromPage($page)); 78637748cd8SNickeau } 78737748cd8SNickeau 788*4cadd4f8SNickeau public 789*4cadd4f8SNickeau function renderFromData(array $array): Call 79037748cd8SNickeau { 7911fa8c418SNickeau 7921fa8c418SNickeau /** 7931fa8c418SNickeau * Render all attributes 7941fa8c418SNickeau */ 7951fa8c418SNickeau $attributes = $this->getAttributes(); 7961fa8c418SNickeau if ($attributes !== null) { 7971fa8c418SNickeau foreach ($attributes as $key => $value) { 7981fa8c418SNickeau if (is_string($value)) { 7991fa8c418SNickeau $this->addAttribute($key, TemplateUtility::renderStringTemplateFromDataArray($value, $array)); 8001fa8c418SNickeau } 8011fa8c418SNickeau } 8021fa8c418SNickeau } 8031fa8c418SNickeau 8041fa8c418SNickeau /** 8051fa8c418SNickeau * Content rendering 8061fa8c418SNickeau */ 80737748cd8SNickeau $state = $this->getState(); 80837748cd8SNickeau if ($state == DOKU_LEXER_UNMATCHED) { 80937748cd8SNickeau if ($this->isPluginCall()) { 81037748cd8SNickeau $payload = $this->getPayload(); 81137748cd8SNickeau if (!empty($payload)) { 81237748cd8SNickeau $this->setPayload(TemplateUtility::renderStringTemplateFromDataArray($payload, $array)); 81337748cd8SNickeau } 81437748cd8SNickeau } 81537748cd8SNickeau } else { 81637748cd8SNickeau $tagName = $this->getTagName(); 81737748cd8SNickeau switch ($tagName) { 81837748cd8SNickeau case "eol": 81937748cd8SNickeau break; 82037748cd8SNickeau case "cdata": 82137748cd8SNickeau $payload = $this->getCapturedContent(); 82237748cd8SNickeau $this->setCapturedContent(TemplateUtility::renderStringTemplateFromDataArray($payload, $array)); 82337748cd8SNickeau break; 82437748cd8SNickeau case \syntax_plugin_combo_pipeline::TAG: 82537748cd8SNickeau $pageTemplate = PluginUtility::getTagContent($this->getCapturedContent()); 82637748cd8SNickeau $script = TemplateUtility::renderStringTemplateFromDataArray($pageTemplate, $array); 82737748cd8SNickeau $string = PipelineUtility::execute($script); 82837748cd8SNickeau $this->setPayload($string); 82937748cd8SNickeau break; 83037748cd8SNickeau } 83137748cd8SNickeau } 8321fa8c418SNickeau 83337748cd8SNickeau return $this; 83437748cd8SNickeau } 83537748cd8SNickeau 836*4cadd4f8SNickeau public 837*4cadd4f8SNickeau function setCapturedContent($content) 83837748cd8SNickeau { 83937748cd8SNickeau $tagName = $this->getTagName(); 84037748cd8SNickeau switch ($tagName) { 84137748cd8SNickeau case "cdata": 84237748cd8SNickeau $this->call[1][0] = $content; 84337748cd8SNickeau break; 84437748cd8SNickeau default: 84537748cd8SNickeau LogUtility::msg("Setting the captured content on a call for the tag ($tagName) is not yet implemented", LogUtility::LVL_MSG_ERROR); 84637748cd8SNickeau } 84737748cd8SNickeau } 84837748cd8SNickeau 8491fa8c418SNickeau /** 8501fa8c418SNickeau * Set the display to block or inline 8511fa8c418SNickeau * One of `block` or `inline` 8521fa8c418SNickeau */ 853*4cadd4f8SNickeau public 854*4cadd4f8SNickeau function setDisplay($display): Call 8551fa8c418SNickeau { 8561fa8c418SNickeau $mode = $this->getMode(); 8571fa8c418SNickeau if ($mode == "plugin") { 8581fa8c418SNickeau $this->call[1][1][PluginUtility::DISPLAY] = $display; 8591fa8c418SNickeau } else { 8601fa8c418SNickeau LogUtility::msg("You can't set a display on a non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING); 8611fa8c418SNickeau } 8621fa8c418SNickeau return $this; 8631fa8c418SNickeau 8641fa8c418SNickeau } 8651fa8c418SNickeau 8661fa8c418SNickeau /** 8671fa8c418SNickeau * The plugin or not 8681fa8c418SNickeau * @return mixed 8691fa8c418SNickeau */ 870*4cadd4f8SNickeau private 871*4cadd4f8SNickeau function getMode() 8721fa8c418SNickeau { 8731fa8c418SNickeau return $this->call[0]; 8741fa8c418SNickeau } 8751fa8c418SNickeau 8761fa8c418SNickeau /** 8771fa8c418SNickeau * Return if this an unmatched call with space 8781fa8c418SNickeau * in captured content 8791fa8c418SNickeau * @return bool 8801fa8c418SNickeau */ 881*4cadd4f8SNickeau public 882*4cadd4f8SNickeau function isUnMatchedEmptyCall(): bool 8831fa8c418SNickeau { 8841fa8c418SNickeau if ($this->getState() === DOKU_LEXER_UNMATCHED && trim($this->getCapturedContent()) === "") { 8851fa8c418SNickeau return true; 8861fa8c418SNickeau } 8871fa8c418SNickeau return false; 8881fa8c418SNickeau } 8891fa8c418SNickeau 890*4cadd4f8SNickeau public 891*4cadd4f8SNickeau function getExitCode() 892*4cadd4f8SNickeau { 893*4cadd4f8SNickeau $mode = $this->call[0]; 894*4cadd4f8SNickeau if ($mode == "plugin") { 895*4cadd4f8SNickeau $value = $this->call[1][1][PluginUtility::EXIT_CODE]; 896*4cadd4f8SNickeau if ($value === null) { 897*4cadd4f8SNickeau return 0; 898*4cadd4f8SNickeau } 899*4cadd4f8SNickeau return $value; 900*4cadd4f8SNickeau } else { 901*4cadd4f8SNickeau LogUtility::msg("You can't ask for the exit code from a non plugin call mode (" . $mode . ").", LogUtility::LVL_MSG_WARNING, "support"); 902*4cadd4f8SNickeau return 0; 903*4cadd4f8SNickeau } 904*4cadd4f8SNickeau } 905*4cadd4f8SNickeau 906*4cadd4f8SNickeau public function setAttribute(string $name, $value): Call 907*4cadd4f8SNickeau { 908*4cadd4f8SNickeau $this->getPluginData()[PluginUtility::ATTRIBUTES][$name] = $value; 909*4cadd4f8SNickeau return $this; 910*4cadd4f8SNickeau } 911*4cadd4f8SNickeau 912*4cadd4f8SNickeau public function setPluginData(string $name, $value): Call 913*4cadd4f8SNickeau { 914*4cadd4f8SNickeau $this->getPluginData()[$name] = $value; 915*4cadd4f8SNickeau return $this; 916*4cadd4f8SNickeau } 917*4cadd4f8SNickeau 91837748cd8SNickeau 91937748cd8SNickeau} 920