function qpuserchoice(Parser &$parser, PPFrame $frame, array $args) { $this->frame = $frame; $this->args =& $args; if (isset($args[0])) { # args[0] is a poll address $this->pollAddr = trim($this->frame->expand($this->args[0])); $this->pollStore = qp_PollStore::newFromAddr($this->pollAddr); if ($this->pollStore instanceof qp_PollStore && $this->pollStore->pid !== null) { $this->error_message = 'missing_question_id'; if (isset($args[1])) { # args[1] is question_id $qdata = $this->getQuestionData(trim($frame->expand($args[1]))); if ($qdata instanceof qp_QuestionData) { $this->error_message = 'missing_proposal_id'; if (isset($args[2])) { # get poll's proposal choice $this->proposal_id = trim($frame->expand($args[2])); $this->error_message = 'invalid_proposal_id'; if (preg_match(qp_Setup::PREG_NON_NEGATIVE_INT4_MATCH, $this->proposal_id)) { $this->defaultProposalText = isset($args[3]) ? trim($frame->expand($args[3])) : ''; $this->proposal_id = intval($this->proposal_id); $this->error_message = 'missing_proposal_id'; if (array_key_exists($this->proposal_id, $qdata->ProposalText)) { return $this->qpuserchoiceValidResult($qdata); } } } } } } } return '<strong class="error">qpuserchoice: ' . wfMsgHTML('qp_func_' . $this->error_message, qp_Setup::specialchars($this->pollAddr), qp_Setup::specialchars($this->question_id), qp_Setup::specialchars($this->proposal_id)) . '</strong>'; }
/** * Magic word 'THIS:' to return certain information about the page the word actually is defined on */ static function pfObj_this(Parser &$parser, PPFrame $frame = null, $args = null) { // if MW version is too old or something is wrong: if ($frame === null || $frame->title === null) { return ''; } // get part behind 'THIS:' if only 'THIS', use 'FULLPAGENAME' $index = isset($args[0]) ? trim($frame->expand($args[0])) : ''; $newArgs = array(); if ($index !== '') { // clean up arguments as if first argument never were set: unset($args[0]); foreach ($args as $arg) { $newArgs[] = $arg; } // get magic word ID of the variable name: $mwId = self::getVariablesMagicWordId($parser, $index); if ($mwId === null) { // requested variable doesn't exist, make the thing a template call return array(null, 'found' => false); } } else { // if only '{{THIS}}', set magic word id to 'FULLPAGENAME' $mwId = 'fullpagename'; } // get value: $out = self::getThisVariableValue($mwId, $parser, $frame, $newArgs); if ($out === null) { // requested variable doesn't support 'THIS:', make the thing a template call return array(null, 'found' => false); } return $out; }
/** * Just "redirect" to $this->IfhascatPf(). * * @param Parser $parser * @param PPFrame $frame */ function IfhascatPfObj(&$parser, $frame, $args) { $page = isset($args[0]) ? trim($frame->expand($args[0])) : ''; $category = isset($args[1]) ? trim($frame->expand($args[1])) : ''; $then = isset($args[2]) ? trim($frame->expand($args[2])) : '1'; $else = isset($args[3]) ? trim($frame->expand($args[3])) : '0'; return $this->IfhascatPf($parser, $page, $category, $then, $else); // *else* }
/** * Method for handling the declare parser function. * * @since 1.5.3 * * @param Parser $parser * @param PPFrame $frame * @param array $args */ public static function render(Parser &$parser, PPFrame $frame, array $args) { if ($frame->isTemplate()) { foreach ($args as $arg) { if (trim($arg) !== '') { $expanded = trim($frame->expand($arg)); $parts = explode('=', $expanded, 2); if (count($parts) == 1) { $propertystring = $expanded; $argumentname = $expanded; } else { $propertystring = $parts[0]; $argumentname = $parts[1]; } $property = SMWPropertyValue::makeUserProperty($propertystring); $argument = $frame->getArgument($argumentname); $valuestring = $frame->expand($argument); if ($property->isValid()) { $type = $property->getPropertyTypeID(); if ($type == '_wpg') { $matches = array(); preg_match_all('/\\[\\[([^\\[\\]]*)\\]\\]/u', $valuestring, $matches); $objects = $matches[1]; if (count($objects) == 0) { if (trim($valuestring) !== '') { SMWParseData::addProperty($propertystring, $valuestring, false, $parser, true); } } else { foreach ($objects as $object) { SMWParseData::addProperty($propertystring, $object, false, $parser, true); } } } elseif (trim($valuestring) !== '') { SMWParseData::addProperty($propertystring, $valuestring, false, $parser, true); } // $value = SMWDataValueFactory::newPropertyObjectValue( $property->getDataItem(), $valuestring ); // if (!$value->isValid()) continue; } } } } else { // @todo Save as metadata } global $wgTitle; if (!is_null($wgTitle) && $wgTitle->isSpecialPage()) { global $wgOut; SMWOutputs::commitToOutputPage($wgOut); } else { SMWOutputs::commitToParser($parser); } return ''; }
/** * #coordinates parser function callback * * @param Parser $parser * @param PPFrame $frame * @param Array $args * @return Mixed */ public function coordinates($parser, $frame, $args) { if ($parser != $this->parser) { throw new MWException(__METHOD__ . '() called by wrong parser'); } $this->output = $parser->getOutput(); if (!isset($this->output->geoData)) { $this->output->geoData = new CoordinatesOutput(); } $this->unnamed = array(); $this->named = array(); $first = trim($frame->expand(array_shift($args))); $this->addArg($first); foreach ($args as $arg) { $bits = $arg->splitArg(); $value = trim($frame->expand($bits['value'])); if ($bits['index'] === '') { $this->named[trim($frame->expand($bits['name']))] = $value; } else { $this->addArg($value); } } $this->parseTagArgs(); $status = GeoData::parseCoordinates($this->unnamed, $this->named['globe']); if ($status->isGood()) { $coord = $status->value; $status = $this->applyTagArgs($coord); if ($status->isGood()) { $status = $this->applyCoord($coord); if ($status->isGood()) { return ''; } } } $parser->addTrackingCategory('geodata-broken-tags-category'); $errorText = $this->errorText($status); if ($errorText == '<>') { // Error that doesn't require a message, // can't think of a better way to pass this condition return ''; } return array("<span class=\"error\">{$errorText}</span>", 'noparse' => false); }
/** * Function executed by use of {{#infoboxbuilder:}} parser function. * It gets the code from InfoboxBuilder.lua and creates new module object * from it. The module is then invoked and the result is returned. * @param Parser $parser Parser object * @param PPFrame $frame PPFrame object * @param array $args Array of arguments passed from $frame object * @return string A string returned by InfoboxBuilder.lua */ public static function parserFunctionHook(\Parser $parser, $frame, $args) { wfProfileIn(__METHOD__); try { /** * Add the registered SCSS with the default theme */ $parser->getOutput()->addModuleStyles('ext.wikia.InfoboxBuilder'); $engine = \Scribunto::getParserEngine($parser); unset($args[0]); $childFrame = $frame->newChild($args, $parser->getTitle(), 1); $moduleText = file_get_contents(__DIR__ . '/includes/lua/InfoboxBuilder.lua'); $module = new \Scribunto_LuaModule($engine, $moduleText, 'InfoboxBuilder'); $result = $module->invoke('builder', $childFrame); $result = \UtfNormal::cleanUp(strval($result)); wfProfileOut(__METHOD__); return $result; } catch (\ScribuntoException $e) { $trace = $e->getScriptTraceHtml(array('msgOptions' => array('content'))); $html = \Html::element('p', array(), $e->getMessage()); if ($trace !== false) { $html .= \Html::element('p', array(), wfMessage('scribunto-common-backtrace')->inContentLanguage()->text()) . $trace; } $out = $parser->getOutput(); if (!isset($out->scribunto_errors)) { $out->addOutputHook('ScribuntoError'); $out->scribunto_errors = array(); $parser->addTrackingCategory('scribunto-common-error-category'); } $out->scribunto_errors[] = $html; $id = 'mw-scribunto-error-' . (count($out->scribunto_errors) - 1); $parserError = wfMessage('scribunto-parser-error')->inContentLanguage()->text() . $parser->insertStripItem('<!--' . htmlspecialchars($e->getMessage()) . '-->'); wfProfileOut(__METHOD__); // #iferror-compatible error element return "<strong class=\"error\"><span class=\"scribunto-error\" id=\"{$id}\">" . $parserError . "</span></strong>"; } }
/** * Make 'Parser Fun' extensions 'THIS' function work with our variables/functions */ static function onGetThisVariableValueSwitch( Parser &$parser, Title $title, &$magicWordId, &$ret, PPFrame $frame, array $args ) { $expArgs = array(); foreach( $args as $arg ) { $expArgs[] = trim( $frame->expand( $arg ) ); } $expArgs[] = '1=' . $title->getPrefixedText(); return self::variableValueSwitch( $parser, $magicWordId, $ret, $expArgs ); }
/** * Base function for operations with multiple arrays given thru n parameters * $operationFunc expects a function name prefix (suffix 'multi_') with two parameters * $array1 and $array2 which will perform an action between $array1 and $array2 which * will result into a new $array1. There can be 1 to n $hash2 in the whole process. * * Note: This function is similar to that of Extension:HashTables. * * @since 2.0 * * @param $frame PPFrame * @param $args array * @param $operationFunc string name of the function calling this. There must be a counterpart * function with prefix 'multi_' which should have two parameters. Both parameters * will receive an array, the function must return the result array of the processing. * @param $runFuncOnSingleArray boolean whether the $operationFunc function should be run in case * only one array id is given. If not, the original array will end up in the new array. */ protected function multiArrayOperation(PPFrame $frame, array $args, $operationFunc, $runFuncOnSingleArray = true) { $lastArray = null; $operationRan = false; $finalArrayId = trim($frame->expand($args[0])); $operationFunc = 'multi_' . preg_replace('/^pfObj_/', '', $operationFunc); // For all arrays given in parameters 2 to n (ignore 1 because this is the name of the new array) for ($i = 1; $i < count($args); $i++) { // just make sure we don't fall into gaps of given arguments: if (!array_key_exists($i, $args)) { continue; } $argArrayId = trim($frame->expand($args[$i])); // ignore all tables which do not exist if ($this->arrayExists($argArrayId)) { $argArray = $this->getArray($argArrayId); if ($lastArray === null) { // first valid array, process together with second... $lastArray = $argArray; } else { // second or later hash table, process with previous: $lastArray = $this->{$operationFunc}($lastArray, $argArray); // perform action between last and current array $operationRan = true; } } } // in case no array was given at all: if ($lastArray === null) { $lastArray = array(); } global $egArraysCompatibilityMode; if (!$operationRan && $egArraysCompatibilityMode && $operationFunc !== 'multi_arraymerge') { /* * COMPATIBILITY-MODE: * Before version 2.0 we didn't create a new array in case only one array was given. * The only exception was 'arraymerge' which did duplicate the array. */ return ''; } // if the operation didn't run because there was only one or no array: if (!$operationRan && $runFuncOnSingleArray) { $lastArray = $this->{$operationFunc}($lastArray); } // re-organize all keys since some 'multi_' functions will preserve keys! $lastArray = array_merge($lastArray); $this->setArray($finalArrayId, $lastArray); }
/** * Generic function handling '#forargs' and '#fornumargs' as one */ protected static function perform_forargs(Parser &$parser, PPFrame $frame, array $funcArgs, array $templateArgs, $prefix = '') { // if not called within template instance: if (!$frame->isTemplate()) { return ''; } // name of the variable to store the argument name: $keyVar = array_shift($funcArgs); $keyVar = $keyVar !== null ? trim($frame->expand($keyVar)) : ''; // name of the variable to store the argument value: $valVar = array_shift($funcArgs); $valVar = $valVar !== null ? trim($frame->expand($valVar)) : ''; // unexpanded code: $rawCode = array_shift($funcArgs); $rawCode = $rawCode !== null ? $rawCode : ''; $output = ''; // if prefix contains numbers only or isn't set, get all arguments, otherwise just non-numeric $tArgs = preg_match('/^([1-9][0-9]*)?$/', $prefix) > 0 ? $frame->getArguments() : $frame->getNamedArguments(); foreach ($templateArgs as $argName => $argVal) { // if no filter or prefix in argument name: if ($prefix !== '' && strpos($argName, $prefix) !== 0) { continue; } if ($keyVar !== $valVar) { // variable with the argument name without prefix as value: self::setVariable($parser, $keyVar, substr($argName, strlen($prefix))); } // variable with the arguments value: self::setVariable($parser, $valVar, $argVal); // expand current run: $output .= trim($frame->expand($rawCode)); } return $output; }
function drawDiagram(Parser $parser, PPFrame $frame) { global $wgTitle; $sumEditing = 0; $pagesList = CDParameters::getInstance()->getPagesList(); $pageWithChanges = array(); foreach ($pagesList as $thisPageTitle) { $names = getPageEditorsFromDb($thisPageTitle); $changesForUsersForPage = getCountsOfEditing($names); $thisPageTitleKey = $thisPageTitle->getText(); if ($thisPageTitle->getNsText() != "") { $thisPageTitleKey = $thisPageTitle->getNsText() . ":" . $thisPageTitleKey; // we can't use Title object this is a key with an array so we generate the Ns:Name key } $pageWithChanges[$thisPageTitleKey] = $changesForUsersForPage; $sumEditing += evaluateCountOfAllEdits($changesForUsersForPage); } $text = drawPreamble(); foreach ($pageWithChanges as $thisPageTitleKey => $changesForUsersForPage) { $drawer = CDDrawerFactory::getDrawer($changesForUsersForPage, $sumEditing, $thisPageTitleKey); $text .= $drawer->draw(); } $text .= "}</graphviz>"; // $text = getPie($changesForUsers, $sumEditing, $thisPageTitle); $parser->disableCache(); $parser->setTitle(Title::newFromText("Main_page")); $frame->getTitle(Title::newFromText("Main_page")); $text = $parser->recursiveTagParse($text, $frame); //this stuff just render my page return $text; }
/** * Return the text of a template, after recursively * replacing any variables or templates within the template. * * @param array $piece The parts of the template * $piece['title']: the title, i.e. the part before the | * $piece['parts']: the parameter array * $piece['lineStart']: whether the brace was at the start of a line * @param PPFrame $frame The current frame, contains template arguments * @throws MWException * @return string The text of the template * @private */ function braceSubstitution($piece, $frame) { wfProfileIn(__METHOD__); wfProfileIn(__METHOD__ . '-setup'); # Flags $found = false; # $text has been filled $nowiki = false; # wiki markup in $text should be escaped $isHTML = false; # $text is HTML, armour it against wikitext transformation $forceRawInterwiki = false; # Force interwiki transclusion to be done in raw mode not rendered $isChildObj = false; # $text is a DOM node needing expansion in a child frame $isLocalObj = false; # $text is a DOM node needing expansion in the current frame # Title object, where $text came from $title = false; # $part1 is the bit before the first |, and must contain only title characters. # Various prefixes will be stripped from it later. $titleWithSpaces = $frame->expand($piece['title']); $part1 = trim($titleWithSpaces); $titleText = false; # Original title text preserved for various purposes $originalTitle = $part1; # $args is a list of argument nodes, starting from index 0, not including $part1 # @todo FIXME: If piece['parts'] is null then the call to getLength() below won't work b/c this $args isn't an object $args = null == $piece['parts'] ? array() : $piece['parts']; wfProfileOut(__METHOD__ . '-setup'); $titleProfileIn = null; // profile templates # SUBST wfProfileIn(__METHOD__ . '-modifiers'); if (!$found) { $substMatch = $this->mSubstWords->matchStartAndRemove($part1); # Possibilities for substMatch: "subst", "safesubst" or FALSE # Decide whether to expand template or keep wikitext as-is. if ($this->ot['wiki']) { if ($substMatch === false) { $literal = true; # literal when in PST with no prefix } else { $literal = false; # expand when in PST with subst: or safesubst: } } else { if ($substMatch == 'subst') { $literal = true; # literal when not in PST with plain subst: } else { $literal = false; # expand when not in PST with safesubst: or no prefix } } if ($literal) { $text = $frame->virtualBracketedImplode('{{', '|', '}}', $titleWithSpaces, $args); $isLocalObj = true; $found = true; } } # Variables if (!$found && $args->getLength() == 0) { $id = $this->mVariables->matchStartToEnd($part1); if ($id !== false) { $text = $this->getVariableValue($id, $frame); if (MagicWord::getCacheTTL($id) > -1) { $this->mOutput->updateCacheExpiry(MagicWord::getCacheTTL($id)); } $found = true; } } # MSG, MSGNW and RAW if (!$found) { # Check for MSGNW: $mwMsgnw = MagicWord::get('msgnw'); if ($mwMsgnw->matchStartAndRemove($part1)) { $nowiki = true; } else { # Remove obsolete MSG: $mwMsg = MagicWord::get('msg'); $mwMsg->matchStartAndRemove($part1); } # Check for RAW: $mwRaw = MagicWord::get('raw'); if ($mwRaw->matchStartAndRemove($part1)) { $forceRawInterwiki = true; } } wfProfileOut(__METHOD__ . '-modifiers'); # Parser functions if (!$found) { wfProfileIn(__METHOD__ . '-pfunc'); $colonPos = strpos($part1, ':'); if ($colonPos !== false) { $func = substr($part1, 0, $colonPos); $funcArgs = array(trim(substr($part1, $colonPos + 1))); for ($i = 0; $i < $args->getLength(); $i++) { $funcArgs[] = $args->item($i); } try { $result = $this->callParserFunction($frame, $func, $funcArgs); } catch (Exception $ex) { wfProfileOut(__METHOD__ . '-pfunc'); wfProfileOut(__METHOD__); throw $ex; } # The interface for parser functions allows for extracting # flags into the local scope. Extract any forwarded flags # here. extract($result); } wfProfileOut(__METHOD__ . '-pfunc'); } # Finish mangling title and then check for loops. # Set $title to a Title object and $titleText to the PDBK if (!$found) { $ns = NS_TEMPLATE; # Split the title into page and subpage $subpage = ''; $relative = $this->maybeDoSubpageLink($part1, $subpage); if ($part1 !== $relative) { $part1 = $relative; $ns = $this->mTitle->getNamespace(); } $title = Title::newFromText($part1, $ns); if ($title) { $titleText = $title->getPrefixedText(); # Check for language variants if the template is not found if ($this->getConverterLanguage()->hasVariants() && $title->getArticleID() == 0) { $this->getConverterLanguage()->findVariantLink($part1, $title, true); } # Do recursion depth check $limit = $this->mOptions->getMaxTemplateDepth(); if ($frame->depth >= $limit) { $found = true; $text = '<span class="error">' . wfMessage('parser-template-recursion-depth-warning')->numParams($limit)->inContentLanguage()->text() . '</span>'; } } } # Load from database if (!$found && $title) { if (!Profiler::instance()->isPersistent()) { # Too many unique items can kill profiling DBs/collectors $titleProfileIn = __METHOD__ . "-title-" . $title->getPrefixedDBkey(); wfProfileIn($titleProfileIn); // template in } wfProfileIn(__METHOD__ . '-loadtpl'); if (!$title->isExternal()) { if ($title->isSpecialPage() && $this->mOptions->getAllowSpecialInclusion() && $this->ot['html']) { // Pass the template arguments as URL parameters. // "uselang" will have no effect since the Language object // is forced to the one defined in ParserOptions. $pageArgs = array(); for ($i = 0; $i < $args->getLength(); $i++) { $bits = $args->item($i)->splitArg(); if (strval($bits['index']) === '') { $name = trim($frame->expand($bits['name'], PPFrame::STRIP_COMMENTS)); $value = trim($frame->expand($bits['value'])); $pageArgs[$name] = $value; } } // Create a new context to execute the special page $context = new RequestContext(); $context->setTitle($title); $context->setRequest(new FauxRequest($pageArgs)); $context->setUser($this->getUser()); $context->setLanguage($this->mOptions->getUserLangObj()); $ret = SpecialPageFactory::capturePath($title, $context); if ($ret) { $text = $context->getOutput()->getHTML(); $this->mOutput->addOutputPageMetadata($context->getOutput()); $found = true; $isHTML = true; $this->disableCache(); } } elseif (MWNamespace::isNonincludable($title->getNamespace())) { $found = false; # access denied wfDebug(__METHOD__ . ": template inclusion denied for " . $title->getPrefixedDBkey() . "\n"); } else { list($text, $title) = $this->getTemplateDom($title); if ($text !== false) { $found = true; $isChildObj = true; } } # If the title is valid but undisplayable, make a link to it if (!$found && ($this->ot['html'] || $this->ot['pre'])) { $text = "[[:{$titleText}]]"; $found = true; } } elseif ($title->isTrans()) { # Interwiki transclusion if ($this->ot['html'] && !$forceRawInterwiki) { $text = $this->interwikiTransclude($title, 'render'); $isHTML = true; } else { $text = $this->interwikiTransclude($title, 'raw'); # Preprocess it like a template $text = $this->preprocessToDom($text, self::PTD_FOR_INCLUSION); $isChildObj = true; } $found = true; } # Do infinite loop check # This has to be done after redirect resolution to avoid infinite loops via redirects if (!$frame->loopCheck($title)) { $found = true; $text = '<span class="error">' . wfMessage('parser-template-loop-warning', $titleText)->inContentLanguage()->text() . '</span>'; wfDebug(__METHOD__ . ": template loop broken at '{$titleText}'\n"); } wfProfileOut(__METHOD__ . '-loadtpl'); } # If we haven't found text to substitute by now, we're done # Recover the source wikitext and return it if (!$found) { $text = $frame->virtualBracketedImplode('{{', '|', '}}', $titleWithSpaces, $args); if ($titleProfileIn) { wfProfileOut($titleProfileIn); // template out } wfProfileOut(__METHOD__); return array('object' => $text); } # Expand DOM-style return values in a child frame if ($isChildObj) { # Clean up argument array $newFrame = $frame->newChild($args, $title); if ($nowiki) { $text = $newFrame->expand($text, PPFrame::RECOVER_ORIG); } elseif ($titleText !== false && $newFrame->isEmpty()) { # Expansion is eligible for the empty-frame cache if (isset($this->mTplExpandCache[$titleText])) { $text = $this->mTplExpandCache[$titleText]; } else { $text = $newFrame->expand($text); $this->mTplExpandCache[$titleText] = $text; } } else { # Uncached expansion $text = $newFrame->expand($text); } } if ($isLocalObj && $nowiki) { $text = $frame->expand($text, PPFrame::RECOVER_ORIG); $isLocalObj = false; } if ($titleProfileIn) { wfProfileOut($titleProfileIn); // template out } # Replace raw HTML by a placeholder if ($isHTML) { $text = $this->insertStripItem($text); } elseif ($nowiki && ($this->ot['html'] || $this->ot['pre'])) { # Escape nowiki-style return values $text = wfEscapeWikiText($text); } elseif (is_string($text) && !$piece['lineStart'] && preg_match('/^(?:{\\||:|;|#|\\*)/', $text)) { # Bug 529: if the template begins with a table or block-level # element, it should be treated as beginning a new line. # This behavior is somewhat controversial. $text = "\n" . $text; } if (is_string($text) && !$this->incrementIncludeSize('post-expand', strlen($text))) { # Error, oversize inclusion if ($titleText !== false) { # Make a working, properly escaped link if possible (bug 23588) $text = "[[:{$titleText}]]"; } else { # This will probably not be a working link, but at least it may # provide some hint of where the problem is preg_replace('/^:/', '', $originalTitle); $text = "[[:{$originalTitle}]]"; } $text .= $this->insertStripItem('<!-- WARNING: template omitted, post-expand include size too large -->'); $this->limitationWarn('post-expand-template-inclusion'); } if ($isLocalObj) { $ret = array('object' => $text); } else { $ret = array('text' => $text); } wfProfileOut(__METHOD__); return $ret; }
/** * Parser function to extension tag adaptor * @param Parser $parser * @param PPFrame $frame * @param array $args * @return string */ public static function tagObj($parser, $frame, $args) { if (!count($args)) { return ''; } $tagName = strtolower(trim($frame->expand(array_shift($args)))); if (count($args)) { $inner = $frame->expand(array_shift($args)); } else { $inner = null; } $stripList = $parser->getStripList(); if (!in_array($tagName, $stripList)) { return '<span class="error">' . wfMessage('unknown_extension_tag', $tagName)->inContentLanguage()->text() . '</span>'; } $attributes = array(); foreach ($args as $arg) { $bits = $arg->splitArg(); if (strval($bits['index']) === '') { $name = trim($frame->expand($bits['name'], PPFrame::STRIP_COMMENTS)); $value = trim($frame->expand($bits['value'])); if (preg_match('/^(?:["\'](.+)["\']|""|\'\')$/s', $value, $m)) { $value = isset($m[1]) ? $m[1] : ''; } $attributes[$name] = $value; } } $params = array('name' => $tagName, 'inner' => $inner, 'attributes' => $attributes, 'close' => "</{$tagName}>"); return $parser->extensionSubstitution($params, $frame); }
/** * Function ensures that arrays are used for merging * * @param PPFrame $frame * * @return array */ protected function getFrameParams(PPFrame $frame) { //we use both getNamedArguments and getArguments to ensure we acquire variables no matter what frame is used $namedArgs = $frame->getNamedArguments(); $namedArgs = isset($namedArgs) ? is_array($namedArgs) ? $namedArgs : [$namedArgs] : []; $args = $frame->getArguments(); $args = isset($args) ? is_array($args) ? $args : [$args] : []; return array_merge($namedArgs, $args); }
/** * Returns either the text result of the function, or an array with the * text in element 0, and a number of flags in the other elements. * * @param Parser $parser * @param PPFrame $frame * @param array $args * @return string Html output */ public static function onParserFunctionHook($parser, $frame, $args) { $arguments = array(); // transform objects to strings foreach ($args as $arg) { $arguments[] = trim($frame->expand($arg)); } // if no argument given, we receive an array with one empty string, remove it if (count($arguments) == 1 && reset($arguments) == '') { array_shift($arguments); } // instanciate $child_class = get_called_class(); $widget = new $child_class($parser, $frame); // execute return $widget->execute($arguments); }
/** * Returns a value from the last performed regex match * * @index $parser Parser instance of running Parser * @param $index Integer index of the last match which should be returnd or a string containing $n as indexes to be replaced * @param $defaultVal Integer default value which will be returned when the result with the given index doesn't exist or is a void string */ public static function pfObj_regex_var(Parser &$parser, PPFrame $frame, array $args) { $index = isset($args[0]) ? trim($frame->expand($args[0])) : 0; $defaultVal = isset($args[1]) ? trim($frame->expand($args[1])) : ''; // get matches from last #regex $lastMatches = self::getLastMatches($frame); if ($lastMatches === null) { // last regex was invalid or none executed yet return $defaultVal; } // if requested index is numerical: if (preg_match('/^\\d+$/', $index)) { // if requested index is in matches and isn't '': if (array_key_exists($index, $lastMatches) && $lastMatches[$index] !== '') { return $lastMatches[$index]; } else { // no match! Return just the default value: return $defaultVal; } } else { // complex string is given, something like "$1, $2 and $3": // limit check, only in complex mode: if (self::limitExceeded($parser)) { return self::msgLimitExceeded(); } self::increaseRegexCount($parser); // do the actual transformation: return self::regexVarReplace($index, $lastMatches, false); } }
/** * Return the text to be used for a given extension tag. * This is the ghost of strip(). * * @param array $params Associative array of parameters: * name PPNode for the tag name * attr PPNode for unparsed text where tag attributes are thought to be * attributes Optional associative array of parsed attributes * inner Contents of extension element * noClose Original text did not have a close tag * @param PPFrame $frame */ function extensionSubstitution($params, $frame) { global $wgRawHtml, $wgContLang; $name = $frame->expand($params['name']); $attrText = !isset($params['attr']) ? null : $frame->expand($params['attr']); $content = !isset($params['inner']) ? null : $frame->expand($params['inner']); $marker = "{$this->mUniqPrefix}-{$name}-" . sprintf('%08X', $this->mMarkerIndex++) . self::MARKER_SUFFIX; if ($this->ot['html']) { $name = strtolower($name); $attributes = Sanitizer::decodeTagAttributes($attrText); if (isset($params['attributes'])) { $attributes = $attributes + $params['attributes']; } switch ($name) { case 'html': if ($wgRawHtml) { $output = $content; break; } else { throw new MWException('<html> extension tag encountered unexpectedly'); } case 'nowiki': $content = strtr($content, array('-{' => '-{', '}-' => '}-')); $output = Xml::escapeTagsOnly($content); break; case 'math': $output = $wgContLang->armourMath(MathRenderer::renderMath($content, $attributes)); break; case 'gallery': $output = $this->renderImageGallery($content, $attributes); break; default: if (isset($this->mTagHooks[$name])) { # Workaround for PHP bug 35229 and similar if (!is_callable($this->mTagHooks[$name])) { throw new MWException("Tag hook for {$name} is not callable\n"); } $output = call_user_func_array($this->mTagHooks[$name], array($content, $attributes, $this)); } else { $output = '<span class="error">Invalid tag extension name: ' . htmlspecialchars($name) . '</span>'; } } } else { if (is_null($attrText)) { $attrText = ''; } if (isset($params['attributes'])) { foreach ($params['attributes'] as $attrName => $attrValue) { $attrText .= ' ' . htmlspecialchars($attrName) . '="' . htmlspecialchars($attrValue) . '"'; } } if ($content === null) { $output = "<{$name}{$attrText}/>"; } else { $close = is_null($params['close']) ? '' : $frame->expand($params['close']); $output = "<{$name}{$attrText}>{$content}{$close}"; } } if ($name === 'html' || $name === 'nowiki') { $this->mStripState->nowiki->setPair($marker, $output); } else { $this->mStripState->general->setPair($marker, $output); } return $marker; }
/** * Return the text to be used for a given extension tag. * This is the ghost of strip(). * * @param array $params Associative array of parameters: * name PPNode for the tag name * attr PPNode for unparsed text where tag attributes are thought to be * attributes Optional associative array of parsed attributes * inner Contents of extension element * noClose Original text did not have a close tag * @param PPFrame $frame * * @throws MWException * @return string */ public function extensionSubstitution($params, $frame) { $name = $frame->expand($params['name']); $attrText = !isset($params['attr']) ? null : $frame->expand($params['attr']); $content = !isset($params['inner']) ? null : $frame->expand($params['inner']); $marker = self::MARKER_PREFIX . "-{$name}-" . sprintf('%08X', $this->mMarkerIndex++) . self::MARKER_SUFFIX; $isFunctionTag = isset($this->mFunctionTagHooks[strtolower($name)]) && ($this->ot['html'] || $this->ot['pre']); if ($isFunctionTag) { $markerType = 'none'; } else { $markerType = 'general'; } if ($this->ot['html'] || $isFunctionTag) { $name = strtolower($name); $attributes = Sanitizer::decodeTagAttributes($attrText); if (isset($params['attributes'])) { $attributes = $attributes + $params['attributes']; } if (isset($this->mTagHooks[$name])) { # Workaround for PHP bug 35229 and similar if (!is_callable($this->mTagHooks[$name])) { throw new MWException("Tag hook for {$name} is not callable\n"); } $output = call_user_func_array($this->mTagHooks[$name], array($content, $attributes, $this, $frame)); } elseif (isset($this->mFunctionTagHooks[$name])) { list($callback, ) = $this->mFunctionTagHooks[$name]; if (!is_callable($callback)) { throw new MWException("Tag hook for {$name} is not callable\n"); } $output = call_user_func_array($callback, array(&$this, $frame, $content, $attributes)); } else { $output = '<span class="error">Invalid tag extension name: ' . htmlspecialchars($name) . '</span>'; } if (is_array($output)) { # Extract flags to local scope (to override $markerType) $flags = $output; $output = $flags[0]; unset($flags[0]); extract($flags); } } else { if (is_null($attrText)) { $attrText = ''; } if (isset($params['attributes'])) { foreach ($params['attributes'] as $attrName => $attrValue) { $attrText .= ' ' . htmlspecialchars($attrName) . '="' . htmlspecialchars($attrValue) . '"'; } } if ($content === null) { $output = "<{$name}{$attrText}/>"; } else { $close = is_null($params['close']) ? '' : $frame->expand($params['close']); $output = "<{$name}{$attrText}>{$content}{$close}"; } } if ($markerType === 'none') { return $output; } elseif ($markerType === 'nowiki') { $this->mStripState->addNoWiki($marker, $output); } elseif ($markerType === 'general') { $this->mStripState->addGeneral($marker, $output); } else { throw new MWException(__METHOD__ . ': invalid marker type'); } return $marker; }
/** * Handler for rendering the function hook registered by Parser::setFunctionHook() together * with object style arguments (SFH_OBJECT_ARGS flag). * * @since 0.4.13 * * @param Parser &$parser * @param PPFrame $frame * @param type $args * @return array */ public function renderFunctionObj(Parser &$parser, PPFrame $frame, $args) { $this->frame = $frame; // create non-object args for old style 'renderFunction()' $oldStyleArgs = array(&$parser); foreach ($args as $arg) { $oldStyleArgs[] = trim($frame->expand($arg)); } /* * since we can't validate un-expandet arguments, we just go on with old-style function * handling from here. Only advantage is that we have $this->frame set properly. */ return call_user_func_array(array($this, 'renderFunction'), $oldStyleArgs); }
/** * Parser function to extension tag adaptor * @param Parser $parser * @param PPFrame $frame * @param PPNode[] $args * @return string */ public static function tagObj($parser, $frame, $args) { if (!count($args)) { return ''; } $tagName = strtolower(trim($frame->expand(array_shift($args)))); if (count($args)) { $inner = $frame->expand(array_shift($args)); } else { $inner = null; } $attributes = []; foreach ($args as $arg) { $bits = $arg->splitArg(); if (strval($bits['index']) === '') { $name = trim($frame->expand($bits['name'], PPFrame::STRIP_COMMENTS)); $value = trim($frame->expand($bits['value'])); if (preg_match('/^(?:["\'](.+)["\']|""|\'\')$/s', $value, $m)) { $value = isset($m[1]) ? $m[1] : ''; } $attributes[$name] = $value; } } $stripList = $parser->getStripList(); if (!in_array($tagName, $stripList)) { // we can't handle this tag (at least not now), so just re-emit it as an ordinary tag $attrText = ''; foreach ($attributes as $name => $value) { $attrText .= ' ' . htmlspecialchars($name) . '="' . htmlspecialchars($value) . '"'; } if ($inner === null) { return "<{$tagName}{$attrText}/>"; } return "<{$tagName}{$attrText}>{$inner}</{$tagName}>"; } $params = ['name' => $tagName, 'inner' => $inner, 'attributes' => $attributes, 'close' => "</{$tagName}>"]; return $parser->extensionSubstitution($params, $frame); }
/** * Base function for operations with multiple hashes given thru n parameters * $operationFunc expects a function name prefix (suffix 'multi_') with two parameters * $hash1 and $hash2 which will perform an action between $hash1 and hash2 which will * result into a new $hash1. There can be 1 to n $hash2 in the whole process. * * @param $frame PPFrame * @param $args array * @param $operationFunc string name of the function calling this. There must be a counterpart * function with prefix 'multi_' which should have two parameters. Both parameters * will receive a hash (array), the function must return the result hash of the * processing. * @param $runFuncOnSingleHash boolean whether the $operationFunc function should be run in case * only one hash table id is given. If not, the original hash will end up in the new hash. */ protected function multiHashOperation(PPFrame $frame, array $args, $operationFunc, $runFuncOnSingleHash = true) { $lastHash = null; $operationRan = false; $finalHashId = trim($frame->expand($args[0])); $operationFunc = 'multi_' . preg_replace('/^pfObj_/', '', $operationFunc); // For all hashes given in parameters 2 to n (ignore 1 because this is the name of the new hash) for ($i = 1; $i < count($args); $i++) { // just make sure we don't fall into gaps of given arguments: if (!array_key_exists($i, $args)) { continue; } $argHashId = trim($frame->expand($args[$i])); // ignore all tables which do not exist if ($this->hashExists($argHashId)) { $argHash = $this->getHash($argHashId); if ($lastHash === null) { // first valid hash table, process together with second... $lastHash = $argHash; } else { // second or later hash table, process with previous: $lastHash = $this->{$operationFunc}($lastHash, $argHash); // perform action between last and current hash $operationRan = true; } } } // in case no hash was given at all: if ($lastHash === null) { $lastHash = array(); } // if the operation didn't run because there was only one or no array: if (!$operationRan && $runFuncOnSingleHash) { $lastHash = $this->{$operationFunc}($lastHash); } $this->setHash($finalHashId, $lastHash); }