Example #1
0
 /**
  * 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;
 }
Example #2
0
 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')));
 }
Example #3
0
 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')));
 }
Example #4
0
 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));
 }
Example #5
0
 protected function getAvailableTags()
 {
     return ChangeTags::listExplicitlyDefinedTags();
 }
Example #6
0
 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');
 }
Example #7
0
 /**
  * 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;
 }
Example #8
0
 /**
  * @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;
 }
Example #9
0
 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));
 }
Example #11
0
 /**
  * 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;
 }