From: jenkins-bot Date: Wed, 13 Sep 2017 10:15:54 +0000 (+0000) Subject: Merge "Linker: Accept LinkTargets in makeCommentLink()" X-Git-Tag: 1.31.0-rc.0~2124 X-Git-Url: http://git.cyclocoop.org/%7B%24www_url%7Dadmin/password.php?a=commitdiff_plain;h=f1c7c0f03da1607dc955dc8db879a16fc0575657;hp=1fd75c78dbd3ba2d7a66d9e35c6716b94ad2d8f3;p=lhc%2Fweb%2Fwiklou.git Merge "Linker: Accept LinkTargets in makeCommentLink()" --- diff --git a/autoload.php b/autoload.php index 4448204a5e..61fd192f0d 100644 --- a/autoload.php +++ b/autoload.php @@ -421,8 +421,8 @@ $wgAutoloadLocalClasses = [ 'EditAction' => __DIR__ . '/includes/actions/EditAction.php', 'EditCLI' => __DIR__ . '/maintenance/edit.php', 'EditPage' => __DIR__ . '/includes/EditPage.php', - 'EditWatchlistCheckboxSeriesField' => __DIR__ . '/includes/specials/SpecialEditWatchlist.php', - 'EditWatchlistNormalHTMLForm' => __DIR__ . '/includes/specials/SpecialEditWatchlist.php', + 'EditWatchlistCheckboxSeriesField' => __DIR__ . '/includes/specials/formfields/EditWatchlistCheckboxSeriesField.php', + 'EditWatchlistNormalHTMLForm' => __DIR__ . '/includes/specials/forms/EditWatchlistNormalHTMLForm.php', 'EmailConfirmation' => __DIR__ . '/includes/specials/SpecialConfirmemail.php', 'EmailInvalidation' => __DIR__ . '/includes/specials/SpecialEmailInvalidate.php', 'EmailNotification' => __DIR__ . '/includes/mail/EmailNotification.php', @@ -633,7 +633,7 @@ $wgAutoloadLocalClasses = [ 'ImageQueryPage' => __DIR__ . '/includes/specialpage/ImageQueryPage.php', 'ImportImages' => __DIR__ . '/maintenance/importImages.php', 'ImportLogFormatter' => __DIR__ . '/includes/logging/ImportLogFormatter.php', - 'ImportReporter' => __DIR__ . '/includes/specials/SpecialImport.php', + 'ImportReporter' => __DIR__ . '/includes/specials/helpers/ImportReporter.php', 'ImportSiteScripts' => __DIR__ . '/maintenance/importSiteScripts.php', 'ImportSites' => __DIR__ . '/maintenance/importSites.php', 'ImportSource' => __DIR__ . '/includes/import/ImportSource.php', @@ -746,8 +746,8 @@ $wgAutoloadLocalClasses = [ 'Languages' => __DIR__ . '/maintenance/language/languages.inc', 'LayeredParameterizedPassword' => __DIR__ . '/includes/password/LayeredParameterizedPassword.php', 'LegacyLogFormatter' => __DIR__ . '/includes/logging/LogFormatter.php', - 'License' => __DIR__ . '/includes/Licenses.php', - 'Licenses' => __DIR__ . '/includes/Licenses.php', + 'License' => __DIR__ . '/includes/specials/helpers/License.php', + 'Licenses' => __DIR__ . '/includes/specials/formfields/Licenses.php', 'LinkBatch' => __DIR__ . '/includes/cache/LinkBatch.php', 'LinkCache' => __DIR__ . '/includes/cache/LinkCache.php', 'LinkFilter' => __DIR__ . '/includes/LinkFilter.php', @@ -1135,7 +1135,7 @@ $wgAutoloadLocalClasses = [ 'PostgresInstaller' => __DIR__ . '/includes/installer/PostgresInstaller.php', 'PostgresUpdater' => __DIR__ . '/includes/installer/PostgresUpdater.php', 'Preferences' => __DIR__ . '/includes/Preferences.php', - 'PreferencesForm' => __DIR__ . '/includes/Preferences.php', + 'PreferencesForm' => __DIR__ . '/includes/specials/forms/PreferencesForm.php', 'PrefixSearch' => __DIR__ . '/includes/PrefixSearch.php', 'PreprocessDump' => __DIR__ . '/maintenance/preprocessDump.php', 'Preprocessor' => __DIR__ . '/includes/parser/Preprocessor.php', @@ -1532,14 +1532,14 @@ $wgAutoloadLocalClasses = [ 'UploadChunkVerificationException' => __DIR__ . '/includes/upload/UploadFromChunks.php', 'UploadChunkZeroLengthFileException' => __DIR__ . '/includes/upload/UploadFromChunks.php', 'UploadDumper' => __DIR__ . '/maintenance/dumpUploads.php', - 'UploadForm' => __DIR__ . '/includes/specials/SpecialUpload.php', + 'UploadForm' => __DIR__ . '/includes/specials/forms/UploadForm.php', 'UploadFromChunks' => __DIR__ . '/includes/upload/UploadFromChunks.php', 'UploadFromFile' => __DIR__ . '/includes/upload/UploadFromFile.php', 'UploadFromStash' => __DIR__ . '/includes/upload/UploadFromStash.php', 'UploadFromUrl' => __DIR__ . '/includes/upload/UploadFromUrl.php', 'UploadLogFormatter' => __DIR__ . '/includes/logging/UploadLogFormatter.php', 'UploadSourceAdapter' => __DIR__ . '/includes/import/UploadSourceAdapter.php', - 'UploadSourceField' => __DIR__ . '/includes/specials/SpecialUpload.php', + 'UploadSourceField' => __DIR__ . '/includes/specials/formfields/UploadSourceField.php', 'UploadStash' => __DIR__ . '/includes/upload/UploadStash.php', 'UploadStashBadPathException' => __DIR__ . '/includes/upload/UploadStash.php', 'UploadStashCleanup' => __DIR__ . '/maintenance/cleanupUploadStash.php', diff --git a/composer.json b/composer.json index dd7567c93c..70d2e8f310 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,7 @@ "jakub-onderka/php-parallel-lint": "0.9.2", "jetbrains/phpstorm-stubs": "dev-master#1b9906084d6635456fcf3f3a01f0d7d5b99a578a", "justinrainbow/json-schema": "~5.2", - "mediawiki/mediawiki-codesniffer": "0.11.0", + "mediawiki/mediawiki-codesniffer": "0.12.0", "monolog/monolog": "~1.22.1", "nikic/php-parser": "2.1.0", "nmred/kafka-php": "0.1.5", diff --git a/includes/AjaxDispatcher.php b/includes/AjaxDispatcher.php index 2adbc80f3b..75fcff3654 100644 --- a/includes/AjaxDispatcher.php +++ b/includes/AjaxDispatcher.php @@ -56,6 +56,7 @@ class AjaxDispatcher { /** * Load up our object with user supplied data + * @param Config $config */ function __construct( Config $config ) { $this->config = $config; diff --git a/includes/Block.php b/includes/Block.php index 40095f18b8..5a4c43e6ae 100644 --- a/includes/Block.php +++ b/includes/Block.php @@ -1329,7 +1329,7 @@ class Block { * which in turn gives User::getName(). * * @param string|int|User|null $target - * @return array( User|String|null, Block::TYPE_ constant|null ) + * @return array [ User|String|null, Block::TYPE_ constant|null ] */ public static function parseTarget( $target ) { # We may have been through this before @@ -1396,7 +1396,7 @@ class Block { * Get the target and target type for this particular Block. Note that for autoblocks, * this returns the unredacted name; frontend functions need to call $block->getRedactedName() * in this situation. - * @return array( User|String, Block::TYPE_ constant ) + * @return array [ User|String, Block::TYPE_ constant ] * @todo FIXME: This should be an integral part of the Block member variables */ public function getTargetAndType() { diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index cf8e089bee..5b77d16c4e 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -3394,8 +3394,8 @@ $wgExperimentalHtmlIds = false; /** * How should section IDs be encoded? * This array can contain 1 or 2 elements, each of them can be one of: - * - 'html5' is modern HTML5 style encoding with minimal escaping. Allows to - * display Unicode characters in many browsers' address bars. + * - 'html5' is modern HTML5 style encoding with minimal escaping. Displays Unicode + * characters in most browsers' address bars. * - 'legacy' is old MediaWiki-style encoding, e.g. 啤酒 turns into .E5.95.A4.E9.85.92 * - 'html5-legacy' corresponds to DEPRECATED $wgExperimentalHtmlIds mode. DO NOT use * it for anything but migration off that mode (see below). @@ -4920,6 +4920,7 @@ $wgDefaultUserOptions = [ 'previewontop' => 1, 'rcdays' => 7, 'rcenhancedfilters' => 0, + 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'rows' => 25, // @deprecated since 1.29 No longer used in core 'showhiddencats' => 0, @@ -6829,19 +6830,37 @@ $wgRCWatchCategoryMembership = false; */ $wgUseRCPatrol = true; +/** + * Whether a preference is displayed for structured change filters. + * If false, no preference is displayed and structured change filters are disabled. + * If true, structured change filters are *enabled* by default, and a preference is displayed + * that lets users disable them. + * + * Temporary variable during development and will be removed. + * + * @since 1.30 + */ +$wgStructuredChangeFiltersShowPreference = false; + /** * Whether to show the new experimental views (like namespaces, tags, and users) in * RecentChanges filters + * + * Temporary variable during development and will be removed. */ $wgStructuredChangeFiltersEnableExperimentalViews = false; /** * Whether to allow users to use the experimental live update feature in the new RecentChanges UI + * + * Temporary variable during development and will be removed. */ $wgStructuredChangeFiltersEnableLiveUpdate = false; /** * Whether to enable RCFilters app on Special:Watchlist + * + * Temporary variable during development and will be removed. */ $wgStructuredChangeFiltersOnWatchlist = false; diff --git a/includes/EditPage.php b/includes/EditPage.php index 06a5cc3b62..9f3f586748 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -2915,7 +2915,7 @@ class EditPage { } } - $buttonLabel = $this->context->msg( $this->getSaveButtonLabel() )->text(); + $buttonLabel = $this->context->msg( $this->getSubmitButtonLabel() )->text(); if ( $this->missingComment ) { $out->wrapWikiMsg( "
\n$1\n
", 'missingcommenttext' ); @@ -3794,7 +3794,7 @@ class EditPage { * @return string */ public function getPreviewText() { - global $wgRawHtml, $wgLang; + global $wgRawHtml; global $wgAllowUserCss, $wgAllowUserJs; $out = $this->context->getOutput(); @@ -3830,7 +3830,8 @@ class EditPage { # provide a anchor link to the editform $continueEditing = '' . - '[[#' . self::EDITFORM_ID . '|' . $wgLang->getArrow() . ' ' . + '[[#' . self::EDITFORM_ID . '|' . + $this->context->getLanguage()->getArrow() . ' ' . $this->context->msg( 'continue-editing' )->text() . ']]'; if ( $this->mTriedSave && !$this->mTokenOk ) { if ( $this->mTokenOkExceptSuffix ) { @@ -4333,9 +4334,9 @@ class EditPage { * * @return string */ - private function getSaveButtonLabel() { + protected function getSubmitButtonLabel() { $labelAsPublish = - $this->mArticle->getContext()->getConfig()->get( 'EditSubmitButtonLabelPublish' ); + $this->context->getConfig()->get( 'EditSubmitButtonLabelPublish' ); // Can't use $this->isNew as that's also true if we're adding a new section to an extant page $newPage = !$this->mTitle->exists(); @@ -4360,7 +4361,7 @@ class EditPage { public function getEditButtons( &$tabindex ) { $buttons = []; - $buttonLabel = $this->context->msg( $this->getSaveButtonLabel() )->text(); + $buttonLabel = $this->context->msg( $this->getSubmitButtonLabel() )->text(); $attribs = [ 'name' => 'wpSave', @@ -4448,11 +4449,10 @@ class EditPage { * @param string|array|bool $match Text (or array of texts) which triggered one or more filters */ public function spamPageWithContent( $match = false ) { - global $wgLang; $this->textbox2 = $this->textbox1; if ( is_array( $match ) ) { - $match = $wgLang->listToText( $match ); + $match = $this->context->getLanguage()->listToText( $match ); } $out = $this->context->getOutput(); $out->prepareErrorPage( $this->context->msg( 'spamprotectiontitle' ) ); @@ -4640,19 +4640,20 @@ class EditPage { * @since 1.29 */ protected function addLongPageWarningHeader() { - global $wgMaxArticleSize, $wgLang; + global $wgMaxArticleSize; if ( $this->contentLength === false ) { $this->contentLength = strlen( $this->textbox1 ); } $out = $this->context->getOutput(); + $lang = $this->context->getLanguage(); if ( $this->tooBig || $this->contentLength > $wgMaxArticleSize * 1024 ) { $out->wrapWikiMsg( "
\n$1\n
", [ 'longpageerror', - $wgLang->formatNum( round( $this->contentLength / 1024, 3 ) ), - $wgLang->formatNum( $wgMaxArticleSize ) + $lang->formatNum( round( $this->contentLength / 1024, 3 ) ), + $lang->formatNum( $wgMaxArticleSize ) ] ); } else { @@ -4660,7 +4661,7 @@ class EditPage { $out->wrapWikiMsg( "
\n$1\n
", [ 'longpage-hint', - $wgLang->formatSize( strlen( $this->textbox1 ) ), + $lang->formatSize( strlen( $this->textbox1 ) ), strlen( $this->textbox1 ) ] ); @@ -4717,7 +4718,7 @@ class EditPage { protected function addExplainConflictHeader( OutputPage $out ) { $out->wrapWikiMsg( "
\n$1\n
", - [ 'explainconflict', $this->context->msg( $this->getSaveButtonLabel() )->text() ] + [ 'explainconflict', $this->context->msg( $this->getSubmitButtonLabel() )->text() ] ); } diff --git a/includes/FormOptions.php b/includes/FormOptions.php index 725a512980..53c8d3bf7c 100644 --- a/includes/FormOptions.php +++ b/includes/FormOptions.php @@ -246,6 +246,9 @@ class FormOptions implements ArrayAccess { /** * @see validateBounds() + * @param string $name + * @param int $min + * @param int $max */ public function validateIntBounds( $name, $min, $max ) { $this->validateBounds( $name, $min, $max ); diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index fa97515297..e80ecf1c46 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -3160,6 +3160,7 @@ function wfShorthandToInteger( $string = '', $default = -1 ) { /** * Get the normalised IETF language tag * See unit test for examples. + * See mediawiki.language.bcp47 for the JavaScript implementation. * * @param string $code The language code. * @return string The language code which complying with BCP 47 standards. diff --git a/includes/Licenses.php b/includes/Licenses.php deleted file mode 100644 index 6467777bff..0000000000 --- a/includes/Licenses.php +++ /dev/null @@ -1,210 +0,0 @@ - - * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason - * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later - */ - -/** - * A License class for use on Special:Upload - */ -class Licenses extends HTMLFormField { - /** @var string */ - protected $msg; - - /** @var array */ - protected $licenses = []; - - /** @var string */ - protected $html; - /**#@-*/ - - /** - * @param array $params - */ - public function __construct( $params ) { - parent::__construct( $params ); - - $this->msg = empty( $params['licenses'] ) - ? wfMessage( 'licenses' )->inContentLanguage()->plain() - : $params['licenses']; - $this->selected = null; - - $this->makeLicenses(); - } - - /** - * @private - */ - protected function makeLicenses() { - $levels = []; - $lines = explode( "\n", $this->msg ); - - foreach ( $lines as $line ) { - if ( strpos( $line, '*' ) !== 0 ) { - continue; - } else { - list( $level, $line ) = $this->trimStars( $line ); - - if ( strpos( $line, '|' ) !== false ) { - $obj = new License( $line ); - $this->stackItem( $this->licenses, $levels, $obj ); - } else { - if ( $level < count( $levels ) ) { - $levels = array_slice( $levels, 0, $level ); - } - if ( $level == count( $levels ) ) { - $levels[$level - 1] = $line; - } elseif ( $level > count( $levels ) ) { - $levels[] = $line; - } - } - } - } - } - - /** - * @param string $str - * @return array - */ - protected function trimStars( $str ) { - $numStars = strspn( $str, '*' ); - return [ $numStars, ltrim( substr( $str, $numStars ), ' ' ) ]; - } - - /** - * @param array &$list - * @param array $path - * @param mixed $item - */ - protected function stackItem( &$list, $path, $item ) { - $position =& $list; - if ( $path ) { - foreach ( $path as $key ) { - $position =& $position[$key]; - } - } - $position[] = $item; - } - - /** - * @param array $tagset - * @param int $depth - */ - protected function makeHtml( $tagset, $depth = 0 ) { - foreach ( $tagset as $key => $val ) { - if ( is_array( $val ) ) { - $this->html .= $this->outputOption( - $key, '', - [ - 'disabled' => 'disabled', - 'style' => 'color: GrayText', // for MSIE - ], - $depth - ); - $this->makeHtml( $val, $depth + 1 ); - } else { - $this->html .= $this->outputOption( - $val->text, $val->template, - [ 'title' => '{{' . $val->template . '}}' ], - $depth - ); - } - } - } - - /** - * @param string $message - * @param string $value - * @param null|array $attribs - * @param int $depth - * @return string - */ - protected function outputOption( $message, $value, $attribs = null, $depth = 0 ) { - $msgObj = $this->msg( $message ); - $text = $msgObj->exists() ? $msgObj->text() : $message; - $attribs['value'] = $value; - if ( $value === $this->selected ) { - $attribs['selected'] = 'selected'; - } - - $val = str_repeat( /*   */ "\xc2\xa0", $depth * 2 ) . $text; - return str_repeat( "\t", $depth ) . Xml::element( 'option', $attribs, $val ) . "\n"; - } - - /**#@-*/ - - /** - * Accessor for $this->licenses - * - * @return array - */ - public function getLicenses() { - return $this->licenses; - } - - /** - * Accessor for $this->html - * - * @param bool $value - * - * @return string - */ - public function getInputHTML( $value ) { - $this->selected = $value; - - $this->html = $this->outputOption( wfMessage( 'nolicense' )->text(), '', - (bool)$this->selected ? null : [ 'selected' => 'selected' ] ); - $this->makeHtml( $this->getLicenses() ); - - $attribs = [ - 'name' => $this->mName, - 'id' => $this->mID - ]; - if ( !empty( $this->mParams['disabled'] ) ) { - $attibs['disabled'] = 'disabled'; - } - - return Html::rawElement( 'select', $attribs, $this->html ); - } -} - -/** - * A License class for use on Special:Upload (represents a single type of license). - */ -class License { - /** @var string */ - public $template; - - /** @var string */ - public $text; - - /** - * @param string $str License name?? - */ - function __construct( $str ) { - list( $text, $template ) = explode( '|', strrev( $str ), 2 ); - - $this->template = strrev( $template ); - $this->text = strrev( $text ); - } -} diff --git a/includes/Linker.php b/includes/Linker.php index a55067d8cd..c24ae417f1 100644 --- a/includes/Linker.php +++ b/includes/Linker.php @@ -1537,10 +1537,16 @@ class Linker { if ( $sectionIndex !== false ) { $classes .= " tocsection-$sectionIndex"; } - return "\n
  • ' . - $tocnumber . ' ' . - $tocline . ''; + + // \n
  • + // $tocnumber $tocline + return "\n" . Html::openElement( 'li', [ 'class' => $classes ] ) + . Html::rawElement( 'a', + [ 'href' => "#$anchor" ], + Html::element( 'span', [ 'class' => 'tocnumber' ], $tocnumber ) + . ' ' + . Html::rawElement( 'span', [ 'class' => 'toctext' ], $tocline ) + ); } /** diff --git a/includes/OrderedStreamingForkController.php b/includes/OrderedStreamingForkController.php index 1436c1c960..ff29cb510d 100644 --- a/includes/OrderedStreamingForkController.php +++ b/includes/OrderedStreamingForkController.php @@ -56,7 +56,7 @@ class OrderedStreamingForkController extends ForkController { } /** - * {@inheritDoc} + * @inheritDoc */ public function start() { if ( $this->procsToStart > 0 ) { diff --git a/includes/OutputPage.php b/includes/OutputPage.php index dd21194bdb..52161466a6 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -139,6 +139,9 @@ class OutputPage extends ContextSource { /** @var array Array of elements in "". Parser might add its own headers! */ protected $mHeadItems = []; + /** @var array Additional classes; there are also classes from other sources */ + protected $mAdditionalBodyClasses = []; + /** @var array */ protected $mModules = []; @@ -705,6 +708,16 @@ class OutputPage extends ContextSource { return isset( $this->mHeadItems[$name] ); } + /** + * Add a class to the element + * + * @since 1.30 + * @param string|string[] $classes One or more classes to add + */ + public function addBodyClasses( $classes ) { + $this->mAdditionalBodyClasses = array_merge( $this->mAdditionalBodyClasses, (array)$classes ); + } + /** * @deprecated since 1.28 Obsolete - wgUseETag experiment was removed. * @param string $tag @@ -2013,7 +2026,7 @@ class OutputPage extends ContextSource { } $age = time() - wfTimestamp( TS_UNIX, $mtime ); - $adaptiveTTL = max( .9 * $age, $minTTL ); + $adaptiveTTL = max( 0.9 * $age, $minTTL ); $adaptiveTTL = min( $adaptiveTTL, $maxTTL ); $this->lowerCdnMaxage( (int)$adaptiveTTL ); @@ -2923,7 +2936,7 @@ class OutputPage extends ContextSource { $pieces[] = Html::closeElement( 'head' ); - $bodyClasses = []; + $bodyClasses = $this->mAdditionalBodyClasses; $bodyClasses[] = 'mediawiki'; # Classes for LTR/RTL directionality support diff --git a/includes/Pingback.php b/includes/Pingback.php index bd1b2a25b4..c3393bcc1c 100644 --- a/includes/Pingback.php +++ b/includes/Pingback.php @@ -228,6 +228,7 @@ class Pingback { * * The schema for the data is located at: * + * @return bool */ public function sendPingback() { if ( !$this->acquireLock() ) { diff --git a/includes/Preferences.php b/includes/Preferences.php index c64e8a8ae1..0bb1d28af3 100644 --- a/includes/Preferences.php +++ b/includes/Preferences.php @@ -1,7 +1,5 @@ 'tog-shownumberswatching', ]; } + + if ( $config->get( 'StructuredChangeFiltersShowPreference' ) ) { + $defaultPreferences['rcenhancedfilters-disable'] = [ + 'type' => 'toggle', + 'section' => 'rc/advancedrc', + 'label-message' => 'rcfilters-preference-label', + 'help-message' => 'rcfilters-preference-help', + ]; + } } /** @@ -1626,123 +1633,3 @@ class Preferences { return $timeZoneList; } } - -/** Some tweaks to allow js prefs to work */ -class PreferencesForm extends HTMLForm { - // Override default value from HTMLForm - protected $mSubSectionBeforeFields = false; - - private $modifiedUser; - - /** - * @param User $user - */ - public function setModifiedUser( $user ) { - $this->modifiedUser = $user; - } - - /** - * @return User - */ - public function getModifiedUser() { - if ( $this->modifiedUser === null ) { - return $this->getUser(); - } else { - return $this->modifiedUser; - } - } - - /** - * Get extra parameters for the query string when redirecting after - * successful save. - * - * @return array - */ - public function getExtraSuccessRedirectParameters() { - return []; - } - - /** - * @param string $html - * @return string - */ - function wrapForm( $html ) { - $html = Xml::tags( 'div', [ 'id' => 'preferences' ], $html ); - - return parent::wrapForm( $html ); - } - - /** - * @return string - */ - function getButtons() { - $attrs = [ 'id' => 'mw-prefs-restoreprefs' ]; - - if ( !$this->getModifiedUser()->isAllowedAny( 'editmyprivateinfo', 'editmyoptions' ) ) { - return ''; - } - - $html = parent::getButtons(); - - if ( $this->getModifiedUser()->isAllowed( 'editmyoptions' ) ) { - $t = $this->getTitle()->getSubpage( 'reset' ); - - $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer(); - $html .= "\n" . $linkRenderer->makeLink( $t, $this->msg( 'restoreprefs' )->text(), - Html::buttonAttributes( $attrs, [ 'mw-ui-quiet' ] ) ); - - $html = Xml::tags( 'div', [ 'class' => 'mw-prefs-buttons' ], $html ); - } - - return $html; - } - - /** - * Separate multi-option preferences into multiple preferences, since we - * have to store them separately - * @param array $data - * @return array - */ - function filterDataForSubmit( $data ) { - foreach ( $this->mFlatFields as $fieldname => $field ) { - if ( $field instanceof HTMLNestedFilterable ) { - $info = $field->mParams; - $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $fieldname; - foreach ( $field->filterDataForSubmit( $data[$fieldname] ) as $key => $value ) { - $data["$prefix$key"] = $value; - } - unset( $data[$fieldname] ); - } - } - - return $data; - } - - /** - * Get the whole body of the form. - * @return string - */ - function getBody() { - return $this->displaySection( $this->mFieldTree, '', 'mw-prefsection-' ); - } - - /** - * Get the "" for a given section key. Normally this is the - * prefs-$key message but we'll allow extensions to override it. - * @param string $key - * @return string - */ - function getLegend( $key ) { - $legend = parent::getLegend( $key ); - Hooks::run( 'PreferencesGetLegend', [ $this, $key, &$legend ] ); - return $legend; - } - - /** - * Get the keys of each top level preference section. - * @return array of section keys - */ - function getPreferenceSections() { - return array_keys( array_filter( $this->mFieldTree, 'is_array' ) ); - } -} diff --git a/includes/Sanitizer.php b/includes/Sanitizer.php index ed09701d4b..7d17cd1065 100644 --- a/includes/Sanitizer.php +++ b/includes/Sanitizer.php @@ -1284,7 +1284,6 @@ class Sanitizer { $mode = $wgFragmentMode[self::ID_PRIMARY]; $id = self::escapeIdInternal( $id, $mode ); - $id = self::urlEscapeId( $id, $mode ); return $id; } @@ -1302,23 +1301,6 @@ class Sanitizer { global $wgExternalInterwikiFragmentMode; $id = self::escapeIdInternal( $id, $wgExternalInterwikiFragmentMode ); - $id = self::urlEscapeId( $id, $wgExternalInterwikiFragmentMode ); - - return $id; - } - - /** - * Helper for escapeIdFor*() functions. URL-escapes the ID if needed. - * - * @param string $id String to escape - * @param string $mode One of modes from $wgFragmentMode - * @return string - */ - private static function urlEscapeId( $id, $mode ) { - if ( $mode === 'html5' ) { - $id = urlencode( $id ); - $id = str_replace( '%3A', ':', $id ); - } return $id; } diff --git a/includes/TemplateParser.php b/includes/TemplateParser.php index 2759ff9baa..2293dabbd9 100644 --- a/includes/TemplateParser.php +++ b/includes/TemplateParser.php @@ -38,6 +38,13 @@ class TemplateParser { */ protected $forceRecompile = false; + /** + * @var int Compilation flags passed to LightnCandy + */ + // Do not add more flags here without discussion. + // If you do add more flags, be sure to update unit tests as well. + protected $compileFlags = LightnCandy::FLAG_ERROR_EXCEPTION; + /** * @param string $templateDir * @param bool $forceRecompile @@ -47,6 +54,18 @@ class TemplateParser { $this->forceRecompile = $forceRecompile; } + /** + * Enable/disable the use of recursive partials. + * @param bool $enable + */ + public function enableRecursivePartials( $enable ) { + if ( $enable ) { + $this->compileFlags = $this->compileFlags | LightnCandy::FLAG_RUNTIMEPARTIAL; + } else { + $this->compileFlags = $this->compileFlags & ~LightnCandy::FLAG_RUNTIMEPARTIAL; + } + } + /** * Constructs the location of the the source Mustache template * @param string $templateName The name of the template @@ -73,11 +92,13 @@ class TemplateParser { * @throws RuntimeException */ protected function getTemplate( $templateName ) { + $templateKey = $templateName . '|' . $this->compileFlags; + // If a renderer has already been defined for this template, reuse it - if ( isset( $this->renderers[$templateName] ) && - is_callable( $this->renderers[$templateName] ) + if ( isset( $this->renderers[$templateKey] ) && + is_callable( $this->renderers[$templateKey] ) ) { - return $this->renderers[$templateName]; + return $this->renderers[$templateKey]; } $filename = $this->getTemplateFilename( $templateName ); @@ -90,7 +111,7 @@ class TemplateParser { $fileContents = file_get_contents( $filename ); // Generate a quick hash for cache invalidation - $fastHash = md5( $fileContents ); + $fastHash = md5( $this->compileFlags . '|' . $fileContents ); // Fetch a secret key for building a keyed hash of the PHP code $config = MediaWikiServices::getInstance()->getMainConfig(); @@ -127,7 +148,7 @@ class TemplateParser { if ( !is_callable( $renderer ) ) { throw new RuntimeException( "Requested template, {$templateName}, is not callable" ); } - $this->renderers[$templateName] = $renderer; + $this->renderers[$templateKey] = $renderer; return $renderer; } @@ -168,9 +189,7 @@ class TemplateParser { return LightnCandy::compile( $code, [ - // Do not add more flags here without discussion. - // If you do add more flags, be sure to update unit tests as well. - 'flags' => LightnCandy::FLAG_ERROR_EXCEPTION, + 'flags' => $this->compileFlags, 'basedir' => $this->templateDir, 'fileext' => '.mustache', ] diff --git a/includes/Title.php b/includes/Title.php index 8cfeb882a0..3da6ab9552 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -1797,7 +1797,7 @@ class Title implements LinkTarget { * @see self::getLocalURL for the arguments. * @param array|string $query * @param string $proto Protocol type to use in URL - * @return String. A url suitable to use in an HTTP location header. + * @return string A url suitable to use in an HTTP location header. */ public function getFullUrlForRedirect( $query = '', $proto = PROTO_CURRENT ) { $target = $this; @@ -1975,6 +1975,8 @@ class Title implements LinkTarget { * NOTE: Unlike getInternalURL(), the canonical URL includes the fragment * * @see self::getLocalURL for the arguments. + * @param string $query + * @param string|bool $query2 * @return string The URL * @since 1.18 */ diff --git a/includes/Xml.php b/includes/Xml.php index 16a5a9ddec..0091513125 100644 --- a/includes/Xml.php +++ b/includes/Xml.php @@ -493,7 +493,8 @@ class Xml { } /** - * Build a drop-down box from a textual list. + * Build a drop-down box from a textual list. This is a wrapper + * for Xml::listDropDownOptions() plus the XmlSelect class. * * @param string $name Name and id for the drop-down * @param string $list Correctly formatted text (newline delimited) to be @@ -507,60 +508,91 @@ class Xml { public static function listDropDown( $name = '', $list = '', $other = '', $selected = '', $class = '', $tabindex = null ) { - $optgroup = false; + $options = self::listDropDownOptions( $list, [ 'other' => $other ] ); + + $xmlSelect = new XmlSelect( $name, $name, $selected ); + $xmlSelect->addOptions( $options ); + + if ( $class ) { + $xmlSelect->setAttribute( 'class', $class ); + } + if ( $tabindex ) { + $xmlSelect->setAttribute( 'tabindex', $tabindex ); + } - $options = self::option( $other, 'other', $selected === 'other' ); + return $xmlSelect->getHTML(); + } + /** + * Build options for a drop-down box from a textual list. + * + * The result of this function can be passed to XmlSelect::addOptions() + * (to render a plain `' . "\n" . - '' . - '' . - '' . - '' . - '' . "\n" . + '', Xml::listDropDown( // name @@ -426,4 +429,52 @@ class XmlTest extends MediaWikiTestCase { ) ); } + + /** + * @covers Xml::listDropDownOptions + */ + public function testListDropDownOptions() { + $this->assertEquals( + [ + 'other reasons' => 'other', + 'Foo' => [ + 'Foo 1' => 'Foo 1', + 'Example' => 'Example', + ], + 'Bar' => [ + 'Bar 1' => 'Bar 1', + ], + ], + Xml::listDropDownOptions( + "* Foo\n** Foo 1\n** Example\n* Bar\n** Bar 1", + [ 'other' => 'other reasons' ] + ) + ); + } + + /** + * @covers Xml::listDropDownOptionsOoui + */ + public function testListDropDownOptionsOoui() { + $this->assertEquals( + [ + [ 'data' => 'other', 'label' => 'other reasons' ], + [ 'optgroup' => 'Foo' ], + [ 'data' => 'Foo 1', 'label' => 'Foo 1' ], + [ 'data' => 'Example', 'label' => 'Example' ], + [ 'optgroup' => 'Bar' ], + [ 'data' => 'Bar 1', 'label' => 'Bar 1' ], + ], + Xml::listDropDownOptionsOoui( [ + 'other reasons' => 'other', + 'Foo' => [ + 'Foo 1' => 'Foo 1', + 'Example' => 'Example', + ], + 'Bar' => [ + 'Bar 1' => 'Bar 1', + ], + ] ) + ); + } } diff --git a/tests/phpunit/includes/db/DatabaseTestHelper.php b/tests/phpunit/includes/db/DatabaseTestHelper.php index 9ed8f15630..d19d998146 100644 --- a/tests/phpunit/includes/db/DatabaseTestHelper.php +++ b/tests/phpunit/includes/db/DatabaseTestHelper.php @@ -53,6 +53,7 @@ class DatabaseTestHelper extends Database { /** * Returns SQL queries grouped by '; ' * Clear the list of queries that have been done so far. + * @return string */ public function getLastSqls() { $lastSqls = implode( '; ', $this->lastSqls ); diff --git a/tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php b/tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php index 881ace272f..c762aa7d70 100644 --- a/tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php +++ b/tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php @@ -1184,11 +1184,11 @@ class WANObjectCacheTest extends PHPUnit_Framework_TestCase { public static function provideAdaptiveTTL() { return [ - [ 3600, 900, 30, .2, 720 ], - [ 3600, 500, 30, .2, 500 ], - [ 3600, 86400, 800, .2, 800 ], - [ false, 86400, 800, .2, 800 ], - [ null, 86400, 800, .2, 800 ] + [ 3600, 900, 30, 0.2, 720 ], + [ 3600, 500, 30, 0.2, 500 ], + [ 3600, 86400, 800, 0.2, 800 ], + [ false, 86400, 800, 0.2, 800 ], + [ null, 86400, 800, 0.2, 800 ] ]; } diff --git a/tests/phpunit/includes/libs/rdbms/TransactionProfilerTest.php b/tests/phpunit/includes/libs/rdbms/TransactionProfilerTest.php index cb18fb3dc3..b6ea4265ba 100644 --- a/tests/phpunit/includes/libs/rdbms/TransactionProfilerTest.php +++ b/tests/phpunit/includes/libs/rdbms/TransactionProfilerTest.php @@ -112,10 +112,10 @@ class TransactionProfilerTest extends PHPUnit_Framework_TestCase { $tp->setLogger( $logger ); $tp->setExpectation( 'queries', 2, __METHOD__ ); - $tp->recordQueryCompletion( "SQL 1", microtime( true ) - .01, false, 0 ); - $tp->recordQueryCompletion( "SQL 2", microtime( true ) - .01, false, 0 ); - $tp->recordQueryCompletion( "SQL 3", microtime( true ) - .01, false, 0 ); // warn - $tp->recordQueryCompletion( "SQL 4", microtime( true ) - .01, false, 0 ); // warn + $tp->recordQueryCompletion( "SQL 1", microtime( true ) - 0.01, false, 0 ); + $tp->recordQueryCompletion( "SQL 2", microtime( true ) - 0.01, false, 0 ); + $tp->recordQueryCompletion( "SQL 3", microtime( true ) - 0.01, false, 0 ); // warn + $tp->recordQueryCompletion( "SQL 4", microtime( true ) - 0.01, false, 0 ); // warn } public function testWriteQueryCount() { @@ -126,16 +126,16 @@ class TransactionProfilerTest extends PHPUnit_Framework_TestCase { $tp->setLogger( $logger ); $tp->setExpectation( 'writes', 2, __METHOD__ ); - $tp->recordQueryCompletion( "SQL 1", microtime( true ) - .01, false, 0 ); - $tp->recordQueryCompletion( "SQL 2", microtime( true ) - .01, false, 0 ); - $tp->recordQueryCompletion( "SQL 3", microtime( true ) - .01, false, 0 ); - $tp->recordQueryCompletion( "SQL 4", microtime( true ) - .01, false, 0 ); + $tp->recordQueryCompletion( "SQL 1", microtime( true ) - 0.01, false, 0 ); + $tp->recordQueryCompletion( "SQL 2", microtime( true ) - 0.01, false, 0 ); + $tp->recordQueryCompletion( "SQL 3", microtime( true ) - 0.01, false, 0 ); + $tp->recordQueryCompletion( "SQL 4", microtime( true ) - 0.01, false, 0 ); $tp->transactionWritingIn( 'srv1', 'db1', '123' ); - $tp->recordQueryCompletion( "SQL 1w", microtime( true ) - .01, true, 2 ); - $tp->recordQueryCompletion( "SQL 2w", microtime( true ) - .01, true, 5 ); - $tp->recordQueryCompletion( "SQL 3w", microtime( true ) - .01, true, 3 ); - $tp->recordQueryCompletion( "SQL 4w", microtime( true ) - .01, true, 1 ); + $tp->recordQueryCompletion( "SQL 1w", microtime( true ) - 0.01, true, 2 ); + $tp->recordQueryCompletion( "SQL 2w", microtime( true ) - 0.01, true, 5 ); + $tp->recordQueryCompletion( "SQL 3w", microtime( true ) - 0.01, true, 3 ); + $tp->recordQueryCompletion( "SQL 4w", microtime( true ) - 0.01, true, 1 ); $tp->transactionWritingOut( 'srv1', 'db1', '123', 1, 1 ); } } diff --git a/tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php b/tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php index b564310429..456447f01c 100644 --- a/tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php +++ b/tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php @@ -352,8 +352,8 @@ class DatabaseMysqlBaseTest extends PHPUnit_Framework_TestCase { $db->setLBInfo( 'clusterMasterHost', 'db1052' ); $lagEst = $db->getLag(); - $this->assertGreaterThan( $lag - .010, $lagEst, "Correct heatbeat lag" ); - $this->assertLessThan( $lag + .010, $lagEst, "Correct heatbeat lag" ); + $this->assertGreaterThan( $lag - 0.010, $lagEst, "Correct heatbeat lag" ); + $this->assertLessThan( $lag + 0.010, $lagEst, "Correct heatbeat lag" ); } public static function provideLagAmounts() { diff --git a/tests/phpunit/includes/specials/SpecialPageExecutor.php b/tests/phpunit/includes/specials/SpecialPageExecutor.php index 2f7b7678ca..e7cfca7f01 100644 --- a/tests/phpunit/includes/specials/SpecialPageExecutor.php +++ b/tests/phpunit/includes/specials/SpecialPageExecutor.php @@ -15,7 +15,7 @@ class SpecialPageExecutor { * @param User|null $user The user which should be used in the context of this special page * * @throws Exception - * @return array( string, WebResponse ) A two-elements array containing the HTML output + * @return array [ string, WebResponse ] A two-elements array containing the HTML output * generated by the special page as well as the response object. */ public function executeSpecialPage( diff --git a/tests/phpunit/includes/specials/SpecialPageTestBase.php b/tests/phpunit/includes/specials/SpecialPageTestBase.php index 2f091d5d06..930bbe4de7 100644 --- a/tests/phpunit/includes/specials/SpecialPageTestBase.php +++ b/tests/phpunit/includes/specials/SpecialPageTestBase.php @@ -51,7 +51,7 @@ abstract class SpecialPageTestBase extends MediaWikiTestCase { * @param User|null $user The user which should be used in the context of this special page * * @throws Exception - * @return array( string, WebResponse ) A two-elements array containing the HTML output + * @return array [ string, WebResponse ] A two-elements array containing the HTML output * generated by the special page as well as the response object. */ protected function executeSpecialPage( diff --git a/tests/phpunit/mocks/content/DummyContentHandlerForTesting.php b/tests/phpunit/mocks/content/DummyContentHandlerForTesting.php index d712254c22..6b9b782397 100644 --- a/tests/phpunit/mocks/content/DummyContentHandlerForTesting.php +++ b/tests/phpunit/mocks/content/DummyContentHandlerForTesting.php @@ -34,6 +34,7 @@ class DummyContentHandlerForTesting extends ContentHandler { /** * Creates an empty Content object of the type supported by this ContentHandler. + * @return DummyContentForTesting */ public function makeEmptyContent() { return new DummyContentForTesting( '' ); diff --git a/tests/phpunit/mocks/content/DummyNonTextContentHandler.php b/tests/phpunit/mocks/content/DummyNonTextContentHandler.php index 098181debb..9d91d4a1a2 100644 --- a/tests/phpunit/mocks/content/DummyNonTextContentHandler.php +++ b/tests/phpunit/mocks/content/DummyNonTextContentHandler.php @@ -34,6 +34,7 @@ class DummyNonTextContentHandler extends DummyContentHandlerForTesting { /** * Creates an empty Content object of the type supported by this ContentHandler. + * @return DummyNonTextContent */ public function makeEmptyContent() { return new DummyNonTextContent( '' ); diff --git a/tests/phpunit/mocks/filebackend/MockFSFile.php b/tests/phpunit/mocks/filebackend/MockFSFile.php index 047c03ad1f..ef1caa5d12 100644 --- a/tests/phpunit/mocks/filebackend/MockFSFile.php +++ b/tests/phpunit/mocks/filebackend/MockFSFile.php @@ -41,6 +41,7 @@ class MockFSFile extends FSFile { /** * August 22 – The theft of the Mona Lisa is discovered in the Louvre." * T22281 + * @return int */ public function getSize() { return 1911; diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js index b9650796ef..5ce61ea752 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js @@ -1,7 +1,7 @@ ( function ( mw, $ ) { 'use strict'; - var grammarTests; + var grammarTests, bcp47Tests; QUnit.module( 'mediawiki.language', QUnit.newMwEnvironment( { setup: function () { @@ -587,4 +587,100 @@ assert.equal( mw.language.listToText( [ 'a', 'b' ] ), 'a and b', 'Two items' ); assert.equal( mw.language.listToText( [ 'a', 'b', 'c' ] ), 'a, b and c', 'More than two items' ); } ); + + bcp47Tests = [ + // Extracted from BCP 47 (list not exhaustive) + // # 2.1.1 + [ 'en-ca-x-ca', 'en-CA-x-ca' ], + [ 'sgn-be-fr', 'sgn-BE-FR' ], + [ 'az-latn-x-latn', 'az-Latn-x-latn' ], + // # 2.2 + [ 'sr-Latn-RS', 'sr-Latn-RS' ], + [ 'az-arab-ir', 'az-Arab-IR' ], + + // # 2.2.5 + [ 'sl-nedis', 'sl-nedis' ], + [ 'de-ch-1996', 'de-CH-1996' ], + + // # 2.2.6 + [ + 'en-latn-gb-boont-r-extended-sequence-x-private', + 'en-Latn-GB-boont-r-extended-sequence-x-private' + ], + + // Examples from BCP 47 Appendix A + // # Simple language subtag: + [ 'DE', 'de' ], + [ 'fR', 'fr' ], + [ 'ja', 'ja' ], + + // # Language subtag plus script subtag: + [ 'zh-hans', 'zh-Hans' ], + [ 'sr-cyrl', 'sr-Cyrl' ], + [ 'sr-latn', 'sr-Latn' ], + + // # Extended language subtags and their primary language subtag + // # counterparts: + [ 'zh-cmn-hans-cn', 'zh-cmn-Hans-CN' ], + [ 'cmn-hans-cn', 'cmn-Hans-CN' ], + [ 'zh-yue-hk', 'zh-yue-HK' ], + [ 'yue-hk', 'yue-HK' ], + + // # Language-Script-Region: + [ 'zh-hans-cn', 'zh-Hans-CN' ], + [ 'sr-latn-RS', 'sr-Latn-RS' ], + + // # Language-Variant: + [ 'sl-rozaj', 'sl-rozaj' ], + [ 'sl-rozaj-biske', 'sl-rozaj-biske' ], + [ 'sl-nedis', 'sl-nedis' ], + + // # Language-Region-Variant: + [ 'de-ch-1901', 'de-CH-1901' ], + [ 'sl-it-nedis', 'sl-IT-nedis' ], + + // # Language-Script-Region-Variant: + [ 'hy-latn-it-arevela', 'hy-Latn-IT-arevela' ], + + // # Language-Region: + [ 'de-de', 'de-DE' ], + [ 'en-us', 'en-US' ], + [ 'es-419', 'es-419' ], + + // # Private use subtags: + [ 'de-ch-x-phonebk', 'de-CH-x-phonebk' ], + [ 'az-arab-x-aze-derbend', 'az-Arab-x-aze-derbend' ], + /** + * Previous test does not reflect the BCP 47 which states: + * az-Arab-x-AZE-derbend + * AZE being private, it should be lower case, hence the test above + * should probably be: + * [ 'az-arab-x-aze-derbend', 'az-Arab-x-AZE-derbend' ], + */ + + // # Private use registry values: + [ 'x-whatever', 'x-whatever' ], + [ 'qaa-qaaa-qm-x-southern', 'qaa-Qaaa-QM-x-southern' ], + [ 'de-qaaa', 'de-Qaaa' ], + [ 'sr-latn-qm', 'sr-Latn-QM' ], + [ 'sr-qaaa-rs', 'sr-Qaaa-RS' ], + + // # Tags that use extensions + [ 'en-us-u-islamcal', 'en-US-u-islamcal' ], + [ 'zh-cn-a-myext-x-private', 'zh-CN-a-myext-x-private' ], + [ 'en-a-myext-b-another', 'en-a-myext-b-another' ] + + // # Invalid: + // de-419-DE + // a-DE + // ar-a-aaa-b-bbb-a-ccc + ]; + + QUnit.test( 'mw.language.bcp47', function ( assert ) { + bcp47Tests.forEach( function ( data ) { + var input = data[ 0 ], + expected = data[ 1 ]; + assert.equal( mw.language.bcp47( input ), expected ); + } ); + } ); }( mediaWiki, jQuery ) ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js index 2efe9cd7f4..bb27626575 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js @@ -156,7 +156,7 @@ // Test cases are kept in sync with SanitizerTest.php var text = 'foo тест_#%!\'()[]:<>', legacyEncoded = 'foo_.D1.82.D0.B5.D1.81.D1.82_.23.25.21.27.28.29.5B.5D:.3C.3E', - html5Escaped = 'foo_%D1%82%D0%B5%D1%81%D1%82_%23%25!\'()%5B%5D:%3C%3E', + html5Encoded = 'foo_тест_#%!\'()[]:<>', html5Experimental = 'foo_тест_!_()[]:<>', // Settings: this is wgFragmentMode legacy = [ 'legacy' ], @@ -172,13 +172,13 @@ // Transition to a new world: legacy links with HTML5 fallback [ legacyNew, text, legacyEncoded ], // New world: HTML5 links, legacy fallbacks - [ newLegacy, text, html5Escaped ], + [ newLegacy, text, html5Encoded ], // Distant future: no legacy fallbacks - [ allNew, text, html5Escaped ], + [ allNew, text, html5Encoded ], // Someone flipped wgExperimentalHtmlIds on [ experimentalLegacy, text, html5Experimental ], // Migration from wgExperimentalHtmlIds to modern HTML5 - [ newExperimental, text, html5Escaped ] + [ newExperimental, text, html5Encoded ] ], function ( index, testCase ) { mw.config.set( 'wgFragmentMode', testCase[ 0 ] );