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; 16*1fa8c418SNickeauuse syntax_plugin_combo_media; 17*1fa8c418SNickeauuse 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", 6137748cd8SNickeau "monospace", 6237748cd8SNickeau "subscript", 6337748cd8SNickeau "superscript", 6437748cd8SNickeau "deleted", 6537748cd8SNickeau "footnote", 6637748cd8SNickeau /** 6737748cd8SNickeau * Others 6837748cd8SNickeau */ 69*1fa8c418SNickeau "acronym", // abbr 7037748cd8SNickeau "strong_close", 7137748cd8SNickeau "strong_open", 7237748cd8SNickeau "monospace_open", 7337748cd8SNickeau "monospace_close", 7437748cd8SNickeau "doublequoteopening", // ie the character " in "The" 7537748cd8SNickeau "entity", // for instance `...` are transformed in character 7637748cd8SNickeau "linebreak", 7737748cd8SNickeau "externallink", 7837748cd8SNickeau "internallink", 7937748cd8SNickeau MediaLink::INTERNAL_MEDIA_CALL_NAME, 8037748cd8SNickeau MediaLink::EXTERNAL_MEDIA_CALL_NAME, 8137748cd8SNickeau /** 8237748cd8SNickeau * The inline of combo 8337748cd8SNickeau */ 8437748cd8SNickeau \syntax_plugin_combo_link::TAG, 8537748cd8SNickeau \syntax_plugin_combo_icon::TAG, 8637748cd8SNickeau \syntax_plugin_combo_inote::TAG, 8737748cd8SNickeau \syntax_plugin_combo_button::TAG, 8837748cd8SNickeau \syntax_plugin_combo_tooltip::TAG, 8937748cd8SNickeau \syntax_plugin_combo_pipeline::TAG, 9037748cd8SNickeau ); 9137748cd8SNickeau 9237748cd8SNickeau 9337748cd8SNickeau const BLOCK_MARKUP_DOKUWIKI_COMPONENTS = array( 9437748cd8SNickeau "listu_open", // ul 9537748cd8SNickeau "listu_close", 9637748cd8SNickeau "listitem_open", //li 9737748cd8SNickeau "listitem_close", 9837748cd8SNickeau "listcontent_open", // after li ??? 9937748cd8SNickeau "listcontent_close", 10037748cd8SNickeau "table_open", 10137748cd8SNickeau "table_close", 10237748cd8SNickeau ); 10337748cd8SNickeau 104*1fa8c418SNickeau /** 105*1fa8c418SNickeau * A media is not really an image 106*1fa8c418SNickeau * but it may contains one 107*1fa8c418SNickeau */ 108*1fa8c418SNickeau const IMAGE_TAGS = [ 109*1fa8c418SNickeau syntax_plugin_combo_media::TAG, 110*1fa8c418SNickeau syntax_plugin_combo_pageimage::TAG 111*1fa8c418SNickeau ]; 112*1fa8c418SNickeau 11337748cd8SNickeau private $call; 11437748cd8SNickeau 11537748cd8SNickeau /** 11637748cd8SNickeau * The key identifier in the {@link CallStack} 11737748cd8SNickeau * @var mixed|string 11837748cd8SNickeau */ 11937748cd8SNickeau private $key; 12037748cd8SNickeau 12137748cd8SNickeau /** 12237748cd8SNickeau * Call constructor. 12337748cd8SNickeau * @param $call - the instruction array (ie called a call) 12437748cd8SNickeau */ 12537748cd8SNickeau public function __construct(&$call, $key = "") 12637748cd8SNickeau { 12737748cd8SNickeau $this->call = &$call; 12837748cd8SNickeau $this->key = $key; 12937748cd8SNickeau } 13037748cd8SNickeau 13137748cd8SNickeau /** 13237748cd8SNickeau * Insert a tag above 13337748cd8SNickeau * @param $tagName 13437748cd8SNickeau * @param $state 13537748cd8SNickeau * @param $attribute 13637748cd8SNickeau * @param $context 13737748cd8SNickeau * @param string $content 13837748cd8SNickeau * @return Call - a call 13937748cd8SNickeau */ 14037748cd8SNickeau public static function createComboCall($tagName, $state, $attribute = array(), $context = null, $content = '', $payload = null) 14137748cd8SNickeau { 14237748cd8SNickeau $data = array( 14337748cd8SNickeau PluginUtility::ATTRIBUTES => $attribute, 14437748cd8SNickeau PluginUtility::CONTEXT => $context, 14537748cd8SNickeau PluginUtility::STATE => $state 14637748cd8SNickeau ); 14737748cd8SNickeau if ($payload != null) { 14837748cd8SNickeau $data[PluginUtility::PAYLOAD] = $payload; 14937748cd8SNickeau } 15037748cd8SNickeau $positionInText = null; 15137748cd8SNickeau 15237748cd8SNickeau $call = [ 15337748cd8SNickeau "plugin", 15437748cd8SNickeau array( 15537748cd8SNickeau PluginUtility::getComponentName($tagName), 15637748cd8SNickeau $data, 15737748cd8SNickeau $state, 15837748cd8SNickeau $content 15937748cd8SNickeau ), 16037748cd8SNickeau $positionInText 16137748cd8SNickeau ]; 16237748cd8SNickeau return new Call($call); 16337748cd8SNickeau } 16437748cd8SNickeau 16537748cd8SNickeau /** 16637748cd8SNickeau * Insert a dokuwiki call 16737748cd8SNickeau * @param $callName 16837748cd8SNickeau * @param $array 16937748cd8SNickeau * @param $positionInText 17037748cd8SNickeau * @return Call 17137748cd8SNickeau */ 17237748cd8SNickeau public static function createNativeCall($callName, $array = [], $positionInText = null) 17337748cd8SNickeau { 17437748cd8SNickeau $call = [ 17537748cd8SNickeau $callName, 17637748cd8SNickeau $array, 17737748cd8SNickeau $positionInText 17837748cd8SNickeau ]; 17937748cd8SNickeau return new Call($call); 18037748cd8SNickeau } 18137748cd8SNickeau 18237748cd8SNickeau public static function createFromInstruction($instruction) 18337748cd8SNickeau { 18437748cd8SNickeau return new Call($instruction); 18537748cd8SNickeau } 18637748cd8SNickeau 18737748cd8SNickeau 18837748cd8SNickeau /** 18937748cd8SNickeau * 19037748cd8SNickeau * Return the tag name from a call array 19137748cd8SNickeau * 19237748cd8SNickeau * This is not the logical tag. 19337748cd8SNickeau * This is much more what's called: 19437748cd8SNickeau * * the component name for a plugin 19537748cd8SNickeau * * or the handler name for dokuwiki 19637748cd8SNickeau * 19737748cd8SNickeau * For a plugin, this is equivalent 19837748cd8SNickeau * to the {@link SyntaxPlugin::getPluginComponent()} 19937748cd8SNickeau * 20037748cd8SNickeau * This is not the fully qualified component name: 20137748cd8SNickeau * * with the plugin as prefix such as in {@link Call::getComponentName()} 20237748cd8SNickeau * * or with the `open` and `close` prefix such as `p_close` ... 20337748cd8SNickeau * 20437748cd8SNickeau * @return mixed|string 20537748cd8SNickeau */ 20637748cd8SNickeau public function getTagName() 20737748cd8SNickeau { 20837748cd8SNickeau $mode = $this->call[0]; 20937748cd8SNickeau if ($mode != "plugin") { 21037748cd8SNickeau 21137748cd8SNickeau /** 21237748cd8SNickeau * This is a standard dokuwiki node 21337748cd8SNickeau */ 21437748cd8SNickeau $dokuWikiNodeName = $this->call[0]; 21537748cd8SNickeau 21637748cd8SNickeau /** 21737748cd8SNickeau * The dokwuiki node name has also the open and close notion 21837748cd8SNickeau * We delete this is not in the doc and therefore not logical 21937748cd8SNickeau */ 22037748cd8SNickeau $tagName = str_replace("_close", "", $dokuWikiNodeName); 22137748cd8SNickeau $tagName = str_replace("_open", "", $tagName); 22237748cd8SNickeau 22337748cd8SNickeau } else { 22437748cd8SNickeau 22537748cd8SNickeau /** 22637748cd8SNickeau * This is a plugin node 22737748cd8SNickeau */ 22837748cd8SNickeau $pluginDokuData = $this->call[1]; 22937748cd8SNickeau $component = $pluginDokuData[0]; 23037748cd8SNickeau if (!is_array($component)) { 23137748cd8SNickeau /** 23237748cd8SNickeau * Tag name from class 23337748cd8SNickeau */ 23437748cd8SNickeau $componentNames = explode("_", $component); 23537748cd8SNickeau /** 23637748cd8SNickeau * To take care of 23737748cd8SNickeau * PHP Warning: sizeof(): Parameter must be an array or an object that implements Countable 23837748cd8SNickeau * in lib/plugins/combo/class/Tag.php on line 314 23937748cd8SNickeau */ 24037748cd8SNickeau if (is_array($componentNames)) { 24137748cd8SNickeau $tagName = $componentNames[sizeof($componentNames) - 1]; 24237748cd8SNickeau } else { 24337748cd8SNickeau $tagName = $component; 24437748cd8SNickeau } 24537748cd8SNickeau } else { 24637748cd8SNickeau // To resolve: explode() expects parameter 2 to be string, array given 24737748cd8SNickeau LogUtility::msg("The call (" . print_r($this->call, true) . ") has an array and not a string as component (" . print_r($component, true) . "). Page: " . PluginUtility::getPageId(), LogUtility::LVL_MSG_ERROR); 24837748cd8SNickeau $tagName = ""; 24937748cd8SNickeau } 25037748cd8SNickeau 25137748cd8SNickeau 25237748cd8SNickeau } 25337748cd8SNickeau return $tagName; 25437748cd8SNickeau 25537748cd8SNickeau } 25637748cd8SNickeau 25737748cd8SNickeau 25837748cd8SNickeau /** 25937748cd8SNickeau * The parser state 26037748cd8SNickeau * @return mixed 26137748cd8SNickeau * May be null (example eol, internallink, ...) 26237748cd8SNickeau */ 26337748cd8SNickeau public function getState() 26437748cd8SNickeau { 26537748cd8SNickeau $mode = $this->call[0]; 26637748cd8SNickeau if ($mode != "plugin") { 26737748cd8SNickeau 26837748cd8SNickeau /** 26937748cd8SNickeau * There is no state because this is a standard 27037748cd8SNickeau * dokuwiki syntax found in {@link \Doku_Renderer_xhtml} 27137748cd8SNickeau * check if this is not a `...._close` or `...._open` 27237748cd8SNickeau * to derive the state 27337748cd8SNickeau */ 27437748cd8SNickeau $mode = $this->call[0]; 27537748cd8SNickeau $lastPositionSepName = strrpos($mode, "_"); 27637748cd8SNickeau $closeOrOpen = substr($mode, $lastPositionSepName + 1); 27737748cd8SNickeau switch ($closeOrOpen) { 27837748cd8SNickeau case "open": 27937748cd8SNickeau return DOKU_LEXER_ENTER; 28037748cd8SNickeau case "close": 28137748cd8SNickeau return DOKU_LEXER_EXIT; 28237748cd8SNickeau default: 28337748cd8SNickeau return null; 28437748cd8SNickeau } 28537748cd8SNickeau 28637748cd8SNickeau } else { 28737748cd8SNickeau // Plugin 28837748cd8SNickeau $returnedArray = $this->call[1]; 28937748cd8SNickeau if (array_key_exists(2, $returnedArray)) { 29037748cd8SNickeau return $returnedArray[2]; 29137748cd8SNickeau } else { 29237748cd8SNickeau return null; 29337748cd8SNickeau } 29437748cd8SNickeau } 29537748cd8SNickeau } 29637748cd8SNickeau 29737748cd8SNickeau /** 29837748cd8SNickeau * @return mixed the data returned from the {@link DokuWiki_Syntax_Plugin::handle} (ie attributes, payload, ...) 29937748cd8SNickeau */ 30037748cd8SNickeau public function &getPluginData() 30137748cd8SNickeau { 30237748cd8SNickeau return $this->call[1][1]; 30337748cd8SNickeau } 30437748cd8SNickeau 30537748cd8SNickeau /** 30637748cd8SNickeau * @return mixed the matched content from the {@link DokuWiki_Syntax_Plugin::handle} 30737748cd8SNickeau */ 30837748cd8SNickeau public function getCapturedContent() 30937748cd8SNickeau { 31037748cd8SNickeau $caller = $this->call[0]; 31137748cd8SNickeau switch ($caller) { 31237748cd8SNickeau case "plugin": 31337748cd8SNickeau return $this->call[1][3]; 31437748cd8SNickeau case "internallink": 31537748cd8SNickeau return '[[' . $this->call[1][0] . '|' . $this->call[1][1] . ']]'; 31637748cd8SNickeau case "eol": 31737748cd8SNickeau return DOKU_LF; 31837748cd8SNickeau case "header": 31937748cd8SNickeau case "cdata": 32037748cd8SNickeau return $this->call[1][0]; 32137748cd8SNickeau default: 32237748cd8SNickeau if (isset($this->call[1][0]) && is_string($this->call[1][0])) { 32337748cd8SNickeau return $this->call[1][0]; 32437748cd8SNickeau } else { 32537748cd8SNickeau return ""; 32637748cd8SNickeau } 32737748cd8SNickeau } 32837748cd8SNickeau } 32937748cd8SNickeau 33037748cd8SNickeau 33137748cd8SNickeau public function getAttributes() 33237748cd8SNickeau { 33337748cd8SNickeau 33437748cd8SNickeau $tagName = $this->getTagName(); 33537748cd8SNickeau switch ($tagName) { 33637748cd8SNickeau case MediaLink::INTERNAL_MEDIA_CALL_NAME: 33737748cd8SNickeau return $this->call[1]; 33837748cd8SNickeau default: 33937748cd8SNickeau $data = $this->getPluginData(); 34037748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES])) { 34137748cd8SNickeau return $data[PluginUtility::ATTRIBUTES]; 34237748cd8SNickeau } else { 34337748cd8SNickeau return null; 34437748cd8SNickeau } 34537748cd8SNickeau } 34637748cd8SNickeau } 34737748cd8SNickeau 34837748cd8SNickeau public function removeAttributes() 34937748cd8SNickeau { 35037748cd8SNickeau 35137748cd8SNickeau $data = &$this->getPluginData(); 35237748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES])) { 35337748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES]); 35437748cd8SNickeau } 35537748cd8SNickeau 35637748cd8SNickeau } 35737748cd8SNickeau 35837748cd8SNickeau public function updateToPluginComponent($component, $state, $attributes = array()) 35937748cd8SNickeau { 36037748cd8SNickeau if ($this->call[0] == "plugin") { 36137748cd8SNickeau $match = $this->call[1][3]; 36237748cd8SNickeau } else { 36337748cd8SNickeau $this->call[0] = "plugin"; 36437748cd8SNickeau $match = ""; 36537748cd8SNickeau } 36637748cd8SNickeau $this->call[1] = array( 36737748cd8SNickeau 0 => $component, 36837748cd8SNickeau 1 => array( 36937748cd8SNickeau PluginUtility::ATTRIBUTES => $attributes, 37037748cd8SNickeau PluginUtility::STATE => $state, 37137748cd8SNickeau ), 37237748cd8SNickeau 2 => $state, 37337748cd8SNickeau 3 => $match 37437748cd8SNickeau ); 37537748cd8SNickeau 37637748cd8SNickeau } 37737748cd8SNickeau 378*1fa8c418SNickeau /** 379*1fa8c418SNickeau * Does the display has been set 380*1fa8c418SNickeau * to override the dokuwiki default 381*1fa8c418SNickeau * ({@link Syntax::getPType()} 382*1fa8c418SNickeau * 383*1fa8c418SNickeau * because an image is by default a inline component 384*1fa8c418SNickeau * but can be a block (ie top image of a card) 385*1fa8c418SNickeau * @return bool 386*1fa8c418SNickeau */ 387*1fa8c418SNickeau public function isDisplaySet(): bool 388*1fa8c418SNickeau { 389*1fa8c418SNickeau return isset($this->call[1][1][PluginUtility::DISPLAY]); 390*1fa8c418SNickeau } 391*1fa8c418SNickeau 39237748cd8SNickeau public function getDisplay() 39337748cd8SNickeau { 394*1fa8c418SNickeau $mode = $this->getMode(); 395*1fa8c418SNickeau if ($mode == "plugin") { 396*1fa8c418SNickeau if ($this->isDisplaySet()) { 397*1fa8c418SNickeau return $this->call[1][1][PluginUtility::DISPLAY]; 398*1fa8c418SNickeau } 399*1fa8c418SNickeau } 400*1fa8c418SNickeau 40137748cd8SNickeau if ($this->getState() == DOKU_LEXER_UNMATCHED) { 40237748cd8SNickeau /** 40337748cd8SNickeau * Unmatched are content (ie text node in XML/HTML) and have 40437748cd8SNickeau * no display 40537748cd8SNickeau */ 40637748cd8SNickeau return Call::INLINE_DISPLAY; 40737748cd8SNickeau } else { 40837748cd8SNickeau $mode = $this->call[0]; 40937748cd8SNickeau if ($mode == "plugin") { 41037748cd8SNickeau global $DOKU_PLUGINS; 41137748cd8SNickeau $component = $this->getComponentName(); 41237748cd8SNickeau /** 41337748cd8SNickeau * @var SyntaxPlugin $syntaxPlugin 41437748cd8SNickeau */ 41537748cd8SNickeau $syntaxPlugin = $DOKU_PLUGINS['syntax'][$component]; 41637748cd8SNickeau $pType = $syntaxPlugin->getPType(); 41737748cd8SNickeau switch ($pType) { 41837748cd8SNickeau case "normal": 41937748cd8SNickeau return Call::INLINE_DISPLAY; 42037748cd8SNickeau case "block": 42137748cd8SNickeau case "stack": 42237748cd8SNickeau return Call::BlOCK_DISPLAY; 42337748cd8SNickeau default: 42437748cd8SNickeau LogUtility::msg("The ptype (" . $pType . ") is unknown."); 42537748cd8SNickeau return null; 42637748cd8SNickeau } 42737748cd8SNickeau } else { 42837748cd8SNickeau if ($mode == "eol") { 42937748cd8SNickeau /** 43037748cd8SNickeau * Control character 43137748cd8SNickeau * We return it as it's used in the 43237748cd8SNickeau * {@link \syntax_plugin_combo_para::fromEolToParagraphUntilEndOfStack()} 43337748cd8SNickeau * to create the paragraph 43437748cd8SNickeau * This is not a block, nor an inline 43537748cd8SNickeau */ 43637748cd8SNickeau return $mode; 43737748cd8SNickeau } 43837748cd8SNickeau 43937748cd8SNickeau if (in_array($mode, self::INLINE_DOKUWIKI_COMPONENTS)) { 44037748cd8SNickeau return Call::INLINE_DISPLAY; 44137748cd8SNickeau } 44237748cd8SNickeau 44337748cd8SNickeau if (in_array($mode, self::BLOCK_MARKUP_DOKUWIKI_COMPONENTS)) { 44437748cd8SNickeau return Call::BlOCK_DISPLAY; 44537748cd8SNickeau } 44637748cd8SNickeau 44737748cd8SNickeau LogUtility::msg("The display of the call with the mode " . $mode . " is unknown"); 44837748cd8SNickeau return null; 44937748cd8SNickeau 45037748cd8SNickeau 45137748cd8SNickeau } 45237748cd8SNickeau } 45337748cd8SNickeau 45437748cd8SNickeau } 45537748cd8SNickeau 45637748cd8SNickeau /** 45737748cd8SNickeau * Same as {@link Call::getTagName()} 45837748cd8SNickeau * but fully qualified 45937748cd8SNickeau * @return string 46037748cd8SNickeau */ 46137748cd8SNickeau public function getComponentName() 46237748cd8SNickeau { 46337748cd8SNickeau $mode = $this->call[0]; 46437748cd8SNickeau if ($mode == "plugin") { 46537748cd8SNickeau $pluginDokuData = $this->call[1]; 46637748cd8SNickeau return $pluginDokuData[0]; 46737748cd8SNickeau } else { 46837748cd8SNickeau return $mode; 46937748cd8SNickeau } 47037748cd8SNickeau } 47137748cd8SNickeau 47237748cd8SNickeau public function updateEolToSpace() 47337748cd8SNickeau { 47437748cd8SNickeau $mode = $this->call[0]; 47537748cd8SNickeau if ($mode != "eol") { 47637748cd8SNickeau LogUtility::msg("You can't update a " . $mode . " to a space. It should be a eol", LogUtility::LVL_MSG_WARNING, "support"); 47737748cd8SNickeau } else { 47837748cd8SNickeau $this->call[0] = "cdata"; 47937748cd8SNickeau $this->call[1] = array( 48037748cd8SNickeau 0 => " " 48137748cd8SNickeau ); 48237748cd8SNickeau } 48337748cd8SNickeau 48437748cd8SNickeau } 48537748cd8SNickeau 48637748cd8SNickeau public function addAttribute($key, $value) 48737748cd8SNickeau { 48837748cd8SNickeau $mode = $this->call[0]; 48937748cd8SNickeau if ($mode == "plugin") { 49037748cd8SNickeau $this->call[1][1][PluginUtility::ATTRIBUTES][$key] = $value; 49137748cd8SNickeau } else { 49237748cd8SNickeau LogUtility::msg("You can't add an attribute to the non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING, "support"); 49337748cd8SNickeau } 49437748cd8SNickeau } 49537748cd8SNickeau 49637748cd8SNickeau public function getContext() 49737748cd8SNickeau { 49837748cd8SNickeau $mode = $this->call[0]; 49937748cd8SNickeau if ($mode == "plugin") { 50037748cd8SNickeau return $this->call[1][1][PluginUtility::CONTEXT]; 50137748cd8SNickeau } else { 50237748cd8SNickeau LogUtility::msg("You can't ask for a context from a non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING, "support"); 50337748cd8SNickeau return null; 50437748cd8SNickeau } 50537748cd8SNickeau } 50637748cd8SNickeau 50737748cd8SNickeau /** 50837748cd8SNickeau * 50937748cd8SNickeau * @return array 51037748cd8SNickeau */ 51137748cd8SNickeau public function toCallArray() 51237748cd8SNickeau { 51337748cd8SNickeau return $this->call; 51437748cd8SNickeau } 51537748cd8SNickeau 51637748cd8SNickeau public function __toString() 51737748cd8SNickeau { 51837748cd8SNickeau $name = $this->key; 51937748cd8SNickeau if (!empty($name)) { 52037748cd8SNickeau $name .= " - "; 52137748cd8SNickeau } 52237748cd8SNickeau $name .= $this->getTagName(); 52337748cd8SNickeau return $name; 52437748cd8SNickeau } 52537748cd8SNickeau 52637748cd8SNickeau public function getType() 52737748cd8SNickeau { 52837748cd8SNickeau if ($this->getState() == DOKU_LEXER_UNMATCHED) { 52937748cd8SNickeau return null; 53037748cd8SNickeau } else { 53137748cd8SNickeau /** 53237748cd8SNickeau * don't use {@link Call::getAttribute()} to get the type 53337748cd8SNickeau * as this function stack also depends on 53437748cd8SNickeau * this function {@link Call::getType()} 53537748cd8SNickeau * to return the value 53637748cd8SNickeau * Ie: if this is a boolean attribute without specified type 53737748cd8SNickeau * if the boolean value is in the type, we return it 53837748cd8SNickeau */ 53937748cd8SNickeau return $this->call[1][1][PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY]; 54037748cd8SNickeau } 54137748cd8SNickeau } 54237748cd8SNickeau 54337748cd8SNickeau /** 54437748cd8SNickeau * @param $key 54537748cd8SNickeau * @param null $default 54637748cd8SNickeau * @return string|null 54737748cd8SNickeau */ 54837748cd8SNickeau public function getAttribute($key, $default = null) 54937748cd8SNickeau { 55037748cd8SNickeau $attributes = $this->getAttributes(); 55137748cd8SNickeau if (isset($attributes[$key])) { 55237748cd8SNickeau return $attributes[$key]; 55337748cd8SNickeau } else { 55437748cd8SNickeau // boolean attribute 55537748cd8SNickeau if ($this->getType() == $key) { 55637748cd8SNickeau return true; 55737748cd8SNickeau } else { 55837748cd8SNickeau return $default; 55937748cd8SNickeau } 56037748cd8SNickeau } 56137748cd8SNickeau } 56237748cd8SNickeau 56337748cd8SNickeau public function getPayload() 56437748cd8SNickeau { 56537748cd8SNickeau $mode = $this->call[0]; 56637748cd8SNickeau if ($mode == "plugin") { 56737748cd8SNickeau return $this->call[1][1][PluginUtility::PAYLOAD]; 56837748cd8SNickeau } else { 56937748cd8SNickeau LogUtility::msg("You can't ask for a payload from a non plugin call mode (" . $mode . ").", LogUtility::LVL_MSG_WARNING, "support"); 57037748cd8SNickeau return null; 57137748cd8SNickeau } 57237748cd8SNickeau } 57337748cd8SNickeau 57437748cd8SNickeau public function setContext($value) 57537748cd8SNickeau { 57637748cd8SNickeau $this->call[1][1][PluginUtility::CONTEXT] = $value; 57737748cd8SNickeau return $this; 57837748cd8SNickeau } 57937748cd8SNickeau 58037748cd8SNickeau public function hasAttribute($attributeName) 58137748cd8SNickeau { 58237748cd8SNickeau $attributes = $this->getAttributes(); 58337748cd8SNickeau if (isset($attributes[$attributeName])) { 58437748cd8SNickeau return true; 58537748cd8SNickeau } else { 58637748cd8SNickeau if ($this->getType() == $attributeName) { 58737748cd8SNickeau return true; 58837748cd8SNickeau } else { 58937748cd8SNickeau return false; 59037748cd8SNickeau } 59137748cd8SNickeau } 59237748cd8SNickeau } 59337748cd8SNickeau 59437748cd8SNickeau public function isPluginCall() 59537748cd8SNickeau { 59637748cd8SNickeau return $this->call[0] === "plugin"; 59737748cd8SNickeau } 59837748cd8SNickeau 59937748cd8SNickeau /** 60037748cd8SNickeau * @return mixed|string the position (ie key) in the array 60137748cd8SNickeau */ 60237748cd8SNickeau public function getKey() 60337748cd8SNickeau { 60437748cd8SNickeau return $this->key; 60537748cd8SNickeau } 60637748cd8SNickeau 60737748cd8SNickeau public function &getCall() 60837748cd8SNickeau { 60937748cd8SNickeau return $this->call; 61037748cd8SNickeau } 61137748cd8SNickeau 61237748cd8SNickeau public function setState($state) 61337748cd8SNickeau { 61437748cd8SNickeau if ($this->call[0] == "plugin") { 61537748cd8SNickeau // for dokuwiki 61637748cd8SNickeau $this->call[1][2] = $state; 61737748cd8SNickeau // for the combo plugin if any 61837748cd8SNickeau if (isset($this->call[1][1][PluginUtility::STATE])) { 61937748cd8SNickeau $this->call[1][1][PluginUtility::STATE] = $state; 62037748cd8SNickeau } 62137748cd8SNickeau } else { 62237748cd8SNickeau LogUtility::msg("This modification of state is not yet supported for a native call"); 62337748cd8SNickeau } 62437748cd8SNickeau } 62537748cd8SNickeau 62637748cd8SNickeau 62737748cd8SNickeau /** 62837748cd8SNickeau * Return the position of the first matched character in the text file 62937748cd8SNickeau * @return mixed 63037748cd8SNickeau */ 63137748cd8SNickeau public function getFirstMatchedCharacterPosition() 63237748cd8SNickeau { 63337748cd8SNickeau 63437748cd8SNickeau return $this->call[2]; 63537748cd8SNickeau 63637748cd8SNickeau } 63737748cd8SNickeau 63837748cd8SNickeau /** 63937748cd8SNickeau * Return the position of the last matched character in the text file 64037748cd8SNickeau * 64137748cd8SNickeau * This is the {@link Call::getFirstMatchedCharacterPosition()} 64237748cd8SNickeau * plus the length of the {@link Call::getCapturedContent()} 64337748cd8SNickeau * matched content 64437748cd8SNickeau * @return int|mixed 64537748cd8SNickeau */ 64637748cd8SNickeau public function getLastMatchedCharacterPosition() 64737748cd8SNickeau { 64837748cd8SNickeau return $this->getFirstMatchedCharacterPosition() + strlen($this->getCapturedContent()); 64937748cd8SNickeau } 65037748cd8SNickeau 65137748cd8SNickeau /** 65237748cd8SNickeau * @param $value string the class string to add 65337748cd8SNickeau * @return Call 65437748cd8SNickeau */ 65537748cd8SNickeau public function addClassName($value) 65637748cd8SNickeau { 65737748cd8SNickeau $class = $this->getAttribute("class"); 65837748cd8SNickeau if ($class != null) { 65937748cd8SNickeau $value = "$class $value"; 66037748cd8SNickeau } 66137748cd8SNickeau $this->addAttribute("class", $value); 66237748cd8SNickeau return $this; 66337748cd8SNickeau 66437748cd8SNickeau } 66537748cd8SNickeau 66637748cd8SNickeau /** 66737748cd8SNickeau * @param $key 66837748cd8SNickeau * @return mixed|null - the delete value of null if not found 66937748cd8SNickeau */ 67037748cd8SNickeau public function removeAttribute($key) 67137748cd8SNickeau { 67237748cd8SNickeau 67337748cd8SNickeau $data = &$this->getPluginData(); 67437748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES][$key])) { 67537748cd8SNickeau $value = $data[PluginUtility::ATTRIBUTES][$key]; 67637748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES][$key]); 67737748cd8SNickeau return $value; 67837748cd8SNickeau } else { 67937748cd8SNickeau // boolean attribute as first attribute 68037748cd8SNickeau if ($this->getType() == $key) { 68137748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY]); 68237748cd8SNickeau return true; 68337748cd8SNickeau } 68437748cd8SNickeau return null; 68537748cd8SNickeau } 68637748cd8SNickeau 68737748cd8SNickeau } 68837748cd8SNickeau 68937748cd8SNickeau public function setPayload($text) 69037748cd8SNickeau { 69137748cd8SNickeau if ($this->isPluginCall()) { 69237748cd8SNickeau $this->call[1][1][PluginUtility::PAYLOAD] = $text; 69337748cd8SNickeau } else { 69437748cd8SNickeau LogUtility::msg("Setting the payload for a non-native call ($this) is not yet implemented"); 69537748cd8SNickeau } 69637748cd8SNickeau } 69737748cd8SNickeau 69837748cd8SNickeau /** 69937748cd8SNickeau * @return bool true if the call is a text call (same as dom text node) 70037748cd8SNickeau */ 70137748cd8SNickeau public function isTextCall() 70237748cd8SNickeau { 70337748cd8SNickeau return ( 70437748cd8SNickeau $this->getState() == DOKU_LEXER_UNMATCHED || 70537748cd8SNickeau $this->getTagName() == "cdata" || 70637748cd8SNickeau $this->getTagName() == "acronym" 70737748cd8SNickeau ); 70837748cd8SNickeau } 70937748cd8SNickeau 71037748cd8SNickeau public function setType($type) 71137748cd8SNickeau { 71237748cd8SNickeau if ($this->isPluginCall()) { 71337748cd8SNickeau $this->call[1][1][PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY] = $type; 71437748cd8SNickeau } else { 71537748cd8SNickeau LogUtility::msg("This is not a plugin call ($this), you can't set the type"); 71637748cd8SNickeau } 71737748cd8SNickeau } 71837748cd8SNickeau 71937748cd8SNickeau public function addCssStyle($key, $value) 72037748cd8SNickeau { 72137748cd8SNickeau $style = $this->getAttribute("style"); 72237748cd8SNickeau $cssValue = "$key:$value"; 72337748cd8SNickeau if ($style != null) { 72437748cd8SNickeau $cssValue = "$style; $cssValue"; 72537748cd8SNickeau } 72637748cd8SNickeau $this->addAttribute("style", $cssValue); 72737748cd8SNickeau } 72837748cd8SNickeau 72937748cd8SNickeau public function setSyntaxComponentFromTag($tag) 73037748cd8SNickeau { 73137748cd8SNickeau 73237748cd8SNickeau if ($this->isPluginCall()) { 73337748cd8SNickeau $this->call[1][0] = PluginUtility::getComponentName($tag); 73437748cd8SNickeau } else { 73537748cd8SNickeau LogUtility::msg("The call ($this) is a native call and we don't support yet the modification of the component to ($tag)"); 73637748cd8SNickeau } 73737748cd8SNickeau } 73837748cd8SNickeau 73937748cd8SNickeau /** 74037748cd8SNickeau * @param Page $page 74137748cd8SNickeau * @return Call 74237748cd8SNickeau */ 74337748cd8SNickeau public function render(Page $page) 74437748cd8SNickeau { 74537748cd8SNickeau return $this->renderFromData(TemplateUtility::getMetadataDataFromPage($page)); 74637748cd8SNickeau } 74737748cd8SNickeau 748*1fa8c418SNickeau public function renderFromData(array $array): Call 74937748cd8SNickeau { 750*1fa8c418SNickeau 751*1fa8c418SNickeau /** 752*1fa8c418SNickeau * Render all attributes 753*1fa8c418SNickeau */ 754*1fa8c418SNickeau $attributes = $this->getAttributes(); 755*1fa8c418SNickeau if ($attributes !== null) { 756*1fa8c418SNickeau foreach ($attributes as $key => $value) { 757*1fa8c418SNickeau if (is_string($value)) { 758*1fa8c418SNickeau $this->addAttribute($key, TemplateUtility::renderStringTemplateFromDataArray($value, $array)); 759*1fa8c418SNickeau } 760*1fa8c418SNickeau } 761*1fa8c418SNickeau } 762*1fa8c418SNickeau 763*1fa8c418SNickeau /** 764*1fa8c418SNickeau * Content rendering 765*1fa8c418SNickeau */ 76637748cd8SNickeau $state = $this->getState(); 76737748cd8SNickeau if ($state == DOKU_LEXER_UNMATCHED) { 76837748cd8SNickeau if ($this->isPluginCall()) { 76937748cd8SNickeau $payload = $this->getPayload(); 77037748cd8SNickeau if (!empty($payload)) { 77137748cd8SNickeau $this->setPayload(TemplateUtility::renderStringTemplateFromDataArray($payload, $array)); 77237748cd8SNickeau } 77337748cd8SNickeau } 77437748cd8SNickeau } else { 77537748cd8SNickeau $tagName = $this->getTagName(); 77637748cd8SNickeau switch ($tagName) { 77737748cd8SNickeau case "eol": 77837748cd8SNickeau break; 77937748cd8SNickeau case "cdata": 78037748cd8SNickeau $payload = $this->getCapturedContent(); 78137748cd8SNickeau $this->setCapturedContent(TemplateUtility::renderStringTemplateFromDataArray($payload, $array)); 78237748cd8SNickeau break; 78337748cd8SNickeau case \syntax_plugin_combo_pipeline::TAG: 78437748cd8SNickeau $pageTemplate = PluginUtility::getTagContent($this->getCapturedContent()); 78537748cd8SNickeau $script = TemplateUtility::renderStringTemplateFromDataArray($pageTemplate, $array); 78637748cd8SNickeau $string = PipelineUtility::execute($script); 78737748cd8SNickeau $this->setPayload($string); 78837748cd8SNickeau break; 78937748cd8SNickeau } 79037748cd8SNickeau } 791*1fa8c418SNickeau 79237748cd8SNickeau return $this; 79337748cd8SNickeau } 79437748cd8SNickeau 79537748cd8SNickeau public function setCapturedContent($content) 79637748cd8SNickeau { 79737748cd8SNickeau $tagName = $this->getTagName(); 79837748cd8SNickeau switch ($tagName) { 79937748cd8SNickeau case "cdata": 80037748cd8SNickeau $this->call[1][0] = $content; 80137748cd8SNickeau break; 80237748cd8SNickeau default: 80337748cd8SNickeau LogUtility::msg("Setting the captured content on a call for the tag ($tagName) is not yet implemented", LogUtility::LVL_MSG_ERROR); 80437748cd8SNickeau } 80537748cd8SNickeau } 80637748cd8SNickeau 807*1fa8c418SNickeau /** 808*1fa8c418SNickeau * Set the display to block or inline 809*1fa8c418SNickeau * One of `block` or `inline` 810*1fa8c418SNickeau */ 811*1fa8c418SNickeau public function setDisplay($display): Call 812*1fa8c418SNickeau { 813*1fa8c418SNickeau $mode = $this->getMode(); 814*1fa8c418SNickeau if ($mode == "plugin") { 815*1fa8c418SNickeau $this->call[1][1][PluginUtility::DISPLAY] = $display; 816*1fa8c418SNickeau } else { 817*1fa8c418SNickeau LogUtility::msg("You can't set a display on a non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING); 818*1fa8c418SNickeau } 819*1fa8c418SNickeau return $this; 820*1fa8c418SNickeau 821*1fa8c418SNickeau } 822*1fa8c418SNickeau 823*1fa8c418SNickeau /** 824*1fa8c418SNickeau * The plugin or not 825*1fa8c418SNickeau * @return mixed 826*1fa8c418SNickeau */ 827*1fa8c418SNickeau private function getMode() 828*1fa8c418SNickeau { 829*1fa8c418SNickeau return $this->call[0]; 830*1fa8c418SNickeau } 831*1fa8c418SNickeau 832*1fa8c418SNickeau /** 833*1fa8c418SNickeau * Return if this an unmatched call with space 834*1fa8c418SNickeau * in captured content 835*1fa8c418SNickeau * @return bool 836*1fa8c418SNickeau */ 837*1fa8c418SNickeau public function isUnMatchedEmptyCall(): bool 838*1fa8c418SNickeau { 839*1fa8c418SNickeau if ($this->getState() === DOKU_LEXER_UNMATCHED && trim($this->getCapturedContent()) === "") { 840*1fa8c418SNickeau return true; 841*1fa8c418SNickeau } 842*1fa8c418SNickeau return false; 843*1fa8c418SNickeau } 844*1fa8c418SNickeau 84537748cd8SNickeau 84637748cd8SNickeau} 847