/** * Returns a <select multiple> element with a list of change tags that can be * applied by users. * * @param array $selectedTags The tags that should be preselected in the * list. Any tags in this list, but not in the list returned by * ChangeTags::listExplicitlyDefinedTags, will be appended to the <select> * element. * @param string $label The text of a <label> to precede the <select> * @return array HTML <label> element at index 0, HTML <select> element at * index 1 */ protected function getTagSelect($selectedTags, $label) { $result = []; $result[0] = Xml::label($label, 'mw-edittags-tag-list'); $select = new XmlSelect('wpTagList[]', 'mw-edittags-tag-list', $selectedTags); $select->setAttribute('multiple', 'multiple'); $select->setAttribute('size', '8'); $tags = ChangeTags::listExplicitlyDefinedTags(); $tags = array_unique(array_merge($tags, $selectedTags)); // Values of $tags are also used as <option> labels $select->addOptions(array_combine($tags, $tags)); $result[1] = $select->getHTML(); return $result; }
public function getAllowedParams() { return array('title' => array(ApiBase::PARAM_TYPE => 'string'), 'pageid' => array(ApiBase::PARAM_TYPE => 'integer'), 'section' => null, 'sectiontitle' => array(ApiBase::PARAM_TYPE => 'string'), 'text' => array(ApiBase::PARAM_TYPE => 'text'), 'summary' => null, 'tags' => array(ApiBase::PARAM_TYPE => ChangeTags::listExplicitlyDefinedTags(), ApiBase::PARAM_ISMULTI => true), 'minor' => false, 'notminor' => false, 'bot' => false, 'basetimestamp' => array(ApiBase::PARAM_TYPE => 'timestamp'), 'starttimestamp' => array(ApiBase::PARAM_TYPE => 'timestamp'), 'recreate' => false, 'createonly' => false, 'nocreate' => false, 'watch' => array(ApiBase::PARAM_DFLT => false, ApiBase::PARAM_DEPRECATED => true), 'unwatch' => array(ApiBase::PARAM_DFLT => false, ApiBase::PARAM_DEPRECATED => true), 'watchlist' => array(ApiBase::PARAM_DFLT => 'preferences', ApiBase::PARAM_TYPE => array('watch', 'unwatch', 'preferences', 'nochange')), 'md5' => null, 'prependtext' => array(ApiBase::PARAM_TYPE => 'text'), 'appendtext' => array(ApiBase::PARAM_TYPE => 'text'), 'undo' => array(ApiBase::PARAM_TYPE => 'integer'), 'undoafter' => array(ApiBase::PARAM_TYPE => 'integer'), 'redirect' => array(ApiBase::PARAM_TYPE => 'boolean', ApiBase::PARAM_DFLT => false), 'contentformat' => array(ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats()), 'contentmodel' => array(ApiBase::PARAM_TYPE => ContentHandler::getContentModels()), 'token' => array(ApiBase::PARAM_HELP_MSG_APPEND => array('apihelp-edit-param-token'))); }
public function getAllowedParams() { return array('title' => null, 'pageid' => array(ApiBase::PARAM_TYPE => 'integer'), 'tags' => array(ApiBase::PARAM_TYPE => ChangeTags::listExplicitlyDefinedTags(), ApiBase::PARAM_ISMULTI => true), 'user' => array(ApiBase::PARAM_TYPE => 'user', ApiBase::PARAM_REQUIRED => true), 'summary' => '', 'markbot' => false, 'watchlist' => array(ApiBase::PARAM_DFLT => 'preferences', ApiBase::PARAM_TYPE => array('watch', 'unwatch', 'preferences', 'nochange')), 'token' => array(ApiBase::PARAM_HELP_MSG_APPEND => array('api-help-param-token-webui'))); }
function showTagList() { $out = $this->getOutput(); $out->setPageTitle($this->msg('tags-title')); $out->wrapWikiMsg("<div class='mw-tags-intro'>\n\$1\n</div>", 'tags-intro'); $user = $this->getUser(); $userCanManage = $user->isAllowed('managechangetags'); $userCanDelete = $user->isAllowed('deletechangetags'); $userCanEditInterface = $user->isAllowed('editinterface'); // Show form to create a tag if ($userCanManage) { $fields = ['Tag' => ['type' => 'text', 'label' => $this->msg('tags-create-tag-name')->plain(), 'required' => true], 'Reason' => ['type' => 'text', 'label' => $this->msg('tags-create-reason')->plain(), 'size' => 50], 'IgnoreWarnings' => ['type' => 'hidden']]; $form = new HTMLForm($fields, $this->getContext()); $form->setAction($this->getPageTitle('create')->getLocalURL()); $form->setWrapperLegendMsg('tags-create-heading'); $form->setHeaderText($this->msg('tags-create-explanation')->parseAsBlock()); $form->setSubmitCallback([$this, 'processCreateTagForm']); $form->setSubmitTextMsg('tags-create-submit'); $form->show(); // If processCreateTagForm generated a redirect, there's no point // continuing with this, as the user is just going to end up getting sent // somewhere else. Additionally, if we keep going here, we end up // populating the memcache of tag data (see ChangeTags::listDefinedTags) // with out-of-date data from the slave, because the slave hasn't caught // up to the fact that a new tag has been created as part of an implicit, // as yet uncommitted transaction on master. if ($out->getRedirect() !== '') { return; } } // Used to get hitcounts for #doTagRow() $tagStats = ChangeTags::tagUsageStatistics(); // Used in #doTagRow() $this->explicitlyDefinedTags = array_fill_keys(ChangeTags::listExplicitlyDefinedTags(), true); $this->extensionDefinedTags = array_fill_keys(ChangeTags::listExtensionDefinedTags(), true); // List all defined tags, even if they were never applied $definedTags = array_keys(array_merge($this->explicitlyDefinedTags, $this->extensionDefinedTags)); // Show header only if there exists atleast one tag if (!$tagStats && !$definedTags) { return; } // Write the headers $html = Xml::tags('tr', null, Xml::tags('th', null, $this->msg('tags-tag')->parse()) . Xml::tags('th', null, $this->msg('tags-display-header')->parse()) . Xml::tags('th', null, $this->msg('tags-description-header')->parse()) . Xml::tags('th', null, $this->msg('tags-source-header')->parse()) . Xml::tags('th', null, $this->msg('tags-active-header')->parse()) . Xml::tags('th', null, $this->msg('tags-hitcount-header')->parse()) . ($userCanManage ? Xml::tags('th', ['class' => 'unsortable'], $this->msg('tags-actions-header')->parse()) : '')); // Used in #doTagRow() $this->extensionActivatedTags = array_fill_keys(ChangeTags::listExtensionActivatedTags(), true); // Insert tags that have been applied at least once foreach ($tagStats as $tag => $hitcount) { $html .= $this->doTagRow($tag, $hitcount, $userCanManage, $userCanDelete, $userCanEditInterface); } // Insert tags defined somewhere but never applied foreach ($definedTags as $tag) { if (!isset($tagStats[$tag])) { $html .= $this->doTagRow($tag, 0, $userCanManage, $userCanDelete, $userCanEditInterface); } } $out->addHTML(Xml::tags('table', ['class' => 'mw-datatable sortable mw-tags-table'], $html)); }
protected function getAvailableTags() { return ChangeTags::listExplicitlyDefinedTags(); }
public function execute() { $params = $this->extractRequestParams(); $prop = array_flip($params['prop']); $fld_displayname = isset($prop['displayname']); $fld_description = isset($prop['description']); $fld_hitcount = isset($prop['hitcount']); $fld_defined = isset($prop['defined']); $fld_source = isset($prop['source']); $fld_active = isset($prop['active']); $limit = $params['limit']; $result = $this->getResult(); $extensionDefinedTags = array_fill_keys(ChangeTags::listExtensionDefinedTags(), 0); $explicitlyDefinedTags = array_fill_keys(ChangeTags::listExplicitlyDefinedTags(), 0); $extensionActivatedTags = array_fill_keys(ChangeTags::listExtensionActivatedTags(), 0); $definedTags = array_merge($extensionDefinedTags, $explicitlyDefinedTags); # Fetch defined tags that aren't past the continuation if ($params['continue'] !== null) { $cont = $params['continue']; $tags = array_filter(array_keys($definedTags), function ($v) use($cont) { return $v >= $cont; }); $tags = array_fill_keys($tags, 0); } else { $tags = $definedTags; } # Merge in all used tags $this->addTables('change_tag'); $this->addFields('ct_tag'); $this->addFields(array('hitcount' => $fld_hitcount ? 'COUNT(*)' : '0')); $this->addOption('LIMIT', $limit + 1); $this->addOption('GROUP BY', 'ct_tag'); $this->addWhereRange('ct_tag', 'newer', $params['continue'], null); $res = $this->select(__METHOD__); foreach ($res as $row) { $tags[$row->ct_tag] = (int) $row->hitcount; } # Now make sure the array is sorted for proper continuation ksort($tags); $count = 0; foreach ($tags as $tagName => $hitcount) { if (++$count > $limit) { $this->setContinueEnumParameter('continue', $tagName); break; } $tag = array(); $tag['name'] = $tagName; if ($fld_displayname) { $tag['displayname'] = ChangeTags::tagDescription($tagName); } if ($fld_description) { $msg = $this->msg("tag-{$tagName}-description"); $tag['description'] = $msg->exists() ? $msg->text() : ''; } if ($fld_hitcount) { $tag['hitcount'] = $hitcount; } $isExtension = isset($extensionDefinedTags[$tagName]); $isExplicit = isset($explicitlyDefinedTags[$tagName]); if ($fld_defined) { $tag['defined'] = $isExtension || $isExplicit; } if ($fld_source) { $tag['source'] = array(); if ($isExtension) { $tag['source'][] = 'extension'; } if ($isExplicit) { $tag['source'][] = 'manual'; } } if ($fld_active) { $tag['active'] = $isExplicit || isset($extensionActivatedTags[$tagName]); } $fit = $result->addValue(array('query', $this->getModuleName()), null, $tag); if (!$fit) { $this->setContinueEnumParameter('continue', $tagName); break; } } $result->addIndexedTagName(array('query', $this->getModuleName()), 'tag'); }
/** * Recursively-called function to actually construct the help * * @param IContextSource $context * @param ApiBase[] $modules * @param array $options * @param array &$haveModules * @return string */ private static function getHelpInternal(IContextSource $context, array $modules, array $options, &$haveModules) { $out = ''; $level = empty($options['headerlevel']) ? 2 : $options['headerlevel']; if (empty($options['tocnumber'])) { $tocnumber = [2 => 0]; } else { $tocnumber =& $options['tocnumber']; } foreach ($modules as $module) { $tocnumber[$level]++; $path = $module->getModulePath(); $module->setContext($context); $help = ['header' => '', 'flags' => '', 'description' => '', 'help-urls' => '', 'parameters' => '', 'examples' => '', 'submodules' => '']; if (empty($options['noheader']) || !empty($options['toc'])) { $anchor = $path; $i = 1; while (isset($haveModules[$anchor])) { $anchor = $path . '|' . ++$i; } if ($module->isMain()) { $headerContent = $context->msg('api-help-main-header')->parse(); $headerAttr = ['class' => 'apihelp-header']; } else { $name = $module->getModuleName(); $headerContent = $module->getParent()->getModuleManager()->getModuleGroup($name) . "={$name}"; if ($module->getModulePrefix() !== '') { $headerContent .= ' ' . $context->msg('parentheses', $module->getModulePrefix())->parse(); } // Module names are always in English and not localized, // so English language and direction must be set explicitly, // otherwise parentheses will get broken in RTL wikis $headerAttr = ['class' => 'apihelp-header apihelp-module-name', 'dir' => 'ltr', 'lang' => 'en']; } $headerAttr['id'] = $anchor; $haveModules[$anchor] = ['toclevel' => count($tocnumber), 'level' => $level, 'anchor' => $anchor, 'line' => $headerContent, 'number' => implode('.', $tocnumber), 'index' => false]; if (empty($options['noheader'])) { $help['header'] .= Html::element('h' . min(6, $level), $headerAttr, $headerContent); } } else { $haveModules[$path] = true; } $links = []; $any = false; for ($m = $module; $m !== null; $m = $m->getParent()) { $name = $m->getModuleName(); if ($name === 'main_int') { $name = 'main'; } if (count($modules) === 1 && $m === $modules[0] && !(!empty($options['submodules']) && $m->getModuleManager())) { $link = Html::element('b', null, $name); } else { $link = SpecialPage::getTitleFor('ApiHelp', $m->getModulePath())->getLocalURL(); $link = Html::element('a', ['href' => $link, 'class' => 'apihelp-linktrail'], $name); $any = true; } array_unshift($links, $link); } if ($any) { $help['header'] .= self::wrap($context->msg('parentheses')->rawParams($context->getLanguage()->pipeList($links)), 'apihelp-linktrail', 'div'); } $flags = $module->getHelpFlags(); $help['flags'] .= Html::openElement('div', ['class' => 'apihelp-block apihelp-flags']); $msg = $context->msg('api-help-flags'); if (!$msg->isDisabled()) { $help['flags'] .= self::wrap($msg->numParams(count($flags)), 'apihelp-block-head', 'div'); } $help['flags'] .= Html::openElement('ul'); foreach ($flags as $flag) { $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg("api-help-flag-{$flag}"), "apihelp-flag-{$flag}")); } $sourceInfo = $module->getModuleSourceInfo(); if ($sourceInfo) { if (isset($sourceInfo['namemsg'])) { $extname = $context->msg($sourceInfo['namemsg'])->text(); } else { $extname = $sourceInfo['name']; } $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg('api-help-source', $extname, $sourceInfo['name']), 'apihelp-source')); $link = SpecialPage::getTitleFor('Version', 'License/' . $sourceInfo['name']); if (isset($sourceInfo['license-name'])) { $msg = $context->msg('api-help-license', $link, $sourceInfo['license-name']); } elseif (SpecialVersion::getExtLicenseFileName(dirname($sourceInfo['path']))) { $msg = $context->msg('api-help-license-noname', $link); } else { $msg = $context->msg('api-help-license-unknown'); } $help['flags'] .= Html::rawElement('li', null, self::wrap($msg, 'apihelp-license')); } else { $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg('api-help-source-unknown'), 'apihelp-source')); $help['flags'] .= Html::rawElement('li', null, self::wrap($context->msg('api-help-license-unknown'), 'apihelp-license')); } $help['flags'] .= Html::closeElement('ul'); $help['flags'] .= Html::closeElement('div'); foreach ($module->getFinalDescription() as $msg) { $msg->setContext($context); $help['description'] .= $msg->parseAsBlock(); } $urls = $module->getHelpUrls(); if ($urls) { $help['help-urls'] .= Html::openElement('div', ['class' => 'apihelp-block apihelp-help-urls']); $msg = $context->msg('api-help-help-urls'); if (!$msg->isDisabled()) { $help['help-urls'] .= self::wrap($msg->numParams(count($urls)), 'apihelp-block-head', 'div'); } if (!is_array($urls)) { $urls = [$urls]; } $help['help-urls'] .= Html::openElement('ul'); foreach ($urls as $url) { $help['help-urls'] .= Html::rawElement('li', null, Html::element('a', ['href' => $url], $url)); } $help['help-urls'] .= Html::closeElement('ul'); $help['help-urls'] .= Html::closeElement('div'); } $params = $module->getFinalParams(ApiBase::GET_VALUES_FOR_HELP); $dynamicParams = $module->dynamicParameterDocumentation(); $groups = []; if ($params || $dynamicParams !== null) { $help['parameters'] .= Html::openElement('div', ['class' => 'apihelp-block apihelp-parameters']); $msg = $context->msg('api-help-parameters'); if (!$msg->isDisabled()) { $help['parameters'] .= self::wrap($msg->numParams(count($params)), 'apihelp-block-head', 'div'); } $help['parameters'] .= Html::openElement('dl'); $descriptions = $module->getFinalParamDescription(); foreach ($params as $name => $settings) { if (!is_array($settings)) { $settings = [ApiBase::PARAM_DFLT => $settings]; } $help['parameters'] .= Html::element('dt', null, $module->encodeParamName($name)); // Add description $description = []; if (isset($descriptions[$name])) { foreach ($descriptions[$name] as $msg) { $msg->setContext($context); $description[] = $msg->parseAsBlock(); } } // Add usage info $info = []; // Required? if (!empty($settings[ApiBase::PARAM_REQUIRED])) { $info[] = $context->msg('api-help-param-required')->parse(); } // Custom info? if (!empty($settings[ApiBase::PARAM_HELP_MSG_INFO])) { foreach ($settings[ApiBase::PARAM_HELP_MSG_INFO] as $i) { $tag = array_shift($i); $info[] = $context->msg("apihelp-{$path}-paraminfo-{$tag}")->numParams(count($i))->params($context->getLanguage()->commaList($i))->params($module->getModulePrefix())->parse(); } } // Type documentation if (!isset($settings[ApiBase::PARAM_TYPE])) { $dflt = isset($settings[ApiBase::PARAM_DFLT]) ? $settings[ApiBase::PARAM_DFLT] : null; if (is_bool($dflt)) { $settings[ApiBase::PARAM_TYPE] = 'boolean'; } elseif (is_string($dflt) || is_null($dflt)) { $settings[ApiBase::PARAM_TYPE] = 'string'; } elseif (is_int($dflt)) { $settings[ApiBase::PARAM_TYPE] = 'integer'; } } if (isset($settings[ApiBase::PARAM_TYPE])) { $type = $settings[ApiBase::PARAM_TYPE]; $multi = !empty($settings[ApiBase::PARAM_ISMULTI]); $hintPipeSeparated = true; $count = ApiBase::LIMIT_SML2 + 1; if (is_array($type)) { $count = count($type); $links = isset($settings[ApiBase::PARAM_VALUE_LINKS]) ? $settings[ApiBase::PARAM_VALUE_LINKS] : []; $type = array_map(function ($v) use($links) { $ret = wfEscapeWikiText($v); if (isset($links[$v])) { $ret = "[[{$links[$v]}|{$ret}]]"; } return $ret; }, $type); $i = array_search('', $type, true); if ($i === false) { $type = $context->getLanguage()->commaList($type); } else { unset($type[$i]); $type = $context->msg('api-help-param-list-can-be-empty')->numParams(count($type))->params($context->getLanguage()->commaList($type))->parse(); } $info[] = $context->msg('api-help-param-list')->params($multi ? 2 : 1)->params($type)->parse(); $hintPipeSeparated = false; } else { switch ($type) { case 'submodule': $groups[] = $name; if (isset($settings[ApiBase::PARAM_SUBMODULE_MAP])) { $map = $settings[ApiBase::PARAM_SUBMODULE_MAP]; ksort($map); $submodules = []; foreach ($map as $v => $m) { $submodules[] = "[[Special:ApiHelp/{$m}|{$v}]]"; } } else { $submodules = $module->getModuleManager()->getNames($name); sort($submodules); $prefix = $module->isMain() ? '' : $module->getModulePath() . '+'; $submodules = array_map(function ($name) use($prefix) { return "[[Special:ApiHelp/{$prefix}{$name}|{$name}]]"; }, $submodules); } $count = count($submodules); $info[] = $context->msg('api-help-param-list')->params($multi ? 2 : 1)->params($context->getLanguage()->commaList($submodules))->parse(); $hintPipeSeparated = false; // No type message necessary, we have a list of values. $type = null; break; case 'namespace': $namespaces = MWNamespace::getValidNamespaces(); $count = count($namespaces); $info[] = $context->msg('api-help-param-list')->params($multi ? 2 : 1)->params($context->getLanguage()->commaList($namespaces))->parse(); $hintPipeSeparated = false; // No type message necessary, we have a list of values. $type = null; break; case 'tags': $tags = ChangeTags::listExplicitlyDefinedTags(); $count = count($tags); $info[] = $context->msg('api-help-param-list')->params($multi ? 2 : 1)->params($context->getLanguage()->commaList($tags))->parse(); $hintPipeSeparated = false; $type = null; break; case 'limit': if (isset($settings[ApiBase::PARAM_MAX2])) { $info[] = $context->msg('api-help-param-limit2')->numParams($settings[ApiBase::PARAM_MAX])->numParams($settings[ApiBase::PARAM_MAX2])->parse(); } else { $info[] = $context->msg('api-help-param-limit')->numParams($settings[ApiBase::PARAM_MAX])->parse(); } break; case 'integer': // Possible messages: // api-help-param-integer-min, // api-help-param-integer-max, // api-help-param-integer-minmax $suffix = ''; $min = $max = 0; if (isset($settings[ApiBase::PARAM_MIN])) { $suffix .= 'min'; $min = $settings[ApiBase::PARAM_MIN]; } if (isset($settings[ApiBase::PARAM_MAX])) { $suffix .= 'max'; $max = $settings[ApiBase::PARAM_MAX]; } if ($suffix !== '') { $info[] = $context->msg("api-help-param-integer-{$suffix}")->params($multi ? 2 : 1)->numParams($min, $max)->parse(); } break; case 'upload': $info[] = $context->msg('api-help-param-upload')->parse(); // No type message necessary, api-help-param-upload should handle it. $type = null; break; case 'string': case 'text': // Displaying a type message here would be useless. $type = null; break; } } // Add type. Messages for grep: api-help-param-type-limit // api-help-param-type-integer api-help-param-type-boolean // api-help-param-type-timestamp api-help-param-type-user // api-help-param-type-password if (is_string($type)) { $msg = $context->msg("api-help-param-type-{$type}"); if (!$msg->isDisabled()) { $info[] = $msg->params($multi ? 2 : 1)->parse(); } } if ($multi) { $extra = []; if ($hintPipeSeparated) { $extra[] = $context->msg('api-help-param-multi-separate')->parse(); } if ($count > ApiBase::LIMIT_SML1) { $extra[] = $context->msg('api-help-param-multi-max')->numParams(ApiBase::LIMIT_SML1, ApiBase::LIMIT_SML2)->parse(); } if ($extra) { $info[] = implode(' ', $extra); } } } // Add default $default = isset($settings[ApiBase::PARAM_DFLT]) ? $settings[ApiBase::PARAM_DFLT] : null; if ($default === '') { $info[] = $context->msg('api-help-param-default-empty')->parse(); } elseif ($default !== null && $default !== false) { $info[] = $context->msg('api-help-param-default')->params(wfEscapeWikiText($default))->parse(); } if (!array_filter($description)) { $description = [self::wrap($context->msg('api-help-param-no-description'), 'apihelp-empty')]; } // Add "deprecated" flag if (!empty($settings[ApiBase::PARAM_DEPRECATED])) { $help['parameters'] .= Html::openElement('dd', ['class' => 'info']); $help['parameters'] .= self::wrap($context->msg('api-help-param-deprecated'), 'apihelp-deprecated', 'strong'); $help['parameters'] .= Html::closeElement('dd'); } if ($description) { $description = implode('', $description); $description = preg_replace('!\\s*</([oud]l)>\\s*<\\1>\\s*!', "\n", $description); $help['parameters'] .= Html::rawElement('dd', ['class' => 'description'], $description); } foreach ($info as $i) { $help['parameters'] .= Html::rawElement('dd', ['class' => 'info'], $i); } } if ($dynamicParams !== null) { $dynamicParams = ApiBase::makeMessage($dynamicParams, $context, [$module->getModulePrefix(), $module->getModuleName(), $module->getModulePath()]); $help['parameters'] .= Html::element('dt', null, '*'); $help['parameters'] .= Html::rawElement('dd', ['class' => 'description'], $dynamicParams->parse()); } $help['parameters'] .= Html::closeElement('dl'); $help['parameters'] .= Html::closeElement('div'); } $examples = $module->getExamplesMessages(); if ($examples) { $help['examples'] .= Html::openElement('div', ['class' => 'apihelp-block apihelp-examples']); $msg = $context->msg('api-help-examples'); if (!$msg->isDisabled()) { $help['examples'] .= self::wrap($msg->numParams(count($examples)), 'apihelp-block-head', 'div'); } $help['examples'] .= Html::openElement('dl'); foreach ($examples as $qs => $msg) { $msg = ApiBase::makeMessage($msg, $context, [$module->getModulePrefix(), $module->getModuleName(), $module->getModulePath()]); $link = wfAppendQuery(wfScript('api'), $qs); $sandbox = SpecialPage::getTitleFor('ApiSandbox')->getLocalURL() . '#' . $qs; $help['examples'] .= Html::rawElement('dt', null, $msg->parse()); $help['examples'] .= Html::rawElement('dd', null, Html::element('a', ['href' => $link], "api.php?{$qs}") . ' ' . Html::rawElement('a', ['href' => $sandbox], $context->msg('api-help-open-in-apisandbox')->parse())); } $help['examples'] .= Html::closeElement('dl'); $help['examples'] .= Html::closeElement('div'); } $subtocnumber = $tocnumber; $subtocnumber[$level + 1] = 0; $suboptions = ['submodules' => $options['recursivesubmodules'], 'headerlevel' => $level + 1, 'tocnumber' => &$subtocnumber, 'noheader' => false] + $options; if ($options['submodules'] && $module->getModuleManager()) { $manager = $module->getModuleManager(); $submodules = []; foreach ($groups as $group) { $names = $manager->getNames($group); sort($names); foreach ($names as $name) { $submodules[] = $manager->getModule($name); } } $help['submodules'] .= self::getHelpInternal($context, $submodules, $suboptions, $haveModules); } $module->modifyHelp($help, $suboptions, $haveModules); Hooks::run('APIHelpModifyOutput', [$module, &$help, $suboptions, &$haveModules]); $out .= implode("\n", $help); } return $out; }
/** * @param ApiBase $module * @return ApiResult */ private function getModuleInfo($module) { $ret = []; $path = $module->getModulePath(); $ret['name'] = $module->getModuleName(); $ret['classname'] = get_class($module); $ret['path'] = $path; if (!$module->isMain()) { $ret['group'] = $module->getParent()->getModuleManager()->getModuleGroup($module->getModuleName()); } $ret['prefix'] = $module->getModulePrefix(); $sourceInfo = $module->getModuleSourceInfo(); if ($sourceInfo) { $ret['source'] = $sourceInfo['name']; if (isset($sourceInfo['namemsg'])) { $ret['sourcename'] = $this->context->msg($sourceInfo['namemsg'])->text(); } else { $ret['sourcename'] = $ret['source']; } $link = SpecialPage::getTitleFor('Version', 'License/' . $sourceInfo['name'])->getFullURL(); if (isset($sourceInfo['license-name'])) { $ret['licensetag'] = $sourceInfo['license-name']; $ret['licenselink'] = (string) $link; } elseif (SpecialVersion::getExtLicenseFileName(dirname($sourceInfo['path']))) { $ret['licenselink'] = (string) $link; } } $this->formatHelpMessages($ret, 'description', $module->getFinalDescription()); foreach ($module->getHelpFlags() as $flag) { $ret[$flag] = true; } $ret['helpurls'] = (array) $module->getHelpUrls(); if (isset($ret['helpurls'][0]) && $ret['helpurls'][0] === false) { $ret['helpurls'] = []; } ApiResult::setIndexedTagName($ret['helpurls'], 'helpurl'); if ($this->helpFormat !== 'none') { $ret['examples'] = []; $examples = $module->getExamplesMessages(); foreach ($examples as $qs => $msg) { $item = ['query' => $qs]; $msg = ApiBase::makeMessage($msg, $this->context, [$module->getModulePrefix(), $module->getModuleName(), $module->getModulePath()]); $this->formatHelpMessages($item, 'description', [$msg]); if (isset($item['description'])) { if (is_array($item['description'])) { $item['description'] = $item['description'][0]; } else { ApiResult::setSubelementsList($item, 'description'); } } $ret['examples'][] = $item; } ApiResult::setIndexedTagName($ret['examples'], 'example'); } $ret['parameters'] = []; $params = $module->getFinalParams(ApiBase::GET_VALUES_FOR_HELP); $paramDesc = $module->getFinalParamDescription(); foreach ($params as $name => $settings) { if (!is_array($settings)) { $settings = [ApiBase::PARAM_DFLT => $settings]; } $item = ['name' => $name]; if (isset($paramDesc[$name])) { $this->formatHelpMessages($item, 'description', $paramDesc[$name], true); } $item['required'] = !empty($settings[ApiBase::PARAM_REQUIRED]); if (!empty($settings[ApiBase::PARAM_DEPRECATED])) { $item['deprecated'] = true; } if ($name === 'token' && $module->needsToken()) { $item['tokentype'] = $module->needsToken(); } if (!isset($settings[ApiBase::PARAM_TYPE])) { $dflt = isset($settings[ApiBase::PARAM_DFLT]) ? $settings[ApiBase::PARAM_DFLT] : null; if (is_bool($dflt)) { $settings[ApiBase::PARAM_TYPE] = 'boolean'; } elseif (is_string($dflt) || is_null($dflt)) { $settings[ApiBase::PARAM_TYPE] = 'string'; } elseif (is_int($dflt)) { $settings[ApiBase::PARAM_TYPE] = 'integer'; } } if (isset($settings[ApiBase::PARAM_DFLT])) { switch ($settings[ApiBase::PARAM_TYPE]) { case 'boolean': $item['default'] = (bool) $settings[ApiBase::PARAM_DFLT]; break; case 'string': case 'text': case 'password': $item['default'] = strval($settings[ApiBase::PARAM_DFLT]); break; case 'integer': case 'limit': $item['default'] = intval($settings[ApiBase::PARAM_DFLT]); break; case 'timestamp': $item['default'] = wfTimestamp(TS_ISO_8601, $settings[ApiBase::PARAM_DFLT]); break; default: $item['default'] = $settings[ApiBase::PARAM_DFLT]; break; } } $item['multi'] = !empty($settings[ApiBase::PARAM_ISMULTI]); if ($item['multi']) { $item['limit'] = $this->getMain()->canApiHighLimits() ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_SML1; $item['lowlimit'] = ApiBase::LIMIT_SML1; $item['highlimit'] = ApiBase::LIMIT_SML2; } if (!empty($settings[ApiBase::PARAM_ALLOW_DUPLICATES])) { $item['allowsduplicates'] = true; } if (isset($settings[ApiBase::PARAM_TYPE])) { if ($settings[ApiBase::PARAM_TYPE] === 'submodule') { if (isset($settings[ApiBase::PARAM_SUBMODULE_MAP])) { ksort($settings[ApiBase::PARAM_SUBMODULE_MAP]); $item['type'] = array_keys($settings[ApiBase::PARAM_SUBMODULE_MAP]); $item['submodules'] = $settings[ApiBase::PARAM_SUBMODULE_MAP]; } else { $item['type'] = $module->getModuleManager()->getNames($name); sort($item['type']); $prefix = $module->isMain() ? '' : $module->getModulePath() . '+'; $item['submodules'] = []; foreach ($item['type'] as $v) { $item['submodules'][$v] = $prefix . $v; } } if (isset($settings[ApiBase::PARAM_SUBMODULE_PARAM_PREFIX])) { $item['submoduleparamprefix'] = $settings[ApiBase::PARAM_SUBMODULE_PARAM_PREFIX]; } } elseif ($settings[ApiBase::PARAM_TYPE] === 'tags') { $item['type'] = ChangeTags::listExplicitlyDefinedTags(); } else { $item['type'] = $settings[ApiBase::PARAM_TYPE]; } if (is_array($item['type'])) { // To prevent sparse arrays from being serialized to JSON as objects $item['type'] = array_values($item['type']); ApiResult::setIndexedTagName($item['type'], 't'); } } if (isset($settings[ApiBase::PARAM_MAX])) { $item['max'] = $settings[ApiBase::PARAM_MAX]; } if (isset($settings[ApiBase::PARAM_MAX2])) { $item['highmax'] = $settings[ApiBase::PARAM_MAX2]; } if (isset($settings[ApiBase::PARAM_MIN])) { $item['min'] = $settings[ApiBase::PARAM_MIN]; } if (!empty($settings[ApiBase::PARAM_RANGE_ENFORCE])) { $item['enforcerange'] = true; } if (!empty($settings[ApiBase::PARAM_HELP_MSG_INFO])) { $item['info'] = []; foreach ($settings[ApiBase::PARAM_HELP_MSG_INFO] as $i) { $tag = array_shift($i); $info = ['name' => $tag]; if (count($i)) { $info['values'] = $i; ApiResult::setIndexedTagName($info['values'], 'v'); } $this->formatHelpMessages($info, 'text', [$this->context->msg("apihelp-{$path}-paraminfo-{$tag}")->numParams(count($i))->params($this->context->getLanguage()->commaList($i))->params($module->getModulePrefix())]); ApiResult::setSubelementsList($info, 'text'); $item['info'][] = $info; } ApiResult::setIndexedTagName($item['info'], 'i'); } $ret['parameters'][] = $item; } ApiResult::setIndexedTagName($ret['parameters'], 'param'); $dynamicParams = $module->dynamicParameterDocumentation(); if ($dynamicParams !== null) { if ($this->helpFormat === 'none') { $ret['dynamicparameters'] = true; } else { $dynamicParams = ApiBase::makeMessage($dynamicParams, $this->context, [$module->getModulePrefix(), $module->getModuleName(), $module->getModulePath()]); $this->formatHelpMessages($ret, 'dynamicparameters', [$dynamicParams]); } } return $ret; }
public function getAllowedParams() { return array('title' => null, 'pageid' => array(ApiBase::PARAM_TYPE => 'integer'), 'reason' => null, 'tags' => array(ApiBase::PARAM_TYPE => ChangeTags::listExplicitlyDefinedTags(), ApiBase::PARAM_ISMULTI => true), 'watch' => array(ApiBase::PARAM_DFLT => false, ApiBase::PARAM_DEPRECATED => true), 'watchlist' => array(ApiBase::PARAM_DFLT => 'preferences', ApiBase::PARAM_TYPE => array('watch', 'unwatch', 'preferences', 'nochange')), 'unwatch' => array(ApiBase::PARAM_DFLT => false, ApiBase::PARAM_DEPRECATED => true), 'oldimage' => null); }
function showTagList() { $out = $this->getOutput(); $out->setPageTitle($this->msg('tags-title')); $out->wrapWikiMsg("<div class='mw-tags-intro'>\n\$1\n</div>", 'tags-intro'); $user = $this->getUser(); // Show form to create a tag if ($user->isAllowed('managechangetags')) { $fields = array('Tag' => array('type' => 'text', 'label' => $this->msg('tags-create-tag-name')->plain(), 'required' => true), 'Reason' => array('type' => 'text', 'label' => $this->msg('tags-create-reason')->plain(), 'size' => 50), 'IgnoreWarnings' => array('type' => 'hidden')); $form = new HTMLForm($fields, $this->getContext()); $form->setAction($this->getPageTitle('create')->getLocalURL()); $form->setWrapperLegendMsg('tags-create-heading'); $form->setHeaderText($this->msg('tags-create-explanation')->plain()); $form->setSubmitCallback(array($this, 'processCreateTagForm')); $form->setSubmitTextMsg('tags-create-submit'); $form->show(); // If processCreateTagForm generated a redirect, there's no point // continuing with this, as the user is just going to end up getting sent // somewhere else. Additionally, if we keep going here, we end up // populating the memcache of tag data (see ChangeTags::listDefinedTags) // with out-of-date data from the slave, because the slave hasn't caught // up to the fact that a new tag has been created as part of an implicit, // as yet uncommitted transaction on master. if ($out->getRedirect() !== '') { return; } } // Whether to show the "Actions" column in the tag list // If any actions added in the future require other user rights, add those // rights here $showActions = $user->isAllowed('managechangetags'); // Write the headers $tagUsageStatistics = ChangeTags::tagUsageStatistics(); // Show header only if there exists atleast one tag if (!$tagUsageStatistics) { return; } $html = Xml::tags('tr', null, Xml::tags('th', null, $this->msg('tags-tag')->parse()) . Xml::tags('th', null, $this->msg('tags-display-header')->parse()) . Xml::tags('th', null, $this->msg('tags-description-header')->parse()) . Xml::tags('th', null, $this->msg('tags-source-header')->parse()) . Xml::tags('th', null, $this->msg('tags-active-header')->parse()) . Xml::tags('th', null, $this->msg('tags-hitcount-header')->parse()) . ($showActions ? Xml::tags('th', array('class' => 'unsortable'), $this->msg('tags-actions-header')->parse()) : '')); // Used in #doTagRow() $this->explicitlyDefinedTags = array_fill_keys(ChangeTags::listExplicitlyDefinedTags(), true); $this->extensionDefinedTags = array_fill_keys(ChangeTags::listExtensionDefinedTags(), true); $this->extensionActivatedTags = array_fill_keys(ChangeTags::listExtensionActivatedTags(), true); foreach ($tagUsageStatistics as $tag => $hitcount) { $html .= $this->doTagRow($tag, $hitcount, $showActions); } $out->addHTML(Xml::tags('table', array('class' => 'mw-datatable sortable mw-tags-table'), $html)); }
/** * Returns a <select multiple> element with a list of change tags that can be * applied by users. * * @param array $selectedTags The tags that should be preselected in the * list. Any tags in this list, but not in the list returned by * ChangeTags::listExplicitlyDefinedTags, will be appended to the <select> * element. * @param string $label The text of a <label> to precede the <select> * @return array HTML <label> element at index 0, HTML <select> element at * index 1 */ protected function getTagSelect($selectedTags, $label) { $result = array(); $result[0] = Xml::label($label, 'mw-edittags-tag-list'); $result[1] = Xml::openElement('select', array('name' => 'wpTagList[]', 'id' => 'mw-edittags-tag-list', 'multiple' => 'multiple', 'size' => '8')); $tags = ChangeTags::listExplicitlyDefinedTags(); $tags = array_unique(array_merge($tags, $selectedTags)); foreach ($tags as $tag) { $result[1] .= Xml::option($tag, $tag, in_array($tag, $selectedTags)); } $result[1] .= Xml::closeElement('select'); return $result; }