1*37748cd8SNickeau<?php 2*37748cd8SNickeau/** 3*37748cd8SNickeau * Copyright (c) 2021. ComboStrap, Inc. and its affiliates. All Rights Reserved. 4*37748cd8SNickeau * 5*37748cd8SNickeau * This source code is licensed under the GPL license found in the 6*37748cd8SNickeau * COPYING file in the root directory of this source tree. 7*37748cd8SNickeau * 8*37748cd8SNickeau * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 9*37748cd8SNickeau * @author ComboStrap <support@combostrap.com> 10*37748cd8SNickeau * 11*37748cd8SNickeau */ 12*37748cd8SNickeau 13*37748cd8SNickeaunamespace ComboStrap; 14*37748cd8SNickeau 15*37748cd8SNickeauuse dokuwiki\Extension\SyntaxPlugin; 16*37748cd8SNickeau 17*37748cd8SNickeau 18*37748cd8SNickeau/** 19*37748cd8SNickeau * Class Call 20*37748cd8SNickeau * @package ComboStrap 21*37748cd8SNickeau * 22*37748cd8SNickeau * A wrapper around what's called a call 23*37748cd8SNickeau * which is an array of information such 24*37748cd8SNickeau * the mode, the data 25*37748cd8SNickeau * 26*37748cd8SNickeau * The {@link CallStack} is the only syntax representation that 27*37748cd8SNickeau * is available in DokuWiki 28*37748cd8SNickeau */ 29*37748cd8SNickeauclass Call 30*37748cd8SNickeau{ 31*37748cd8SNickeau 32*37748cd8SNickeau const INLINE_DISPLAY = "inline"; 33*37748cd8SNickeau const BlOCK_DISPLAY = "block"; 34*37748cd8SNickeau /** 35*37748cd8SNickeau * List of inline components 36*37748cd8SNickeau * Used to manage white space before an unmatched string. 37*37748cd8SNickeau * The syntax tree of Dokuwiki (ie {@link \Doku_Handler::$calls}) 38*37748cd8SNickeau * has only data and no class, for now, we create this 39*37748cd8SNickeau * lists manually because this is a hassle to retrieve this information from {@link \DokuWiki_Syntax_Plugin::getType()} 40*37748cd8SNickeau */ 41*37748cd8SNickeau const INLINE_DOKUWIKI_COMPONENTS = array( 42*37748cd8SNickeau /** 43*37748cd8SNickeau * Formatting https://www.dokuwiki.org/devel:syntax_plugins#syntax_types 44*37748cd8SNickeau * Comes from the {@link \dokuwiki\Parsing\ParserMode\Formatting} class 45*37748cd8SNickeau */ 46*37748cd8SNickeau "cdata", 47*37748cd8SNickeau "unformatted", // ie %% or nowiki 48*37748cd8SNickeau "doublequoteclosing", // https://www.dokuwiki.org/config:typography / https://www.dokuwiki.org/wiki:syntax#text_to_html_conversions 49*37748cd8SNickeau "doublequoteopening", 50*37748cd8SNickeau "singlequoteopening", 51*37748cd8SNickeau "singlequoteclosing", 52*37748cd8SNickeau "multiplyentity", 53*37748cd8SNickeau "apostrophe", 54*37748cd8SNickeau "strong", 55*37748cd8SNickeau "emphasis", 56*37748cd8SNickeau "emphasis_open", 57*37748cd8SNickeau "emphasis_close", 58*37748cd8SNickeau "underline", 59*37748cd8SNickeau "monospace", 60*37748cd8SNickeau "subscript", 61*37748cd8SNickeau "superscript", 62*37748cd8SNickeau "deleted", 63*37748cd8SNickeau "footnote", 64*37748cd8SNickeau /** 65*37748cd8SNickeau * Others 66*37748cd8SNickeau */ 67*37748cd8SNickeau "acronym", 68*37748cd8SNickeau "strong_close", 69*37748cd8SNickeau "strong_open", 70*37748cd8SNickeau "monospace_open", 71*37748cd8SNickeau "monospace_close", 72*37748cd8SNickeau "doublequoteopening", // ie the character " in "The" 73*37748cd8SNickeau "entity", // for instance `...` are transformed in character 74*37748cd8SNickeau "linebreak", 75*37748cd8SNickeau "externallink", 76*37748cd8SNickeau "internallink", 77*37748cd8SNickeau MediaLink::INTERNAL_MEDIA_CALL_NAME, 78*37748cd8SNickeau MediaLink::EXTERNAL_MEDIA_CALL_NAME, 79*37748cd8SNickeau /** 80*37748cd8SNickeau * The inline of combo 81*37748cd8SNickeau * TODO: Should be deleted when {@link PluginUtility::renderUnmatched()} is not using the array anymore 82*37748cd8SNickeau * but is using {@link Call::getDisplay()} instead or any other rewrite 83*37748cd8SNickeau */ 84*37748cd8SNickeau \syntax_plugin_combo_link::TAG, 85*37748cd8SNickeau \syntax_plugin_combo_icon::TAG, 86*37748cd8SNickeau \syntax_plugin_combo_inote::TAG, 87*37748cd8SNickeau \syntax_plugin_combo_button::TAG, 88*37748cd8SNickeau \syntax_plugin_combo_tooltip::TAG, 89*37748cd8SNickeau \syntax_plugin_combo_pipeline::TAG, 90*37748cd8SNickeau ); 91*37748cd8SNickeau 92*37748cd8SNickeau 93*37748cd8SNickeau const BLOCK_MARKUP_DOKUWIKI_COMPONENTS = array( 94*37748cd8SNickeau "listu_open", // ul 95*37748cd8SNickeau "listu_close", 96*37748cd8SNickeau "listitem_open", //li 97*37748cd8SNickeau "listitem_close", 98*37748cd8SNickeau "listcontent_open", // after li ??? 99*37748cd8SNickeau "listcontent_close", 100*37748cd8SNickeau "table_open", 101*37748cd8SNickeau "table_close", 102*37748cd8SNickeau ); 103*37748cd8SNickeau 104*37748cd8SNickeau private $call; 105*37748cd8SNickeau 106*37748cd8SNickeau /** 107*37748cd8SNickeau * The key identifier in the {@link CallStack} 108*37748cd8SNickeau * @var mixed|string 109*37748cd8SNickeau */ 110*37748cd8SNickeau private $key; 111*37748cd8SNickeau 112*37748cd8SNickeau /** 113*37748cd8SNickeau * Call constructor. 114*37748cd8SNickeau * @param $call - the instruction array (ie called a call) 115*37748cd8SNickeau */ 116*37748cd8SNickeau public function __construct(&$call, $key = "") 117*37748cd8SNickeau { 118*37748cd8SNickeau $this->call = &$call; 119*37748cd8SNickeau $this->key = $key; 120*37748cd8SNickeau } 121*37748cd8SNickeau 122*37748cd8SNickeau /** 123*37748cd8SNickeau * Insert a tag above 124*37748cd8SNickeau * @param $tagName 125*37748cd8SNickeau * @param $state 126*37748cd8SNickeau * @param $attribute 127*37748cd8SNickeau * @param $context 128*37748cd8SNickeau * @param string $content 129*37748cd8SNickeau * @return Call - a call 130*37748cd8SNickeau */ 131*37748cd8SNickeau public static function createComboCall($tagName, $state, $attribute = array(), $context = null, $content = '', $payload = null) 132*37748cd8SNickeau { 133*37748cd8SNickeau $data = array( 134*37748cd8SNickeau PluginUtility::ATTRIBUTES => $attribute, 135*37748cd8SNickeau PluginUtility::CONTEXT => $context, 136*37748cd8SNickeau PluginUtility::STATE => $state 137*37748cd8SNickeau ); 138*37748cd8SNickeau if ($payload != null) { 139*37748cd8SNickeau $data[PluginUtility::PAYLOAD] = $payload; 140*37748cd8SNickeau } 141*37748cd8SNickeau $positionInText = null; 142*37748cd8SNickeau 143*37748cd8SNickeau $call = [ 144*37748cd8SNickeau "plugin", 145*37748cd8SNickeau array( 146*37748cd8SNickeau PluginUtility::getComponentName($tagName), 147*37748cd8SNickeau $data, 148*37748cd8SNickeau $state, 149*37748cd8SNickeau $content 150*37748cd8SNickeau ), 151*37748cd8SNickeau $positionInText 152*37748cd8SNickeau ]; 153*37748cd8SNickeau return new Call($call); 154*37748cd8SNickeau } 155*37748cd8SNickeau 156*37748cd8SNickeau /** 157*37748cd8SNickeau * Insert a dokuwiki call 158*37748cd8SNickeau * @param $callName 159*37748cd8SNickeau * @param $array 160*37748cd8SNickeau * @param $positionInText 161*37748cd8SNickeau * @return Call 162*37748cd8SNickeau */ 163*37748cd8SNickeau public static function createNativeCall($callName, $array = [], $positionInText = null) 164*37748cd8SNickeau { 165*37748cd8SNickeau $call = [ 166*37748cd8SNickeau $callName, 167*37748cd8SNickeau $array, 168*37748cd8SNickeau $positionInText 169*37748cd8SNickeau ]; 170*37748cd8SNickeau return new Call($call); 171*37748cd8SNickeau } 172*37748cd8SNickeau 173*37748cd8SNickeau public static function createFromInstruction($instruction) 174*37748cd8SNickeau { 175*37748cd8SNickeau return new Call($instruction); 176*37748cd8SNickeau } 177*37748cd8SNickeau 178*37748cd8SNickeau 179*37748cd8SNickeau /** 180*37748cd8SNickeau * 181*37748cd8SNickeau * Return the tag name from a call array 182*37748cd8SNickeau * 183*37748cd8SNickeau * This is not the logical tag. 184*37748cd8SNickeau * This is much more what's called: 185*37748cd8SNickeau * * the component name for a plugin 186*37748cd8SNickeau * * or the handler name for dokuwiki 187*37748cd8SNickeau * 188*37748cd8SNickeau * For a plugin, this is equivalent 189*37748cd8SNickeau * to the {@link SyntaxPlugin::getPluginComponent()} 190*37748cd8SNickeau * 191*37748cd8SNickeau * This is not the fully qualified component name: 192*37748cd8SNickeau * * with the plugin as prefix such as in {@link Call::getComponentName()} 193*37748cd8SNickeau * * or with the `open` and `close` prefix such as `p_close` ... 194*37748cd8SNickeau * 195*37748cd8SNickeau * @return mixed|string 196*37748cd8SNickeau */ 197*37748cd8SNickeau public function getTagName() 198*37748cd8SNickeau { 199*37748cd8SNickeau $mode = $this->call[0]; 200*37748cd8SNickeau if ($mode != "plugin") { 201*37748cd8SNickeau 202*37748cd8SNickeau /** 203*37748cd8SNickeau * This is a standard dokuwiki node 204*37748cd8SNickeau */ 205*37748cd8SNickeau $dokuWikiNodeName = $this->call[0]; 206*37748cd8SNickeau 207*37748cd8SNickeau /** 208*37748cd8SNickeau * The dokwuiki node name has also the open and close notion 209*37748cd8SNickeau * We delete this is not in the doc and therefore not logical 210*37748cd8SNickeau */ 211*37748cd8SNickeau $tagName = str_replace("_close", "", $dokuWikiNodeName); 212*37748cd8SNickeau $tagName = str_replace("_open", "", $tagName); 213*37748cd8SNickeau 214*37748cd8SNickeau } else { 215*37748cd8SNickeau 216*37748cd8SNickeau /** 217*37748cd8SNickeau * This is a plugin node 218*37748cd8SNickeau */ 219*37748cd8SNickeau $pluginDokuData = $this->call[1]; 220*37748cd8SNickeau $component = $pluginDokuData[0]; 221*37748cd8SNickeau if (!is_array($component)) { 222*37748cd8SNickeau /** 223*37748cd8SNickeau * Tag name from class 224*37748cd8SNickeau */ 225*37748cd8SNickeau $componentNames = explode("_", $component); 226*37748cd8SNickeau /** 227*37748cd8SNickeau * To take care of 228*37748cd8SNickeau * PHP Warning: sizeof(): Parameter must be an array or an object that implements Countable 229*37748cd8SNickeau * in lib/plugins/combo/class/Tag.php on line 314 230*37748cd8SNickeau */ 231*37748cd8SNickeau if (is_array($componentNames)) { 232*37748cd8SNickeau $tagName = $componentNames[sizeof($componentNames) - 1]; 233*37748cd8SNickeau } else { 234*37748cd8SNickeau $tagName = $component; 235*37748cd8SNickeau } 236*37748cd8SNickeau } else { 237*37748cd8SNickeau // To resolve: explode() expects parameter 2 to be string, array given 238*37748cd8SNickeau 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); 239*37748cd8SNickeau $tagName = ""; 240*37748cd8SNickeau } 241*37748cd8SNickeau 242*37748cd8SNickeau 243*37748cd8SNickeau } 244*37748cd8SNickeau return $tagName; 245*37748cd8SNickeau 246*37748cd8SNickeau } 247*37748cd8SNickeau 248*37748cd8SNickeau 249*37748cd8SNickeau /** 250*37748cd8SNickeau * The parser state 251*37748cd8SNickeau * @return mixed 252*37748cd8SNickeau * May be null (example eol, internallink, ...) 253*37748cd8SNickeau */ 254*37748cd8SNickeau public function getState() 255*37748cd8SNickeau { 256*37748cd8SNickeau $mode = $this->call[0]; 257*37748cd8SNickeau if ($mode != "plugin") { 258*37748cd8SNickeau 259*37748cd8SNickeau /** 260*37748cd8SNickeau * There is no state because this is a standard 261*37748cd8SNickeau * dokuwiki syntax found in {@link \Doku_Renderer_xhtml} 262*37748cd8SNickeau * check if this is not a `...._close` or `...._open` 263*37748cd8SNickeau * to derive the state 264*37748cd8SNickeau */ 265*37748cd8SNickeau $mode = $this->call[0]; 266*37748cd8SNickeau $lastPositionSepName = strrpos($mode, "_"); 267*37748cd8SNickeau $closeOrOpen = substr($mode, $lastPositionSepName + 1); 268*37748cd8SNickeau switch ($closeOrOpen) { 269*37748cd8SNickeau case "open": 270*37748cd8SNickeau return DOKU_LEXER_ENTER; 271*37748cd8SNickeau case "close": 272*37748cd8SNickeau return DOKU_LEXER_EXIT; 273*37748cd8SNickeau default: 274*37748cd8SNickeau return null; 275*37748cd8SNickeau } 276*37748cd8SNickeau 277*37748cd8SNickeau } else { 278*37748cd8SNickeau // Plugin 279*37748cd8SNickeau $returnedArray = $this->call[1]; 280*37748cd8SNickeau if (array_key_exists(2, $returnedArray)) { 281*37748cd8SNickeau return $returnedArray[2]; 282*37748cd8SNickeau } else { 283*37748cd8SNickeau return null; 284*37748cd8SNickeau } 285*37748cd8SNickeau } 286*37748cd8SNickeau } 287*37748cd8SNickeau 288*37748cd8SNickeau /** 289*37748cd8SNickeau * @return mixed the data returned from the {@link DokuWiki_Syntax_Plugin::handle} (ie attributes, payload, ...) 290*37748cd8SNickeau */ 291*37748cd8SNickeau public function &getPluginData() 292*37748cd8SNickeau { 293*37748cd8SNickeau return $this->call[1][1]; 294*37748cd8SNickeau } 295*37748cd8SNickeau 296*37748cd8SNickeau /** 297*37748cd8SNickeau * @return mixed the matched content from the {@link DokuWiki_Syntax_Plugin::handle} 298*37748cd8SNickeau */ 299*37748cd8SNickeau public function getCapturedContent() 300*37748cd8SNickeau { 301*37748cd8SNickeau $caller = $this->call[0]; 302*37748cd8SNickeau switch ($caller) { 303*37748cd8SNickeau case "plugin": 304*37748cd8SNickeau return $this->call[1][3]; 305*37748cd8SNickeau case "internallink": 306*37748cd8SNickeau return '[[' . $this->call[1][0] . '|' . $this->call[1][1] . ']]'; 307*37748cd8SNickeau case "eol": 308*37748cd8SNickeau return DOKU_LF; 309*37748cd8SNickeau case "header": 310*37748cd8SNickeau case "cdata": 311*37748cd8SNickeau return $this->call[1][0]; 312*37748cd8SNickeau default: 313*37748cd8SNickeau if (isset($this->call[1][0]) && is_string($this->call[1][0])) { 314*37748cd8SNickeau return $this->call[1][0]; 315*37748cd8SNickeau } else { 316*37748cd8SNickeau return ""; 317*37748cd8SNickeau } 318*37748cd8SNickeau } 319*37748cd8SNickeau } 320*37748cd8SNickeau 321*37748cd8SNickeau 322*37748cd8SNickeau public function getAttributes() 323*37748cd8SNickeau { 324*37748cd8SNickeau 325*37748cd8SNickeau $tagName = $this->getTagName(); 326*37748cd8SNickeau switch ($tagName) { 327*37748cd8SNickeau case MediaLink::INTERNAL_MEDIA_CALL_NAME: 328*37748cd8SNickeau return $this->call[1]; 329*37748cd8SNickeau default: 330*37748cd8SNickeau $data = $this->getPluginData(); 331*37748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES])) { 332*37748cd8SNickeau return $data[PluginUtility::ATTRIBUTES]; 333*37748cd8SNickeau } else { 334*37748cd8SNickeau return null; 335*37748cd8SNickeau } 336*37748cd8SNickeau } 337*37748cd8SNickeau } 338*37748cd8SNickeau 339*37748cd8SNickeau public function removeAttributes() 340*37748cd8SNickeau { 341*37748cd8SNickeau 342*37748cd8SNickeau $data = &$this->getPluginData(); 343*37748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES])) { 344*37748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES]); 345*37748cd8SNickeau } 346*37748cd8SNickeau 347*37748cd8SNickeau } 348*37748cd8SNickeau 349*37748cd8SNickeau public function updateToPluginComponent($component, $state, $attributes = array()) 350*37748cd8SNickeau { 351*37748cd8SNickeau if ($this->call[0] == "plugin") { 352*37748cd8SNickeau $match = $this->call[1][3]; 353*37748cd8SNickeau } else { 354*37748cd8SNickeau $this->call[0] = "plugin"; 355*37748cd8SNickeau $match = ""; 356*37748cd8SNickeau } 357*37748cd8SNickeau $this->call[1] = array( 358*37748cd8SNickeau 0 => $component, 359*37748cd8SNickeau 1 => array( 360*37748cd8SNickeau PluginUtility::ATTRIBUTES => $attributes, 361*37748cd8SNickeau PluginUtility::STATE => $state, 362*37748cd8SNickeau ), 363*37748cd8SNickeau 2 => $state, 364*37748cd8SNickeau 3 => $match 365*37748cd8SNickeau ); 366*37748cd8SNickeau 367*37748cd8SNickeau } 368*37748cd8SNickeau 369*37748cd8SNickeau public function getDisplay() 370*37748cd8SNickeau { 371*37748cd8SNickeau if ($this->getState() == DOKU_LEXER_UNMATCHED) { 372*37748cd8SNickeau /** 373*37748cd8SNickeau * Unmatched are content (ie text node in XML/HTML) and have 374*37748cd8SNickeau * no display 375*37748cd8SNickeau */ 376*37748cd8SNickeau return Call::INLINE_DISPLAY; 377*37748cd8SNickeau } else { 378*37748cd8SNickeau $mode = $this->call[0]; 379*37748cd8SNickeau if ($mode == "plugin") { 380*37748cd8SNickeau global $DOKU_PLUGINS; 381*37748cd8SNickeau $component = $this->getComponentName(); 382*37748cd8SNickeau /** 383*37748cd8SNickeau * @var SyntaxPlugin $syntaxPlugin 384*37748cd8SNickeau */ 385*37748cd8SNickeau $syntaxPlugin = $DOKU_PLUGINS['syntax'][$component]; 386*37748cd8SNickeau $pType = $syntaxPlugin->getPType(); 387*37748cd8SNickeau switch ($pType) { 388*37748cd8SNickeau case "normal": 389*37748cd8SNickeau return Call::INLINE_DISPLAY; 390*37748cd8SNickeau case "block": 391*37748cd8SNickeau case "stack": 392*37748cd8SNickeau return Call::BlOCK_DISPLAY; 393*37748cd8SNickeau default: 394*37748cd8SNickeau LogUtility::msg("The ptype (" . $pType . ") is unknown."); 395*37748cd8SNickeau return null; 396*37748cd8SNickeau } 397*37748cd8SNickeau } else { 398*37748cd8SNickeau if ($mode == "eol") { 399*37748cd8SNickeau /** 400*37748cd8SNickeau * Control character 401*37748cd8SNickeau * We return it as it's used in the 402*37748cd8SNickeau * {@link \syntax_plugin_combo_para::fromEolToParagraphUntilEndOfStack()} 403*37748cd8SNickeau * to create the paragraph 404*37748cd8SNickeau * This is not a block, nor an inline 405*37748cd8SNickeau */ 406*37748cd8SNickeau return $mode; 407*37748cd8SNickeau } 408*37748cd8SNickeau 409*37748cd8SNickeau if (in_array($mode, self::INLINE_DOKUWIKI_COMPONENTS)) { 410*37748cd8SNickeau return Call::INLINE_DISPLAY; 411*37748cd8SNickeau } 412*37748cd8SNickeau 413*37748cd8SNickeau if (in_array($mode, self::BLOCK_MARKUP_DOKUWIKI_COMPONENTS)) { 414*37748cd8SNickeau return Call::BlOCK_DISPLAY; 415*37748cd8SNickeau } 416*37748cd8SNickeau 417*37748cd8SNickeau LogUtility::msg("The display of the call with the mode " . $mode . " is unknown"); 418*37748cd8SNickeau return null; 419*37748cd8SNickeau 420*37748cd8SNickeau 421*37748cd8SNickeau } 422*37748cd8SNickeau } 423*37748cd8SNickeau 424*37748cd8SNickeau } 425*37748cd8SNickeau 426*37748cd8SNickeau /** 427*37748cd8SNickeau * Same as {@link Call::getTagName()} 428*37748cd8SNickeau * but fully qualified 429*37748cd8SNickeau * @return string 430*37748cd8SNickeau */ 431*37748cd8SNickeau public function getComponentName() 432*37748cd8SNickeau { 433*37748cd8SNickeau $mode = $this->call[0]; 434*37748cd8SNickeau if ($mode == "plugin") { 435*37748cd8SNickeau $pluginDokuData = $this->call[1]; 436*37748cd8SNickeau return $pluginDokuData[0]; 437*37748cd8SNickeau } else { 438*37748cd8SNickeau return $mode; 439*37748cd8SNickeau } 440*37748cd8SNickeau } 441*37748cd8SNickeau 442*37748cd8SNickeau public function updateEolToSpace() 443*37748cd8SNickeau { 444*37748cd8SNickeau $mode = $this->call[0]; 445*37748cd8SNickeau if ($mode != "eol") { 446*37748cd8SNickeau LogUtility::msg("You can't update a " . $mode . " to a space. It should be a eol", LogUtility::LVL_MSG_WARNING, "support"); 447*37748cd8SNickeau } else { 448*37748cd8SNickeau $this->call[0] = "cdata"; 449*37748cd8SNickeau $this->call[1] = array( 450*37748cd8SNickeau 0 => " " 451*37748cd8SNickeau ); 452*37748cd8SNickeau } 453*37748cd8SNickeau 454*37748cd8SNickeau } 455*37748cd8SNickeau 456*37748cd8SNickeau public function addAttribute($key, $value) 457*37748cd8SNickeau { 458*37748cd8SNickeau $mode = $this->call[0]; 459*37748cd8SNickeau if ($mode == "plugin") { 460*37748cd8SNickeau $this->call[1][1][PluginUtility::ATTRIBUTES][$key] = $value; 461*37748cd8SNickeau } else { 462*37748cd8SNickeau LogUtility::msg("You can't add an attribute to the non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING, "support"); 463*37748cd8SNickeau } 464*37748cd8SNickeau } 465*37748cd8SNickeau 466*37748cd8SNickeau public function getContext() 467*37748cd8SNickeau { 468*37748cd8SNickeau $mode = $this->call[0]; 469*37748cd8SNickeau if ($mode == "plugin") { 470*37748cd8SNickeau return $this->call[1][1][PluginUtility::CONTEXT]; 471*37748cd8SNickeau } else { 472*37748cd8SNickeau LogUtility::msg("You can't ask for a context from a non plugin call mode (" . $mode . ")", LogUtility::LVL_MSG_WARNING, "support"); 473*37748cd8SNickeau return null; 474*37748cd8SNickeau } 475*37748cd8SNickeau } 476*37748cd8SNickeau 477*37748cd8SNickeau /** 478*37748cd8SNickeau * 479*37748cd8SNickeau * @return array 480*37748cd8SNickeau */ 481*37748cd8SNickeau public function toCallArray() 482*37748cd8SNickeau { 483*37748cd8SNickeau return $this->call; 484*37748cd8SNickeau } 485*37748cd8SNickeau 486*37748cd8SNickeau public function __toString() 487*37748cd8SNickeau { 488*37748cd8SNickeau $name = $this->key; 489*37748cd8SNickeau if (!empty($name)) { 490*37748cd8SNickeau $name .= " - "; 491*37748cd8SNickeau } 492*37748cd8SNickeau $name .= $this->getTagName(); 493*37748cd8SNickeau return $name; 494*37748cd8SNickeau } 495*37748cd8SNickeau 496*37748cd8SNickeau public function getType() 497*37748cd8SNickeau { 498*37748cd8SNickeau if ($this->getState() == DOKU_LEXER_UNMATCHED) { 499*37748cd8SNickeau LogUtility::msg("The unmatched tag ($this) does not have any attributes. Get its parent if you want the type", LogUtility::LVL_MSG_ERROR); 500*37748cd8SNickeau return null; 501*37748cd8SNickeau } else { 502*37748cd8SNickeau /** 503*37748cd8SNickeau * don't use {@link Call::getAttribute()} to get the type 504*37748cd8SNickeau * as this function stack also depends on 505*37748cd8SNickeau * this function {@link Call::getType()} 506*37748cd8SNickeau * to return the value 507*37748cd8SNickeau * Ie: if this is a boolean attribute without specified type 508*37748cd8SNickeau * if the boolean value is in the type, we return it 509*37748cd8SNickeau */ 510*37748cd8SNickeau return $this->call[1][1][PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY]; 511*37748cd8SNickeau } 512*37748cd8SNickeau } 513*37748cd8SNickeau 514*37748cd8SNickeau /** 515*37748cd8SNickeau * @param $key 516*37748cd8SNickeau * @param null $default 517*37748cd8SNickeau * @return string|null 518*37748cd8SNickeau */ 519*37748cd8SNickeau public function getAttribute($key, $default = null) 520*37748cd8SNickeau { 521*37748cd8SNickeau $attributes = $this->getAttributes(); 522*37748cd8SNickeau if (isset($attributes[$key])) { 523*37748cd8SNickeau return $attributes[$key]; 524*37748cd8SNickeau } else { 525*37748cd8SNickeau // boolean attribute 526*37748cd8SNickeau if ($this->getType() == $key) { 527*37748cd8SNickeau return true; 528*37748cd8SNickeau } else { 529*37748cd8SNickeau return $default; 530*37748cd8SNickeau } 531*37748cd8SNickeau } 532*37748cd8SNickeau } 533*37748cd8SNickeau 534*37748cd8SNickeau public function getPayload() 535*37748cd8SNickeau { 536*37748cd8SNickeau $mode = $this->call[0]; 537*37748cd8SNickeau if ($mode == "plugin") { 538*37748cd8SNickeau return $this->call[1][1][PluginUtility::PAYLOAD]; 539*37748cd8SNickeau } else { 540*37748cd8SNickeau LogUtility::msg("You can't ask for a payload from a non plugin call mode (" . $mode . ").", LogUtility::LVL_MSG_WARNING, "support"); 541*37748cd8SNickeau return null; 542*37748cd8SNickeau } 543*37748cd8SNickeau } 544*37748cd8SNickeau 545*37748cd8SNickeau public function setContext($value) 546*37748cd8SNickeau { 547*37748cd8SNickeau $this->call[1][1][PluginUtility::CONTEXT] = $value; 548*37748cd8SNickeau return $this; 549*37748cd8SNickeau } 550*37748cd8SNickeau 551*37748cd8SNickeau public function hasAttribute($attributeName) 552*37748cd8SNickeau { 553*37748cd8SNickeau $attributes = $this->getAttributes(); 554*37748cd8SNickeau if (isset($attributes[$attributeName])) { 555*37748cd8SNickeau return true; 556*37748cd8SNickeau } else { 557*37748cd8SNickeau if ($this->getType() == $attributeName) { 558*37748cd8SNickeau return true; 559*37748cd8SNickeau } else { 560*37748cd8SNickeau return false; 561*37748cd8SNickeau } 562*37748cd8SNickeau } 563*37748cd8SNickeau } 564*37748cd8SNickeau 565*37748cd8SNickeau public function isPluginCall() 566*37748cd8SNickeau { 567*37748cd8SNickeau return $this->call[0] === "plugin"; 568*37748cd8SNickeau } 569*37748cd8SNickeau 570*37748cd8SNickeau /** 571*37748cd8SNickeau * @return mixed|string the position (ie key) in the array 572*37748cd8SNickeau */ 573*37748cd8SNickeau public function getKey() 574*37748cd8SNickeau { 575*37748cd8SNickeau return $this->key; 576*37748cd8SNickeau } 577*37748cd8SNickeau 578*37748cd8SNickeau public function &getCall() 579*37748cd8SNickeau { 580*37748cd8SNickeau return $this->call; 581*37748cd8SNickeau } 582*37748cd8SNickeau 583*37748cd8SNickeau public function setState($state) 584*37748cd8SNickeau { 585*37748cd8SNickeau if ($this->call[0] == "plugin") { 586*37748cd8SNickeau // for dokuwiki 587*37748cd8SNickeau $this->call[1][2] = $state; 588*37748cd8SNickeau // for the combo plugin if any 589*37748cd8SNickeau if (isset($this->call[1][1][PluginUtility::STATE])) { 590*37748cd8SNickeau $this->call[1][1][PluginUtility::STATE] = $state; 591*37748cd8SNickeau } 592*37748cd8SNickeau } else { 593*37748cd8SNickeau LogUtility::msg("This modification of state is not yet supported for a native call"); 594*37748cd8SNickeau } 595*37748cd8SNickeau } 596*37748cd8SNickeau 597*37748cd8SNickeau 598*37748cd8SNickeau /** 599*37748cd8SNickeau * Return the position of the first matched character in the text file 600*37748cd8SNickeau * @return mixed 601*37748cd8SNickeau */ 602*37748cd8SNickeau public function getFirstMatchedCharacterPosition() 603*37748cd8SNickeau { 604*37748cd8SNickeau 605*37748cd8SNickeau return $this->call[2]; 606*37748cd8SNickeau 607*37748cd8SNickeau } 608*37748cd8SNickeau 609*37748cd8SNickeau /** 610*37748cd8SNickeau * Return the position of the last matched character in the text file 611*37748cd8SNickeau * 612*37748cd8SNickeau * This is the {@link Call::getFirstMatchedCharacterPosition()} 613*37748cd8SNickeau * plus the length of the {@link Call::getCapturedContent()} 614*37748cd8SNickeau * matched content 615*37748cd8SNickeau * @return int|mixed 616*37748cd8SNickeau */ 617*37748cd8SNickeau public function getLastMatchedCharacterPosition() 618*37748cd8SNickeau { 619*37748cd8SNickeau return $this->getFirstMatchedCharacterPosition() + strlen($this->getCapturedContent()); 620*37748cd8SNickeau } 621*37748cd8SNickeau 622*37748cd8SNickeau /** 623*37748cd8SNickeau * @param $value string the class string to add 624*37748cd8SNickeau * @return Call 625*37748cd8SNickeau */ 626*37748cd8SNickeau public function addClassName($value) 627*37748cd8SNickeau { 628*37748cd8SNickeau $class = $this->getAttribute("class"); 629*37748cd8SNickeau if ($class != null) { 630*37748cd8SNickeau $value = "$class $value"; 631*37748cd8SNickeau } 632*37748cd8SNickeau $this->addAttribute("class", $value); 633*37748cd8SNickeau return $this; 634*37748cd8SNickeau 635*37748cd8SNickeau } 636*37748cd8SNickeau 637*37748cd8SNickeau /** 638*37748cd8SNickeau * @param $key 639*37748cd8SNickeau * @return mixed|null - the delete value of null if not found 640*37748cd8SNickeau */ 641*37748cd8SNickeau public function removeAttribute($key) 642*37748cd8SNickeau { 643*37748cd8SNickeau 644*37748cd8SNickeau $data = &$this->getPluginData(); 645*37748cd8SNickeau if (isset($data[PluginUtility::ATTRIBUTES][$key])) { 646*37748cd8SNickeau $value = $data[PluginUtility::ATTRIBUTES][$key]; 647*37748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES][$key]); 648*37748cd8SNickeau return $value; 649*37748cd8SNickeau } else { 650*37748cd8SNickeau // boolean attribute as first attribute 651*37748cd8SNickeau if ($this->getType() == $key) { 652*37748cd8SNickeau unset($data[PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY]); 653*37748cd8SNickeau return true; 654*37748cd8SNickeau } 655*37748cd8SNickeau return null; 656*37748cd8SNickeau } 657*37748cd8SNickeau 658*37748cd8SNickeau } 659*37748cd8SNickeau 660*37748cd8SNickeau public function setPayload($text) 661*37748cd8SNickeau { 662*37748cd8SNickeau if ($this->isPluginCall()) { 663*37748cd8SNickeau $this->call[1][1][PluginUtility::PAYLOAD] = $text; 664*37748cd8SNickeau } else { 665*37748cd8SNickeau LogUtility::msg("Setting the payload for a non-native call ($this) is not yet implemented"); 666*37748cd8SNickeau } 667*37748cd8SNickeau } 668*37748cd8SNickeau 669*37748cd8SNickeau /** 670*37748cd8SNickeau * @return bool true if the call is a text call (same as dom text node) 671*37748cd8SNickeau */ 672*37748cd8SNickeau public function isTextCall() 673*37748cd8SNickeau { 674*37748cd8SNickeau return ( 675*37748cd8SNickeau $this->getState() == DOKU_LEXER_UNMATCHED || 676*37748cd8SNickeau $this->getTagName() == "cdata" || 677*37748cd8SNickeau $this->getTagName() == "acronym" 678*37748cd8SNickeau ); 679*37748cd8SNickeau } 680*37748cd8SNickeau 681*37748cd8SNickeau public function setType($type) 682*37748cd8SNickeau { 683*37748cd8SNickeau if ($this->isPluginCall()) { 684*37748cd8SNickeau $this->call[1][1][PluginUtility::ATTRIBUTES][TagAttributes::TYPE_KEY] = $type; 685*37748cd8SNickeau } else { 686*37748cd8SNickeau LogUtility::msg("This is not a plugin call ($this), you can't set the type"); 687*37748cd8SNickeau } 688*37748cd8SNickeau } 689*37748cd8SNickeau 690*37748cd8SNickeau public function addCssStyle($key, $value) 691*37748cd8SNickeau { 692*37748cd8SNickeau $style = $this->getAttribute("style"); 693*37748cd8SNickeau $cssValue = "$key:$value"; 694*37748cd8SNickeau if ($style != null) { 695*37748cd8SNickeau $cssValue = "$style; $cssValue"; 696*37748cd8SNickeau } 697*37748cd8SNickeau $this->addAttribute("style", $cssValue); 698*37748cd8SNickeau } 699*37748cd8SNickeau 700*37748cd8SNickeau public function setSyntaxComponentFromTag($tag) 701*37748cd8SNickeau { 702*37748cd8SNickeau 703*37748cd8SNickeau if ($this->isPluginCall()) { 704*37748cd8SNickeau $this->call[1][0] = PluginUtility::getComponentName($tag); 705*37748cd8SNickeau } else { 706*37748cd8SNickeau LogUtility::msg("The call ($this) is a native call and we don't support yet the modification of the component to ($tag)"); 707*37748cd8SNickeau } 708*37748cd8SNickeau } 709*37748cd8SNickeau 710*37748cd8SNickeau /** 711*37748cd8SNickeau * @param Page $page 712*37748cd8SNickeau * @return Call 713*37748cd8SNickeau */ 714*37748cd8SNickeau public function render(Page $page) 715*37748cd8SNickeau { 716*37748cd8SNickeau return $this->renderFromData(TemplateUtility::getMetadataDataFromPage($page)); 717*37748cd8SNickeau } 718*37748cd8SNickeau 719*37748cd8SNickeau public function renderFromData(array $array) 720*37748cd8SNickeau { 721*37748cd8SNickeau $state = $this->getState(); 722*37748cd8SNickeau if ($state == DOKU_LEXER_UNMATCHED) { 723*37748cd8SNickeau if ($this->isPluginCall()) { 724*37748cd8SNickeau $payload = $this->getPayload(); 725*37748cd8SNickeau if (!empty($payload)) { 726*37748cd8SNickeau $this->setPayload(TemplateUtility::renderStringTemplateFromDataArray($payload, $array)); 727*37748cd8SNickeau } 728*37748cd8SNickeau } 729*37748cd8SNickeau } else { 730*37748cd8SNickeau $tagName = $this->getTagName(); 731*37748cd8SNickeau switch ($tagName) { 732*37748cd8SNickeau case "eol": 733*37748cd8SNickeau break; 734*37748cd8SNickeau case "cdata": 735*37748cd8SNickeau $payload = $this->getCapturedContent(); 736*37748cd8SNickeau $this->setCapturedContent(TemplateUtility::renderStringTemplateFromDataArray($payload, $array)); 737*37748cd8SNickeau break; 738*37748cd8SNickeau case \syntax_plugin_combo_pipeline::TAG: 739*37748cd8SNickeau $pageTemplate = PluginUtility::getTagContent($this->getCapturedContent()); 740*37748cd8SNickeau $script = TemplateUtility::renderStringTemplateFromDataArray($pageTemplate, $array); 741*37748cd8SNickeau $string = PipelineUtility::execute($script); 742*37748cd8SNickeau $this->setPayload($string); 743*37748cd8SNickeau break; 744*37748cd8SNickeau case \syntax_plugin_combo_link::TAG: 745*37748cd8SNickeau switch ($this->getState()) { 746*37748cd8SNickeau case DOKU_LEXER_ENTER: 747*37748cd8SNickeau $ref = $this->getAttribute("ref"); 748*37748cd8SNickeau $this->addAttribute("ref", TemplateUtility::renderStringTemplateFromDataArray($ref, $array)); 749*37748cd8SNickeau break; 750*37748cd8SNickeau } 751*37748cd8SNickeau break; 752*37748cd8SNickeau } 753*37748cd8SNickeau } 754*37748cd8SNickeau return $this; 755*37748cd8SNickeau } 756*37748cd8SNickeau 757*37748cd8SNickeau public function setCapturedContent($content) 758*37748cd8SNickeau { 759*37748cd8SNickeau $tagName = $this->getTagName(); 760*37748cd8SNickeau switch ($tagName) { 761*37748cd8SNickeau case "cdata": 762*37748cd8SNickeau $this->call[1][0] = $content; 763*37748cd8SNickeau break; 764*37748cd8SNickeau default: 765*37748cd8SNickeau LogUtility::msg("Setting the captured content on a call for the tag ($tagName) is not yet implemented", LogUtility::LVL_MSG_ERROR); 766*37748cd8SNickeau } 767*37748cd8SNickeau } 768*37748cd8SNickeau 769*37748cd8SNickeau 770*37748cd8SNickeau} 771