* $wgEnablePartialBlocks – This enables the Partial Blocks feature, which gives
accounts with block permissions the ability to block users, IPs, and IP ranges
from editing specific pages, while allowing them to edit the rest of the wiki.
-* $wgMediaInTargetLanguage – whether multilingual images should be dispalyed in
- the current parse language where available.
==== Changed configuration ====
* Some external link searches will not work correctly until update.php (or
(requires PHP 7.2+) and GPU hacking (7.3+).
* Special:CreateAccount now warns the user if their chosen username has to be
normalized.
+* (T205040) Multilingual images are now be displayed in the current parse
+ language where available.
=== External library changes in 1.33 ===
*/
public function getRedactedName() {
if ( $this->mAuto ) {
- return Html::rawElement(
+ return Html::element(
'span',
[ 'class' => 'mw-autoblockid' ],
- wfMessage( 'autoblockid', $this->mId )
+ wfMessage( 'autoblockid', $this->mId )->text()
);
} else {
return htmlspecialchars( $this->getTarget() );
$db, 'log_user', User::newFromName( $params['user'], false )
);
$this->addWhere( $q['conds'] );
+
+ // T71222: MariaDB's optimizer, at least 10.1.37 and .38, likes to choose a wildly bad plan for
+ // some reason for this code path. Tell it not to use the wrong index it wants to pick.
+ $this->addOption( 'IGNORE INDEX', [ 'logging' => [ 'times' ] ] );
}
$title = $params['title'];
}
if ( !$caches ) {
- $key = 'config-no-cache-apcu';
- $this->showMessage( $key );
+ $this->showMessage( 'config-no-cache-apcu' );
}
$this->setVar( '_Caches', $caches );
}
/**
- * Generate a secret value for variables using our CryptRand generator.
- * Produce a warning if the random source was insecure.
+ * Generate a secret value for variables using a secure generator.
*
* @param array $keys
* @return Status
$ticket = $factory->getEmptyTransactionTicket( __METHOD__ );
// Update page_touched (skipping pages already touched since the root job).
// Check $wgUpdateRowsPerQuery for sanity; batch jobs are sized by that already.
- foreach ( array_chunk( $pageIds, $wgUpdateRowsPerQuery ) as $batch ) {
- $factory->commitAndWaitForReplication( __METHOD__, $ticket );
-
+ $batches = array_chunk( $pageIds, $wgUpdateRowsPerQuery );
+ foreach ( $batches as $batch ) {
$dbw->update( 'page',
[ 'page_touched' => $dbw->timestamp( $touchTimestamp ) ],
[ 'page_id' => $batch,
],
__METHOD__
);
+ if ( count( $batches ) > 1 ) {
+ $factory->commitAndWaitForReplication( __METHOD__, $ticket );
+ }
}
// Get the list of affected pages (races only mean something else did the purge)
$titleArray = TitleArray::newFromResult( $dbw->select(
$batchSize = $services->getMainConfig()->get( 'UpdateRowsPerQuery' );
$ticket = $lbFactory->getEmptyTransactionTicket( $fname );
- foreach ( array_chunk( $ids, $batchSize ) as $idBatch ) {
+ $idBatches = array_chunk( $ids, $batchSize );
+ foreach ( $idBatches as $idBatch ) {
$dbw->update(
'page',
[ 'page_touched' => $now ],
],
$fname
);
- $lbFactory->commitAndWaitForReplication( $fname, $ticket );
+ if ( count( $idBatches ) > 1 ) {
+ $lbFactory->commitAndWaitForReplication( $fname, $ticket );
+ }
}
}
) );
* @param string $key Cache key
* @param mixed $value
* @param int $ttl Seconds to live. Special values are:
- * - WANObjectCache::TTL_INDEFINITE: Cache forever
+ * - WANObjectCache::TTL_INDEFINITE: Cache forever (default)
* @param array $opts Options map:
* - lag : Seconds of replica DB lag. Typically, this is either the replica DB lag
* before the data was read or, if applicable, the replica DB lag before
* @note Options added in 1.28: staleTTL
* @return bool Success
*/
- final public function set( $key, $value, $ttl = 0, array $opts = [] ) {
+ final public function set( $key, $value, $ttl = self::TTL_INDEFINITE, array $opts = [] ) {
$now = $this->getCurrentTime();
$lockTSE = $opts['lockTSE'] ?? self::TSE_NONE;
$staleTTL = $opts['staleTTL'] ?? self::STALE_TTL_NONE;
return $this->__call( __FUNCTION__, func_get_args() );
}
+ public function addIdentifierQuotes( $s ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
public function buildLike() {
return $this->__call( __FUNCTION__, func_get_args() );
}
}
/**
+ * Error out if the DB is not in a valid state for a query via query()
+ *
* @param string $sql
* @param string $fname
* @throws DBTransactionStateError
*/
private function assertTransactionStatus( $sql, $fname ) {
- if ( $this->getQueryVerb( $sql ) === 'ROLLBACK' ) { // transaction/savepoint
+ $verb = $this->getQueryVerb( $sql );
+ if ( $verb === 'USE' ) {
+ throw new DBUnexpectedError( $this, "Got USE query; use selectDomain() instead." );
+ }
+
+ if ( $verb === 'ROLLBACK' ) { // transaction/savepoint
return;
}
}
}
- /**
- * Quotes an identifier using `backticks` or "double quotes" depending on the database type.
- * MySQL uses `backticks` while basically everything else uses double quotes.
- * Since MySQL is the odd one out here the double quotes are our generic
- * and we implement backticks in DatabaseMysqlBase.
- *
- * @param string $s
- * @return string
- */
public function addIdentifierQuotes( $s ) {
return '"' . str_replace( '"', '""', $s ) . '"';
}
}
protected function doSelectDomain( DatabaseDomain $domain ) {
- $encDatabase = $this->addIdentifierQuotes( $domain->getDatabase() );
- $this->query( "USE $encDatabase" );
+ if ( $domain->getSchema() !== null ) {
+ throw new DBExpectedError( $this, __CLASS__ . ": domain schemas are not supported." );
+ }
+
+ $database = $domain->getDatabase();
+ if ( $database !== $this->getDBname() ) {
+ $encDatabase = $this->addIdentifierQuotes( $database );
+ $res = $this->doQuery( "USE $encDatabase" );
+ if ( !$res ) {
+ throw new DBExpectedError( $this, "Could not select database '$database'." );
+ }
+ }
// Update that domain fields on success (no exception thrown)
$this->currentDomain = $domain;
}
function doSelectDomain( DatabaseDomain $domain ) {
- $conn = $this->getBindingHandle();
-
if ( $domain->getSchema() !== null ) {
throw new DBExpectedError( $this, __CLASS__ . ": domain schemas are not supported." );
}
$database = $domain->getDatabase();
- if ( !$conn->select_db( $database ) ) {
- throw new DBExpectedError( $this, "Could not select database '$database'." );
+ if ( $database !== $this->getDBname() ) {
+ $conn = $this->getBindingHandle();
+ if ( !$conn->select_db( $database ) ) {
+ throw new DBExpectedError( $this, "Could not select database '$database'." );
+ }
}
// Update that domain fields on success (no exception thrown)
*/
public function addQuotes( $s );
+ /**
+ * Quotes an identifier, in order to make user controlled input safe
+ *
+ * Depending on the database this will either be `backticks` or "double quotes"
+ *
+ * @param string $s
+ * @return string
+ * @since 1.33
+ */
+ public function addIdentifierQuotes( $s );
+
/**
* LIKE statement wrapper, receives a variable-length argument list with
* parts of pattern to match containing either string literals that will be
# * bottom
# * text-bottom
- global $wgMediaInTargetLanguage;
-
# Protect LanguageConverter markup when splitting into parts
$parts = StringUtils::delimiterExplode(
'-{', '}-', '|', $options, true /* allow nesting */
# Use the "caption" for the tooltip text
$params['frame']['title'] = $this->stripAltText( $caption, $holders );
}
- if ( $wgMediaInTargetLanguage ) {
- $params['handler']['targetlang'] = $this->getTargetLanguage()->getCode();
- }
+ $params['handler']['targetlang'] = $this->getTargetLanguage()->getCode();
Hooks::run( 'ParserMakeImageParams', [ $title, $file, &$params, $this ] );
// mw.loader.implement will use globalEval if scripts is a string.
// Minify manually here, because general response minification is
// not effective due it being a string literal, not a function.
- if ( !self::inDebugMode() ) {
+ if ( !$context->getDebug() ) {
$scripts = self::filter( 'minify-js', $scripts ); // T107377
}
} else {
'modules' => self::makePackedModulesString( $modules ),
'lang' => $lang,
'skin' => $skin,
- 'debug' => $debug ? 'true' : 'false',
];
+ if ( $debug === true ) {
+ $query['debug'] = 'true';
+ }
if ( $user !== null ) {
$query['user'] = $user;
}
// Various parameters
$this->user = $request->getRawVal( 'user' );
- $this->debug = $request->getFuzzyBool(
- 'debug',
- $this->getConfig()->get( 'ResourceLoaderDebug' )
- );
+ $this->debug = $request->getRawVal( 'debug' ) === 'true';
$this->only = $request->getRawVal( 'only', null );
$this->version = $request->getRawVal( 'version', null );
$this->raw = $request->getFuzzyBool( 'raw' );
* @ingroup Maintenance
*/
+use MediaWiki\MediaWikiServices;
+
require_once __DIR__ . '/Maintenance.php';
/**
$outText = InstallDocFormatter::format( $inText );
if ( $this->hasOption( 'html' ) ) {
- global $wgParser;
+ $parser = MediaWikiServices::getInstance()->getParser();
$opt = new ParserOptions;
$title = Title::newFromText( 'Text file' );
- $out = $wgParser->parse( $outText, $title, $opt );
+ $out = $parser->parse( $outText, $title, $opt );
$outText = "<html><body>\n" . $out->getText() . "\n</body></html>\n";
}
* @ingroup Maintenance
*/
+use MediaWiki\MediaWikiServices;
+
require_once __DIR__ . '/dumpIterator.php';
/**
public $mPPNodeCount = 0;
public function getStripList() {
- global $wgParser;
+ $parser = MediaWikiServices::getInstance()->getParser();
- return $wgParser->getStripList();
+ return $parser->getStripList();
}
public function __construct() {
wfInstallerMain();
function wfInstallerMain() {
- global $wgRequest, $wgLang, $wgMetaNamespace, $wgCanonicalNamespaceNames;
+ global $wgLang, $wgMetaNamespace, $wgCanonicalNamespaceNames;
+ $request = RequestContext::getMain()->getRequest();
- $installer = InstallerOverrides::getWebInstaller( $wgRequest );
+ $installer = InstallerOverrides::getWebInstaller( $request );
if ( !$installer->startSession() ) {
if ( $installer->request->getVal( "css" ) ) {
$session = array();
}
- if ( !is_null( $wgRequest->getVal( 'uselang' ) ) ) {
- $langCode = $wgRequest->getVal( 'uselang' );
+ if ( !is_null( $request->getVal( 'uselang' ) ) ) {
+ $langCode = $request->getVal( 'uselang' );
} elseif ( isset( $session['settings']['_UserLang'] ) ) {
$langCode = $session['settings']['_UserLang'];
} else {
'styles' => 'resources/src/mediawiki.checkboxtoggle.styles.css',
],
'mediawiki.cookie' => [
- 'scripts' => 'resources/src/mediawiki.cookie.js',
+ 'scripts' => 'resources/src/mediawiki.cookie/index.js',
'dependencies' => 'jquery.cookie',
'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.widgets.NamespacesMultiselectWidget' => [
'scripts' => [
'resources/src/mediawiki.widgets/mw.widgets.NamespacesMultiselectWidget.js',
+ 'resources/src/mediawiki.widgets/mw.widgets.NamespacesMenuOptionWidget.js',
],
'dependencies' => [
'oojs-ui-widgets',
+++ /dev/null
-( function () {
- 'use strict';
-
- /**
- * Provides an API for getting and setting cookies that is
- * syntactically and functionally similar to the server-side cookie
- * API (`WebRequest#getCookie` and `WebResponse#setcookie`).
- *
- * @author Sam Smith <samsmith@wikimedia.org>
- * @author Matthew Flaschen <mflaschen@wikimedia.org>
- * @author Timo Tijhof <krinklemail@gmail.com>
- *
- * @class mw.cookie
- * @singleton
- */
- mw.cookie = {
-
- /**
- * Set or delete a cookie.
- *
- * While this is natural in JavaScript, contrary to `WebResponse#setcookie` in PHP, the
- * default values for the `options` properties only apply if that property isn't set
- * already in your options object (e.g. passing `{ secure: null }` or `{ secure: undefined }`
- * overrides the default value for `options.secure`).
- *
- * @param {string} key
- * @param {string|null} value Value of cookie. If `value` is `null` then this method will
- * instead remove a cookie by name of `key`.
- * @param {Object|Date|number} [options] Options object, or expiry date
- * @param {Date|number|null} [options.expires] The expiry date of the cookie, or lifetime in seconds.
- *
- * If `options.expires` is null, then a session cookie is set.
- *
- * By default cookie expiration is based on `wgCookieExpiration`. Similar to `WebResponse`
- * in PHP, we set a session cookie if `wgCookieExpiration` is 0. And for non-zero values
- * it is interpreted as lifetime in seconds.
- *
- * @param {string} [options.prefix=wgCookiePrefix] The prefix of the key
- * @param {string} [options.domain=wgCookieDomain] The domain attribute of the cookie
- * @param {string} [options.path=wgCookiePath] The path attribute of the cookie
- * @param {boolean} [options.secure=false] Whether or not to include the secure attribute.
- * (Does **not** use the wgCookieSecure configuration variable)
- */
- set: function ( key, value, options ) {
- var config, defaultOptions, date;
-
- // wgCookieSecure is not used for now, since 'detect' could not work with
- // ResourceLoaderStartUpModule, as module cache is not fragmented by protocol.
- config = mw.config.get( [
- 'wgCookiePrefix',
- 'wgCookieDomain',
- 'wgCookiePath',
- 'wgCookieExpiration'
- ] );
-
- defaultOptions = {
- prefix: config.wgCookiePrefix,
- domain: config.wgCookieDomain,
- path: config.wgCookiePath,
- secure: false
- };
-
- // Options argument can also be a shortcut for the expiry
- // Expiry can be a Date, number or null
- if ( !options || options instanceof Date || typeof options === 'number' ) {
- // Also takes care of options = undefined, in which case we also don't need $.extend()
- defaultOptions.expires = options;
- options = defaultOptions;
- } else {
- options = $.extend( defaultOptions, options );
- }
-
- // Default to using wgCookieExpiration (lifetime in seconds).
- // If wgCookieExpiration is 0, that is considered a special value indicating
- // all cookies should be session cookies by default.
- if ( options.expires === undefined && config.wgCookieExpiration !== 0 ) {
- date = new Date();
- date.setTime( Number( date ) + ( config.wgCookieExpiration * 1000 ) );
- options.expires = date;
- } else if ( typeof options.expires === 'number' ) {
- // Lifetime in seconds
- date = new Date();
- date.setTime( Number( date ) + ( options.expires * 1000 ) );
- options.expires = date;
- } else if ( options.expires === null ) {
- // $.cookie makes a session cookie when options.expires is omitted
- delete options.expires;
- }
-
- // Process prefix
- key = options.prefix + key;
- delete options.prefix;
-
- // Process value
- if ( value !== null ) {
- value = String( value );
- }
-
- // Other options are handled by $.cookie
- $.cookie( key, value, options );
- },
-
- /**
- * Get the value of a cookie.
- *
- * @param {string} key
- * @param {string} [prefix=wgCookiePrefix] The prefix of the key. If `prefix` is
- * `undefined` or `null`, then `wgCookiePrefix` is used
- * @param {Mixed} [defaultValue=null]
- * @return {string|null|Mixed} If the cookie exists, then the value of the
- * cookie, otherwise `defaultValue`
- */
- get: function ( key, prefix, defaultValue ) {
- var result;
-
- if ( prefix === undefined || prefix === null ) {
- prefix = mw.config.get( 'wgCookiePrefix' );
- }
-
- // Was defaultValue omitted?
- if ( arguments.length < 3 ) {
- defaultValue = null;
- }
-
- result = $.cookie( prefix + key );
-
- return result !== null ? result : defaultValue;
- }
- };
-
-}() );
--- /dev/null
+( function () {
+ 'use strict';
+
+ /**
+ * Provides an API for getting and setting cookies that is
+ * syntactically and functionally similar to the server-side cookie
+ * API (`WebRequest#getCookie` and `WebResponse#setcookie`).
+ *
+ * @author Sam Smith <samsmith@wikimedia.org>
+ * @author Matthew Flaschen <mflaschen@wikimedia.org>
+ * @author Timo Tijhof <krinklemail@gmail.com>
+ *
+ * @class mw.cookie
+ * @singleton
+ */
+ mw.cookie = {
+
+ /**
+ * Set or delete a cookie.
+ *
+ * While this is natural in JavaScript, contrary to `WebResponse#setcookie` in PHP, the
+ * default values for the `options` properties only apply if that property isn't set
+ * already in your options object (e.g. passing `{ secure: null }` or `{ secure: undefined }`
+ * overrides the default value for `options.secure`).
+ *
+ * @param {string} key
+ * @param {string|null} value Value of cookie. If `value` is `null` then this method will
+ * instead remove a cookie by name of `key`.
+ * @param {Object|Date|number} [options] Options object, or expiry date
+ * @param {Date|number|null} [options.expires] The expiry date of the cookie, or lifetime in seconds.
+ *
+ * If `options.expires` is null, then a session cookie is set.
+ *
+ * By default cookie expiration is based on `wgCookieExpiration`. Similar to `WebResponse`
+ * in PHP, we set a session cookie if `wgCookieExpiration` is 0. And for non-zero values
+ * it is interpreted as lifetime in seconds.
+ *
+ * @param {string} [options.prefix=wgCookiePrefix] The prefix of the key
+ * @param {string} [options.domain=wgCookieDomain] The domain attribute of the cookie
+ * @param {string} [options.path=wgCookiePath] The path attribute of the cookie
+ * @param {boolean} [options.secure=false] Whether or not to include the secure attribute.
+ * (Does **not** use the wgCookieSecure configuration variable)
+ */
+ set: function ( key, value, options ) {
+ var config, defaultOptions, date;
+
+ // wgCookieSecure is not used for now, since 'detect' could not work with
+ // ResourceLoaderStartUpModule, as module cache is not fragmented by protocol.
+ config = mw.config.get( [
+ 'wgCookiePrefix',
+ 'wgCookieDomain',
+ 'wgCookiePath',
+ 'wgCookieExpiration'
+ ] );
+
+ defaultOptions = {
+ prefix: config.wgCookiePrefix,
+ domain: config.wgCookieDomain,
+ path: config.wgCookiePath,
+ secure: false
+ };
+
+ // Options argument can also be a shortcut for the expiry
+ // Expiry can be a Date, number or null
+ if ( !options || options instanceof Date || typeof options === 'number' ) {
+ // Also takes care of options = undefined, in which case we also don't need $.extend()
+ defaultOptions.expires = options;
+ options = defaultOptions;
+ } else {
+ options = $.extend( defaultOptions, options );
+ }
+
+ // Default to using wgCookieExpiration (lifetime in seconds).
+ // If wgCookieExpiration is 0, that is considered a special value indicating
+ // all cookies should be session cookies by default.
+ if ( options.expires === undefined && config.wgCookieExpiration !== 0 ) {
+ date = new Date();
+ date.setTime( Number( date ) + ( config.wgCookieExpiration * 1000 ) );
+ options.expires = date;
+ } else if ( typeof options.expires === 'number' ) {
+ // Lifetime in seconds
+ date = new Date();
+ date.setTime( Number( date ) + ( options.expires * 1000 ) );
+ options.expires = date;
+ } else if ( options.expires === null ) {
+ // $.cookie makes a session cookie when options.expires is omitted
+ delete options.expires;
+ }
+
+ // Process prefix
+ key = options.prefix + key;
+ delete options.prefix;
+
+ // Process value
+ if ( value !== null ) {
+ value = String( value );
+ }
+
+ // Other options are handled by $.cookie
+ $.cookie( key, value, options );
+ },
+
+ /**
+ * Get the value of a cookie.
+ *
+ * @param {string} key
+ * @param {string} [prefix=wgCookiePrefix] The prefix of the key. If `prefix` is
+ * `undefined` or `null`, then `wgCookiePrefix` is used
+ * @param {Mixed} [defaultValue=null]
+ * @return {string|null|Mixed} If the cookie exists, then the value of the
+ * cookie, otherwise `defaultValue`
+ */
+ get: function ( key, prefix, defaultValue ) {
+ var result;
+
+ if ( prefix === undefined || prefix === null ) {
+ prefix = mw.config.get( 'wgCookiePrefix' );
+ }
+
+ // Was defaultValue omitted?
+ if ( arguments.length < 3 ) {
+ defaultValue = null;
+ }
+
+ result = $.cookie( prefix + key );
+
+ return result !== null ? result : defaultValue;
+ }
+ };
+
+}() );
}
ul {
- list-style-type: square;
margin: 0.3em 0 0 1.6em;
padding: 0;
}
--- /dev/null
+/*!
+ * MediaWiki Widgets - NamespacesMenuOptionWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function () {
+
+ /**
+ * Creates an mw.widgets.NamespacesMenuOptionWidget object
+ *
+ * This MenuOptionWidget widget returns an item match text that includes
+ * both the label and the data, so the menu can filter on either.
+ *
+ * @class
+ * @extends OO.ui.MenuOptionWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+ mw.widgets.NamespacesMenuOptionWidget = function MwWidgetsNamespacesMenuOptionWidget( config ) {
+ // Parent
+ mw.widgets.NamespacesMenuOptionWidget.parent.call( this, config );
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.NamespacesMenuOptionWidget, OO.ui.MenuOptionWidget );
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.NamespacesMenuOptionWidget.prototype.getMatchText = function () {
+ return this.getData() + ' ' + this.getLabel();
+ };
+
+}() );
{
clearInputOnChoose: true,
inputPosition: 'inline',
- allowEditTags: false
+ allowEditTags: false,
+ menu: {
+ filterMode: 'substring'
+ }
},
config,
{
OO.inheritClass( mw.widgets.NamespacesMultiselectWidget, OO.ui.MenuTagMultiselectWidget );
OO.mixinClass( mw.widgets.NamespacesMultiselectWidget, OO.ui.mixin.PendingElement );
+ /* Methods */
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.NamespacesMultiselectWidget.prototype.createMenuOptionWidget = function ( data, label, icon ) {
+ return new mw.widgets.NamespacesMenuOptionWidget( {
+ data: data,
+ label: label || data,
+ icon: icon
+ } );
+ };
+
}() );
$setup['wgHtml5'] = true;
$setup['wgDisableLangConversion'] = false;
$setup['wgDisableTitleConversion'] = false;
- $setup['wgMediaInTargetLanguage'] = false;
// "extra language links"
// see https://gerrit.wikimedia.org/r/111390
+ [ 'ISBN' => true, 'PMID' => true, 'RFC' => true ],
// Test with legacy encoding by default until HTML5 is very stable and default
'wgFragmentMode' => [ 'legacy' ],
- 'wgMediaInTargetLanguage' => self::getOptionValue( 'wgMediaInTargetLanguage', $opts, false ),
];
$nonIncludable = self::getOptionValue( 'wgNonincludableNamespaces', $opts, false );
# You can also set the following parser properties via test options:
# wgEnableUploads, wgAllowExternalImages, wgMaxTocLevel,
# wgLinkHolderBatchSize, wgRawHtml, wgInterwikiMagic,
-# wgEnableMagicLinks, wgMediaInTargetLanguage
+# wgEnableMagicLinks
#
# For testing purposes, temporary articles can created:
# !!article / NAMESPACE:TITLE / !!text / ARTICLE TEXT / !!endarticle
SVG thumbnails in page language
!! options
language=ru
-wgMediaInTargetLanguage = true
!! wikitext
[[File:Foobar.svg]] [[File:Foobar.svg|lang=en]]
!! html/php
SVG thumbnails in page language not present in the file
!! options
language=de
-wgMediaInTargetLanguage = true
!! wikitext
[[File:Foobar.svg]] [[File:Foobar.svg|lang=ru]]
!! html/php
"PhanParamTooMany",
// approximate error count: 3
"PhanParamTooManyInternal",
- // approximate error count: 1
- "PhanRedefineFunctionInternal",
// approximate error count: 2
"PhanTraitParentReference",
// approximate error count: 3
$options = [ 'lang' => $options ];
}
$options += [
+ 'debug' => 'true',
'lang' => 'en',
'dir' => 'ltr',
'skin' => 'vector',
];
$resourceLoader = $rl ?: new ResourceLoader();
$request = new FauxRequest( [
+ 'debug' => $options['debug'],
'lang' => $options['lang'],
'modules' => $options['modules'],
'only' => $options['only'],
[
[ 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS ],
"<script nonce=\"secret\">(window.RLQ=window.RLQ||[]).push(function(){"
- . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.foo\u0026only=scripts\u0026skin=fallback");'
+ . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?lang=en\u0026modules=test.foo\u0026only=scripts\u0026skin=fallback");'
. "});</script>"
],
// Multiple only=styles load
[
[ [ 'test.baz', 'test.foo', 'test.bar' ], ResourceLoaderModule::TYPE_STYLES ],
- '<link rel="stylesheet" href="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.bar%2Cbaz%2Cfoo&only=styles&skin=fallback"/>'
+ '<link rel="stylesheet" href="http://127.0.0.1:8080/w/load.php?lang=en&modules=test.bar%2Cbaz%2Cfoo&only=styles&skin=fallback"/>'
],
// Private embed (only=scripts)
[
// noscript group
[
[ 'test.noscript', ResourceLoaderModule::TYPE_STYLES ],
- '<noscript><link rel="stylesheet" href="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.noscript&only=styles&skin=fallback"/></noscript>'
+ '<noscript><link rel="stylesheet" href="http://127.0.0.1:8080/w/load.php?lang=en&modules=test.noscript&only=styles&skin=fallback"/></noscript>'
],
// Load two modules in separate groups
[
[ [ 'test.group.foo', 'test.group.bar' ], ResourceLoaderModule::TYPE_COMBINED ],
"<script nonce=\"secret\">(window.RLQ=window.RLQ||[]).push(function(){"
- . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.bar\u0026skin=fallback");'
- . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.foo\u0026skin=fallback");'
+ . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?lang=en\u0026modules=test.group.bar\u0026skin=fallback");'
+ . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?lang=en\u0026modules=test.group.foo\u0026skin=fallback");'
. "});</script>"
],
];
'default logged-out' => [
'exemptStyleModules' => [ 'site' => [ 'site.styles' ] ],
'<meta name="ResourceLoaderDynamicStyles" content=""/>' . "\n" .
- '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=site.styles&only=styles&skin=fallback"/>',
+ '<link rel="stylesheet" href="/w/load.php?lang=en&modules=site.styles&only=styles&skin=fallback"/>',
],
'default logged-in' => [
'exemptStyleModules' => [ 'site' => [ 'site.styles' ], 'user' => [ 'user.styles' ] ],
'<meta name="ResourceLoaderDynamicStyles" content=""/>' . "\n" .
- '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=site.styles&only=styles&skin=fallback"/>' . "\n" .
- '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=user.styles&only=styles&skin=fallback&version=1ai9g6t"/>',
+ '<link rel="stylesheet" href="/w/load.php?lang=en&modules=site.styles&only=styles&skin=fallback"/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?lang=en&modules=user.styles&only=styles&skin=fallback&version=1ai9g6t"/>',
],
'custom modules' => [
'exemptStyleModules' => [
'user' => [ 'user.styles', 'example.user' ],
],
'<meta name="ResourceLoaderDynamicStyles" content=""/>' . "\n" .
- '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=example.site.a%2Cb&only=styles&skin=fallback"/>' . "\n" .
- '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=site.styles&only=styles&skin=fallback"/>' . "\n" .
- '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=example.user&only=styles&skin=fallback&version=0a56zyi"/>' . "\n" .
- '<link rel="stylesheet" href="/w/load.php?debug=false&lang=en&modules=user.styles&only=styles&skin=fallback&version=1ai9g6t"/>',
+ '<link rel="stylesheet" href="/w/load.php?lang=en&modules=example.site.a%2Cb&only=styles&skin=fallback"/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?lang=en&modules=site.styles&only=styles&skin=fallback"/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?lang=en&modules=example.user&only=styles&skin=fallback&version=0a56zyi"/>' . "\n" .
+ '<link rel="stylesheet" href="/w/load.php?lang=en&modules=user.styles&only=styles&skin=fallback&version=1ai9g6t"/>',
],
];
// phpcs:enable
*/
public function testGetXMLMetadata( $infile, $expected ) {
$r = new XMLReader();
- if ( !method_exists( $r, 'readInnerXML' ) ) {
- $this->markTestSkipped( 'XMLReader::readInnerXML() does not exist (libxml >2.6.20 needed).' );
-
- return;
- }
$this->assertMetadata( $infile, $expected );
}
'ResourceModuleSkinStyles' => [],
'ResourceModules' => [],
'EnableJavaScriptTest' => false,
- 'ResourceLoaderDebug' => false,
'LoadScript' => '/w/load.php',
] );
return new ResourceLoaderContext(
. 'mw.loader.implement("test.private@{blankVer}",null,{"css":[]});'
. 'RLPAGEMODULES=["test"];mw.loader.load(RLPAGEMODULES);'
. '});</script>' . "\n"
- . '<link rel="stylesheet" href="/w/load.php?debug=false&lang=nl&modules=test.styles.deprecated%2Cpure&only=styles&skin=fallback"/>' . "\n"
+ . '<link rel="stylesheet" href="/w/load.php?lang=nl&modules=test.styles.deprecated%2Cpure&only=styles&skin=fallback"/>' . "\n"
. '<style>.private{}</style>' . "\n"
- . '<script async="" src="/w/load.php?debug=false&lang=nl&modules=startup&only=scripts&skin=fallback"></script>';
+ . '<script async="" src="/w/load.php?lang=nl&modules=startup&only=scripts&skin=fallback"></script>';
// phpcs:enable
$expected = self::expandVariables( $expected );
// phpcs:disable Generic.Files.LineLength
$expected = '<script>document.documentElement.className = document.documentElement.className.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>' . "\n"
- . '<script async="" src="/w/load.php?debug=false&lang=nl&modules=startup&only=scripts&skin=fallback&target=example"></script>';
+ . '<script async="" src="/w/load.php?lang=nl&modules=startup&only=scripts&skin=fallback&target=example"></script>';
// phpcs:enable
$this->assertEquals( $expected, $client->getHeadHtml() );
// phpcs:disable Generic.Files.LineLength
$expected = '<script>document.documentElement.className = document.documentElement.className.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>' . "\n"
- . '<script async="" src="/w/load.php?debug=false&lang=nl&modules=startup&only=scripts&safemode=1&skin=fallback"></script>';
+ . '<script async="" src="/w/load.php?lang=nl&modules=startup&only=scripts&safemode=1&skin=fallback"></script>';
// phpcs:enable
$this->assertEquals( $expected, $client->getHeadHtml() );
// phpcs:disable Generic.Files.LineLength
$expected = '<script>document.documentElement.className = document.documentElement.className.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>' . "\n"
- . '<script async="" src="/w/load.php?debug=false&lang=nl&modules=startup&only=scripts&skin=fallback"></script>';
+ . '<script async="" src="/w/load.php?lang=nl&modules=startup&only=scripts&skin=fallback"></script>';
// phpcs:enable
$this->assertEquals( $expected, $client->getHeadHtml() );
'context' => [],
'modules' => [ 'test.unknown' ],
'only' => ResourceLoaderModule::TYPE_STYLES,
+ 'extra' => [],
'output' => '',
],
[
'context' => [],
'modules' => [ 'test.styles.private' ],
'only' => ResourceLoaderModule::TYPE_STYLES,
+ 'extra' => [],
'output' => '<style>.private{}</style>',
],
[
'context' => [],
'modules' => [ 'test.private' ],
'only' => ResourceLoaderModule::TYPE_COMBINED,
+ 'extra' => [],
'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.implement("test.private@{blankVer}",null,{"css":[]});});</script>',
],
[
// Eg. startup module
'modules' => [ 'test.scripts.raw' ],
'only' => ResourceLoaderModule::TYPE_SCRIPTS,
- 'output' => '<script async="" src="/w/load.php?debug=false&lang=nl&modules=test.scripts.raw&only=scripts&skin=fallback"></script>',
+ 'extra' => [],
+ 'output' => '<script async="" src="/w/load.php?lang=nl&modules=test.scripts.raw&only=scripts&skin=fallback"></script>',
],
[
- 'context' => [ 'sync' => true ],
+ 'context' => [],
'modules' => [ 'test.scripts.raw' ],
'only' => ResourceLoaderModule::TYPE_SCRIPTS,
- 'output' => '<script src="/w/load.php?debug=false&lang=nl&modules=test.scripts.raw&only=scripts&skin=fallback&sync=1"></script>',
+ 'extra' => [ 'sync' => '1' ],
+ 'output' => '<script src="/w/load.php?lang=nl&modules=test.scripts.raw&only=scripts&skin=fallback&sync=1"></script>',
],
[
'context' => [],
'modules' => [ 'test.scripts.user' ],
'only' => ResourceLoaderModule::TYPE_SCRIPTS,
- 'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?debug=false\u0026lang=nl\u0026modules=test.scripts.user\u0026only=scripts\u0026skin=fallback\u0026user=Example\u0026version=0a56zyi");});</script>',
+ 'extra' => [],
+ 'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test.scripts.user\u0026only=scripts\u0026skin=fallback\u0026user=Example\u0026version=0a56zyi");});</script>',
],
[
'context' => [],
'modules' => [ 'test.user' ],
'only' => ResourceLoaderModule::TYPE_COMBINED,
- 'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?debug=false\u0026lang=nl\u0026modules=test.user\u0026skin=fallback\u0026user=Example\u0026version=0a56zyi");});</script>',
+ 'extra' => [],
+ 'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test.user\u0026skin=fallback\u0026user=Example\u0026version=0a56zyi");});</script>',
],
[
- 'context' => [ 'debug' => true ],
+ 'context' => [ 'debug' => 'true' ],
'modules' => [ 'test.styles.pure', 'test.styles.mixed' ],
'only' => ResourceLoaderModule::TYPE_STYLES,
+ 'extra' => [],
'output' => '<link rel="stylesheet" href="/w/load.php?debug=true&lang=nl&modules=test.styles.mixed&only=styles&skin=fallback"/>' . "\n"
. '<link rel="stylesheet" href="/w/load.php?debug=true&lang=nl&modules=test.styles.pure&only=styles&skin=fallback"/>',
],
[
- 'context' => [ 'debug' => false ],
+ 'context' => [ 'debug' => 'false' ],
'modules' => [ 'test.styles.pure', 'test.styles.mixed' ],
'only' => ResourceLoaderModule::TYPE_STYLES,
- 'output' => '<link rel="stylesheet" href="/w/load.php?debug=false&lang=nl&modules=test.styles.mixed%2Cpure&only=styles&skin=fallback"/>',
+ 'extra' => [],
+ 'output' => '<link rel="stylesheet" href="/w/load.php?lang=nl&modules=test.styles.mixed%2Cpure&only=styles&skin=fallback"/>',
],
[
'context' => [],
'modules' => [ 'test.styles.noscript' ],
'only' => ResourceLoaderModule::TYPE_STYLES,
- 'output' => '<noscript><link rel="stylesheet" href="/w/load.php?debug=false&lang=nl&modules=test.styles.noscript&only=styles&skin=fallback"/></noscript>',
+ 'extra' => [],
+ 'output' => '<noscript><link rel="stylesheet" href="/w/load.php?lang=nl&modules=test.styles.noscript&only=styles&skin=fallback"/></noscript>',
],
[
'context' => [],
'modules' => [ 'test.shouldembed' ],
'only' => ResourceLoaderModule::TYPE_COMBINED,
+ 'extra' => [],
'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.implement("test.shouldembed@09p30q0",null,{"css":[]});});</script>',
],
[
'context' => [],
'modules' => [ 'test.styles.shouldembed' ],
'only' => ResourceLoaderModule::TYPE_STYLES,
+ 'extra' => [],
'output' => '<style>.shouldembed{}</style>',
],
[
'context' => [],
'modules' => [ 'test.scripts.shouldembed' ],
'only' => ResourceLoaderModule::TYPE_SCRIPTS,
+ 'extra' => [],
'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.state({"test.scripts.shouldembed":"ready"});});</script>',
],
[
'context' => [],
'modules' => [ 'test', 'test.shouldembed' ],
'only' => ResourceLoaderModule::TYPE_COMBINED,
- 'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?debug=false\u0026lang=nl\u0026modules=test\u0026skin=fallback");mw.loader.implement("test.shouldembed@09p30q0",null,{"css":[]});});</script>',
+ 'extra' => [],
+ 'output' => '<script>(window.RLQ=window.RLQ||[]).push(function(){mw.loader.load("/w/load.php?lang=nl\u0026modules=test\u0026skin=fallback");mw.loader.implement("test.shouldembed@09p30q0",null,{"css":[]});});</script>',
],
[
'context' => [],
'modules' => [ 'test.styles.pure', 'test.styles.shouldembed' ],
'only' => ResourceLoaderModule::TYPE_STYLES,
+ 'extra' => [],
'output' =>
- '<link rel="stylesheet" href="/w/load.php?debug=false&lang=nl&modules=test.styles.pure&only=styles&skin=fallback"/>' . "\n"
+ '<link rel="stylesheet" href="/w/load.php?lang=nl&modules=test.styles.pure&only=styles&skin=fallback"/>' . "\n"
. '<style>.shouldembed{}</style>'
],
[
'context' => [],
'modules' => [ 'test.ordering.a', 'test.ordering.e', 'test.ordering.b', 'test.ordering.d', 'test.ordering.c' ],
'only' => ResourceLoaderModule::TYPE_STYLES,
+ 'extra' => [],
'output' =>
- '<link rel="stylesheet" href="/w/load.php?debug=false&lang=nl&modules=test.ordering.a%2Cb&only=styles&skin=fallback"/>' . "\n"
+ '<link rel="stylesheet" href="/w/load.php?lang=nl&modules=test.ordering.a%2Cb&only=styles&skin=fallback"/>' . "\n"
. '<style>.orderingC{}.orderingD{}</style>' . "\n"
- . '<link rel="stylesheet" href="/w/load.php?debug=false&lang=nl&modules=test.ordering.e&only=styles&skin=fallback"/>'
+ . '<link rel="stylesheet" href="/w/load.php?lang=nl&modules=test.ordering.e&only=styles&skin=fallback"/>'
],
];
// phpcs:enable
* @covers ResourceLoader::makeLoaderQuery
* @covers ResourceLoader::makeInlineScript
*/
- public function testMakeLoad( array $extraQuery, array $modules, $type, $expected ) {
- $context = self::makeContext( $extraQuery );
+ public function testMakeLoad(
+ array $contextQuery,
+ array $modules,
+ $type,
+ array $extraQuery,
+ $expected
+ ) {
+ $context = self::makeContext( $contextQuery );
$context->getResourceLoader()->register( self::makeSampleModules() );
$actual = ResourceLoaderClientHtml::makeLoad( $context, $modules, $type, $extraQuery, false );
$expected = self::expandVariables( $expected );
}, $scripts );
$rl->register( $modules );
- $this->setMwGlobals( 'wgResourceLoaderDebug', $debug );
$context = $this->getResourceLoaderContext(
[
'modules' => implode( '|', array_keys( $modules ) ),
'only' => 'scripts',
+ 'debug' => $debug ? 'true' : 'false',
],
$rl
);