* The deprecated IPSet\IPSet alias was removed, Wikimedia\IPSet must be
used instead.
* Updated qunitjs from 2.6.2 to 2.9.1.
+* Updated jquery-client from 2.0.1 to 2.0.2.
==== Removed external libraries ====
* Class SquidUpdate, deprecated in 1.27, was removed.
* Title->getSquidURLs(), deprecated in 1.27, was removed. Instead, use
Title->getCdnUrls().
+* Title::escapeFragmentForURL(), deprecated in 1.30, was removed. Use
+ Sanitizer::escapeIdForLink() or escapeIdForExternalInterwiki() instead.
+* Title->canTalk(), deprecated in 1.30, was removed. Instead, use
+ Title->canHaveTalkPage().
+* Title's methods for site and user page related to CSS and JS, deprecated in
+ 1.31, were removed:
+ * Title->isCssOrJsPage() — Use Title->isSiteConfigPage()
+ * Title->isCssJsSubpage() – Use Title->isUserConfigPage()
+ * Title->getSkinFromCssJsSubpage() – Use Title->getSkinFromConfigSubpage()
+ * Title->isCssSubpage() – Use Title->isUserCssConfigPage()
+ * Title->isJsSubpage() – Use Title->isUserJsConfigPage()
+* SiteSQLStore, deprecated in 1.27 and whose only method, ::newInstance(),
+ would return the global SiteStore instance, has been removed. You can get to
+ this via MediaWiki\MediaWikiServices::getInstance()->getSiteStore() directly.
+* Linker::formatSize, deprecated in 1.28, has been removed (with DummyLinker's).
+ Instead, use Language->formatSize() with the relevant Language object.
+* Linker::formatTemplates, deprecated in 1.28, has been removed (along with the
+ version in DummyLinker). You can use TemplatesOnThisPageFormatter directly.
+* EventRelayerGroup::singleton(), deprecated in 1.27, has been removed. You can
+ use MediaWikiServices::getInstance()->getEventRelayerGroup() directly.
+* LinkCache->addLink(), deprecated in 1.27, has been removed. It is thought to
+ be unused, and is distinct from OutputPage->addLink(), which remains.
+* JsonContent->getJsonData(), deprecated in 1.25, has been removed. Instead, use
+ JsonContent->getData().
+* MWExceptionHandler::getLogId(), deprecated in 1.27, has been removed, as the
+ exception ID is the same as the request ID, from WebRequest::getRequestId().
+* SearchEngine::getNearMatchResultSet(), deprecated in 1.27, has been removed.
+ You can use SearchEngine::getNearMatcher() instead.
+* EmailNotification::updateWatchlistTimestamp, deprecated in 1.27, has been
+ removed. Instead, use WatchedItemStore::updateNotificationTimestamp directly.
+* User::getGroupName() and ::getGroupMember(), both deprecated in 1.29, have
+ been removed. Instead, please use UserGroupMembership::getGroupName() and
+ UserGroupMembership::getGroupMemberName().
+* Backwards compatibility for setting wgSessionsInObjectCache to false or using
+ wgSessionHandler, both of which were deprecated in 1.27 with the introduction
+ of SessionManager, has been removed.
+* SessionManager::autoCreateUser, deprecated in 1.27, has been removed. Use
+ MediaWiki\Auth\AuthManager::autoCreateUser instead.
+* The mw.libs.jpegmeta property, deprecated in 1.31, was removed.
+ Use require( 'mediawiki.libs.jpegmeta' ) instead.
+* The mw.user.stickyRandomId() method, deprecated in 1.32, was removed.
+ Use mw.user.getPageviewToken() instead.
=== Deprecations in 1.33 ===
* The configuration option $wgUseESI has been deprecated, and is expected
use the new extension registration key 'QUnitTestModule'.
* (T213426) The jquery.throttle-debounce module has been deprecated. JavaScript
code that needs this behaviour should use OO.ui.debounce/throttle.
+* The mw.language.specialCharacters property from the
+ 'mediawiki.language.specialCharacters' module has been deprecated.
+ Use require( 'mediawiki.language.specialCharacters' ) instead.
=== Other changes in 1.33 ===
-* (T208871) The hard-coded Google search form on the database error page was
- removed.
* (T201747) Html::openElement() warns if given an element name with a space
in it.
'SiteImporter' => __DIR__ . '/includes/site/SiteImporter.php',
'SiteList' => __DIR__ . '/includes/site/SiteList.php',
'SiteLookup' => __DIR__ . '/includes/site/SiteLookup.php',
- 'SiteSQLStore' => __DIR__ . '/includes/site/SiteSQLStore.php',
'SiteStats' => __DIR__ . '/includes/SiteStats.php',
'SiteStatsInit' => __DIR__ . '/includes/SiteStatsInit.php',
'SiteStatsUpdate' => __DIR__ . '/includes/deferred/SiteStatsUpdate.php',
*/
$wgParserCacheExpireTime = 86400;
-/**
- * @deprecated since 1.27, session data is always stored in object cache.
- */
-$wgSessionsInObjectCache = true;
-
/**
* The expiry time to use for session storage, in seconds.
*/
$wgObjectCacheSessionExpiry = 3600;
-/**
- * @deprecated since 1.27, MediaWiki\Session\SessionManager doesn't use PHP session storage.
- */
-$wgSessionHandler = null;
-
/**
* Whether to use PHP session handling ($_SESSION and session_*() functions)
*
);
}
- /**
- * @deprecated since 1.28, use TemplatesOnThisPageFormatter directly
- */
- public function formatTemplates(
- $templates,
- $preview = false,
- $section = false,
- $more = null
- ) {
- wfDeprecated( __METHOD__, '1.28' );
-
- return Linker::formatTemplates(
- $templates,
- $preview,
- $section,
- $more
- );
- }
-
public function formatHiddenCategories( $hiddencats ) {
return Linker::formatHiddenCategories( $hiddencats );
}
- /**
- * @deprecated since 1.28, use Language::formatSize() directly
- */
- public function formatSize( $size ) {
- wfDeprecated( __METHOD__, '1.28' );
-
- return Linker::formatSize( $size );
- }
-
public function titleAttrib( $name, $options = null, array $msgParams = [] ) {
return Linker::titleAttrib(
$name,
* @file
*/
-use MediaWiki\MediaWikiServices;
-
/**
* Factory class for spawning EventRelayer objects using configuration
*
$this->configByChannel = $config;
}
- /**
- * @deprecated since 1.27 Use MediaWikiServices::getInstance()->getEventRelayerGroup()
- * @return EventRelayerGroup
- */
- public static function singleton() {
- wfDeprecated( __METHOD__, '1.27' );
- return MediaWikiServices::getInstance()->getEventRelayerGroup();
- }
-
/**
* @param string $channel
* @return EventRelayer Relayer instance that handles the given channel
}
}
- /**
- * @deprecated since 1.28, use TemplatesOnThisPageFormatter directly
- *
- * Returns HTML for the "templates used on this page" list.
- *
- * Make an HTML list of templates, and then add a "More..." link at
- * the bottom. If $more is null, do not add a "More..." link. If $more
- * is a Title, make a link to that title and use it. If $more is a string,
- * directly paste it in as the link (escaping needs to be done manually).
- * Finally, if $more is a Message, call toString().
- *
- * @since 1.16.3. $more added in 1.21
- * @param Title[] $templates Array of templates
- * @param bool $preview Whether this is for a preview
- * @param bool $section Whether this is for a section edit
- * @param Title|Message|string|null $more An escaped link for "More..." of the templates
- * @return string HTML output
- */
- public static function formatTemplates( $templates, $preview = false,
- $section = false, $more = null
- ) {
- wfDeprecated( __METHOD__, '1.28' );
-
- $type = false;
- if ( $preview ) {
- $type = 'preview';
- } elseif ( $section ) {
- $type = 'section';
- }
-
- if ( $more instanceof Message ) {
- $more = $more->toString();
- }
-
- $formatter = new TemplatesOnThisPageFormatter(
- RequestContext::getMain(),
- MediaWikiServices::getInstance()->getLinkRenderer()
- );
- return $formatter->format( $templates, $type, $more );
- }
-
/**
* Returns HTML for the "hidden categories on this page" list.
*
return $outText;
}
- /**
- * @deprecated since 1.28, use Language::formatSize() directly
- *
- * Format a size in bytes for output, using an appropriate
- * unit (B, KB, MB or GB) according to the magnitude in question
- *
- * @since 1.16.3
- * @param int $size Size to format
- * @return string
- */
- public static function formatSize( $size ) {
- wfDeprecated( __METHOD__, '1.28' );
-
- global $wgLang;
- return htmlspecialchars( $wgLang->formatSize( $size ) );
- }
-
/**
* Given the id of an interface element, constructs the appropriate title
* attribute from the system messages. (Note, this is usually the id but
}
/**
- * This function commits all DB changes as needed before
- * the user can receive a response (in case commit fails)
+ * This function commits all DB and session changes as needed *before* the
+ * client can receive a response (in case DB commit fails) and thus also before
+ * the response can trigger a subsequent related request by the client
+ *
+ * If there is a significant amount of content to flush, it can be done in $postCommitWork
*
* @param IContextSource $context
* @param callable|null $postCommitWork [default: null]
// Run updates that need to block the user or affect output (this is the last chance)
DeferredUpdates::doUpdates( 'enqueue', DeferredUpdates::PRESEND );
wfDebug( __METHOD__ . ': pre-send deferred updates completed' );
+ // T214471: persist the session to avoid race conditions on subsequent requests
+ $request->getSession()->save();
// Should the client return, their request should observe the new ChronologyProtector
// DB positions. This request might be on a foreign wiki domain, so synchronously update
$wgPasswordPolicy['policies']['default']['MaximalPasswordLength'] = $wgMaximalPasswordLength;
}
-// Backwards compatibility warning
-if ( !$wgSessionsInObjectCache ) {
- wfDeprecated( '$wgSessionsInObjectCache = false', '1.27' );
- if ( $wgSessionHandler ) {
- wfDeprecated( '$wgSessionsHandler', '1.27' );
- }
- $cacheType = get_class( ObjectCache::getInstance( $wgSessionCacheType ) );
- wfDebugLog(
- 'caches',
- "Session data will be stored in \"$cacheType\" cache with " .
- "expiry $wgObjectCacheSessionExpiry seconds"
- );
-}
-$wgSessionsInObjectCache = true;
-
if ( $wgPHPSessionHandling !== 'enable' &&
$wgPHPSessionHandling !== 'warn' &&
$wgPHPSessionHandling !== 'disable'
return $name;
}
- /**
- * Escape a text fragment, say from a link, for a URL
- *
- * @deprecated since 1.30, use Sanitizer::escapeIdForLink() or escapeIdForExternalInterwiki()
- *
- * @param string $fragment Containing a URL or link fragment (after the "#")
- * @return string Escaped string
- */
- static function escapeFragmentForURL( $fragment ) {
- wfDeprecated( __METHOD__, '1.30' );
- # Note that we don't urlencode the fragment. urlencoded Unicode
- # fragments appear not to work in IE (at least up to 7) or in at least
- # one version of Opera 9.x. The W3C validator, for one, doesn't seem
- # to care if they aren't encoded.
- return Sanitizer::escapeId( $fragment, 'noninitial' );
- }
-
/**
* Callback for usort() to do title sorts by (namespace, title)
*
getNsText( MWNamespace::getTalk( $this->mNamespace ) );
}
- /**
- * Can this title have a corresponding talk page?
- *
- * @deprecated since 1.30, use canHaveTalkPage() instead.
- *
- * @return bool True if this title either is a talk page or can have a talk page associated.
- */
- public function canTalk() {
- return $this->canHaveTalkPage();
- }
-
/**
* Can this title have a corresponding talk page?
*
);
}
- /**
- * @return bool
- * @deprecated Since 1.31; use ::isSiteConfigPage() instead (which also checks for JSON pages)
- */
- public function isCssOrJsPage() {
- wfDeprecated( __METHOD__, '1.31' );
- return ( NS_MEDIAWIKI == $this->mNamespace
- && ( $this->hasContentModel( CONTENT_MODEL_CSS )
- || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) ) );
- }
-
/**
* Is this a "config" (.css, .json, or .js) sub-page of a user page?
*
);
}
- /**
- * @return bool
- * @deprecated Since 1.31; use ::isUserConfigPage() instead (which also checks for JSON pages)
- */
- public function isCssJsSubpage() {
- wfDeprecated( __METHOD__, '1.31' );
- return ( NS_USER == $this->mNamespace && $this->isSubpage()
- && ( $this->hasContentModel( CONTENT_MODEL_CSS )
- || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) ) );
- }
-
/**
* Trim down a .css, .json, or .js subpage title to get the corresponding skin name
*
return substr( $subpage, 0, $lastdot );
}
- /**
- * @deprecated Since 1.31; use ::getSkinFromConfigSubpage() instead
- * @return string Containing skin name from .css, .json, or .js subpage title
- */
- public function getSkinFromCssJsSubpage() {
- wfDeprecated( __METHOD__, '1.31' );
- return $this->getSkinFromConfigSubpage();
- }
-
/**
* Is this a CSS "config" sub-page of a user page?
*
);
}
- /**
- * @deprecated Since 1.31; use ::isUserCssConfigPage()
- * @return bool
- */
- public function isCssSubpage() {
- wfDeprecated( __METHOD__, '1.31' );
- return $this->isUserCssConfigPage();
- }
-
/**
* Is this a JSON "config" sub-page of a user page?
*
);
}
- /**
- * @deprecated Since 1.31; use ::isUserJsConfigPage()
- * @return bool
- */
- public function isJsSubpage() {
- wfDeprecated( __METHOD__, '1.31' );
- return $this->isUserJsConfigPage();
- }
-
/**
* Is this a sitewide CSS "config" page?
*
$this->goodLinks->clear( $dbkey );
}
- /**
- * Add a title to the link cache, return the page_id or zero if non-existent
- *
- * @deprecated since 1.27, unused
- * @param string $title Prefixed DB key
- * @return int Page ID or zero
- */
- public function addLink( $title ) {
- wfDeprecated( __METHOD__, '1.27' );
- $nt = Title::newFromDBkey( $title );
- if ( !$nt ) {
- return 0;
- }
- return $this->addLinkObj( $nt );
- }
-
/**
* Fields that LinkCache needs to select
*
parent::__construct( $text, $modelId );
}
- /**
- * Decodes the JSON into a PHP associative array.
- *
- * @deprecated since 1.25 Use getData instead.
- * @return array|null
- */
- public function getJsonData() {
- wfDeprecated( __METHOD__, '1.25' );
- return FormatJson::decode( $this->getText(), true );
- }
-
/**
* Decodes the JSON string.
*
}, $trace );
}
- /**
- * Get the ID for this exception.
- *
- * The ID is saved so that one can match the one output to the user (when
- * $wgShowExceptionDetails is set to false), to the entry in the debug log.
- *
- * @since 1.22
- * @deprecated since 1.27: Exception IDs are synonymous with request IDs.
- * @param Exception|Throwable $e
- * @return string
- */
- public static function getLogId( $e ) {
- wfDeprecated( __METHOD__, '1.27' );
- return WebRequest::getRequestId();
- }
-
/**
* If the exception occurred in the course of responding to a request,
* returns the requested URL. Otherwise, returns false.
* @author Luke Welling lwelling@wikimedia.org
*/
-use MediaWiki\Linker\LinkTarget;
use MediaWiki\MediaWikiServices;
/**
return $this->pageStatus;
}
- /**
- * @deprecated since 1.27 use WatchedItemStore::updateNotificationTimestamp directly
- *
- * @param User $editor The editor that triggered the update. Their notification
- * timestamp will not be updated(they have already seen it)
- * @param LinkTarget $linkTarget The link target of the title to update timestamps for
- * @param string $timestamp Set the update timestamp to this value
- *
- * @return int[] Array of user IDs
- */
- public static function updateWatchlistTimestamp(
- User $editor,
- LinkTarget $linkTarget,
- $timestamp
- ) {
- wfDeprecated( __METHOD__, '1.27' );
- $config = RequestContext::getMain()->getConfig();
- if ( !$config->get( 'EnotifWatchlist' ) && !$config->get( 'ShowUpdatedMarker' ) ) {
- return [];
- }
- return MediaWikiServices::getInstance()->getWatchedItemStore()->updateNotificationTimestamp(
- $editor,
- $linkTarget,
- $timestamp
- );
- }
-
/**
* Send emails corresponding to the user $editor editing the page $title.
*
# image
# "Download high res version" link below the image
# $msgsize = $this->getContext()->msg( 'file-info-size', $width_orig, $height_orig,
- # Linker::formatSize( $this->displayImg->getSize() ), $mime )->escaped();
+ # Language::formatSize( $this->displayImg->getSize() ), $mime )->escaped();
# We'll show a thumbnail of this image
if ( $width > $maxWidth || $height > $maxHeight || $this->displayImg->isVectorized() ) {
list( $width, $height ) = $this->getDisplayWidthHeight(
return static::defaultNearMatcher()->getNearMatch( $searchterm );
}
- /**
- * Do a near match (see SearchEngine::getNearMatch) and wrap it into a
- * SearchResultSet.
- * @deprecated since 1.27; Use SearchEngine::getNearMatcher()
- * @param string $searchterm
- * @return SearchResultSet
- */
- public static function getNearMatchResultSet( $searchterm ) {
- wfDeprecated( __METHOD__, '1.27' );
- return static::defaultNearMatcher()->getNearMatchResultSet( $searchterm );
- }
-
/**
* Get chars legal for search
* NOTE: usage as static is deprecated and preserved only as BC measure
* @{
*/
- /**
- * Auto-create the given user, if necessary
- * @private Don't call this yourself. Let Setup.php do it for you at the right time.
- * @deprecated since 1.27, use MediaWiki\Auth\AuthManager::autoCreateUser instead
- * @param User $user User to auto-create
- * @return bool Success
- * @codeCoverageIgnore
- */
- public static function autoCreateUser( User $user ) {
- wfDeprecated( __METHOD__, '1.27' );
- return \MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
- $user,
- \MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
- false
- )->isGood();
- }
-
/**
* Prevent future sessions for the user
*
+++ /dev/null
-<?php
-
-/**
- * Dummy class for accessing the global SiteStore instance.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @since 1.21
- *
- * @file
- * @ingroup Site
- *
- * @license GPL-2.0-or-later
- * @author Daniel Kinzler
- */
-class SiteSQLStore {
-
- /**
- * Returns the global SiteStore instance. This is a relict of the first implementation
- * of SiteStore, and is kept around for compatibility.
- *
- * @note This does not return an instance of SiteSQLStore!
- *
- * @since 1.21
- * @deprecated since 1.27 use MediaWikiServices::getSiteStore()
- * or MediaWikiServices::getSiteLookup() instead.
- *
- * @param null $sitesTable IGNORED
- * @param BagOStuff|null $cache IGNORED
- *
- * @return SiteStore
- */
- public static function newInstance( $sitesTable = null, BagOStuff $cache = null ) {
- wfDeprecated( __METHOD__, '1.27' );
- if ( $sitesTable !== null ) {
- throw new InvalidArgumentException(
- __METHOD__ . ': $sitesTable parameter is unused and must be null'
- );
- }
-
- // NOTE: we silently ignore $cache for now, since some existing callers
- // specify it. If we break compatibility with them, we could just as
- // well just remove this class.
-
- return \MediaWiki\MediaWikiServices::getInstance()->getSiteStore();
- }
-
-}
return true;
}
- /**
- * Get the localized descriptive name for a group, if it exists
- * @deprecated since 1.29 Use UserGroupMembership::getGroupName instead
- *
- * @param string $group Internal group name
- * @return string Localized descriptive group name
- */
- public static function getGroupName( $group ) {
- wfDeprecated( __METHOD__, '1.29' );
- return UserGroupMembership::getGroupName( $group );
- }
-
- /**
- * Get the localized descriptive name for a member of a group, if it exists
- * @deprecated since 1.29 Use UserGroupMembership::getGroupMemberName instead
- *
- * @param string $group Internal group name
- * @param string $username Username for gender (since 1.19)
- * @return string Localized name for group member
- */
- public static function getGroupMember( $group, $username = '#' ) {
- wfDeprecated( __METHOD__, '1.29' );
- return UserGroupMembership::getGroupMemberName( $group, $username );
- }
-
/**
* Return the set of defined explicit groups.
* The implicit groups (by default *, 'user' and 'autoconfirmed')
jquery.client:
type: tar
- src: https://registry.npmjs.org/jquery-client/-/jquery-client-2.0.1.tgz
- integrity: sha256-tizJojJ55YYdKh67Zj/ho/9IAkDDA2UGKpcNvzn96Zs=
+ src: https://registry.npmjs.org/jquery-client/-/jquery-client-2.0.2.tgz
+ integrity: sha256-8c8nBbBykHEMc4I7ksdKJvvw/P7WkaC2X46RTPdz/pw=
dest:
package/AUTHORS.txt:
package/jquery.client.js:
-Trevor Parscal <trevorparscal@gmail.com>
-Timo Tijhof <krinklemail@gmail.com>
-Roan Kattouw <roan.kattouw@gmail.com>
-Derk-Jan Hartman <hartman.wiki@gmail.com>
+Alexander Monk <krenair@gmail.com>
Bartosz Dziewoński <matma.rex@gmail.com>
-Rob Moen <rmoen@wikimedia.org>
+Brion Vibber <brion@wikimedia.org>
+Derk-Jan Hartman <hartman@videolan.org>
Ed Sanders <esanders@wikimedia.org>
-Alex Monk <krenair@gmail.com>
James D. Forrester <jforrester@wikimedia.org>
+Roan Kattouw <roan.kattouw@gmail.com>
+Rob Moen <rmoen@mediawiki.org>
+Timo Tijhof <krinklemail@gmail.com>
+Trevor Parscal <trevorparscal@gmail.com>
/*!
- * jQuery Client v2.0.1
+ * jQuery Client v2.0.2
* https://www.mediawiki.org/wiki/JQuery_Client
*
- * Copyright 2010-2015 jquery-client maintainers and other contributors.
+ * Copyright 2010-2019 jquery-client maintainers and other contributors.
* Released under the MIT license
* http://jquery-client.mit-license.org
*/
* @class jQuery.client
* @singleton
*/
-( function ( $ ) {
+( function () {
/**
* @private
return profileCache[ nav.userAgent + '|' + nav.platform ];
}
+ // eslint-disable-next-line vars-on-top
var
versionNumber,
key = nav.userAgent + '|' + nav.platform,
[ 'Minefield', 'Firefox' ],
// This helps keep different versions consistent
[ 'Navigator', 'Netscape' ],
- // This prevents version extraction issues, otherwise translation would happen later
+ // This prevents version extraction issues,
+ // otherwise translation would happen later
[ 'PLAYSTATION 3', 'PS3' ]
],
- // Strings which precede a version number in a user agent string - combined and used as
- // match 1 in version detection
+ // Strings which precede a version number in a user agent string - combined and
+ // used as match 1 in version detection
versionPrefixes = [
'camino', 'chrome', 'firefox', 'iceweasel', 'netscape', 'netscape6', 'opera', 'version', 'konqueror',
'lynx', 'msie', 'safari', 'ps3', 'android'
],
- // Used as matches 2, 3 and 4 in version extraction - 3 is used as actual version number
+ // Used as matches 2, 3 and 4 in version extraction - 3 is used as actual
+ // version number
versionSuffix = '(\\/|\\;?\\s|)([a-z0-9\\.\\+]*?)(\\;|dev|rel|\\)|\\s|$)',
// Names of known browsers
names = [
// Translations for conforming operating system names
platformTranslations = [ [ 'sunos', 'solaris' ], [ 'wow64', 'win' ] ],
- /**
- * Performs multiple replacements on a string
- * @ignore
- */
+ // Performs multiple replacements on a string
translate = function ( source, translations ) {
var i;
for ( i = 0; i < translations.length; i++ ) {
platform = uk,
version = x;
- if ( match = new RegExp( '(' + wildUserAgents.join( '|' ) + ')' ).exec( ua ) ) {
- // Takes a userAgent string and translates given text into something we can more easily work with
+ if ( ( match = new RegExp( '(' + wildUserAgents.join( '|' ) + ')' ).exec( ua ) ) ) {
+ // Takes a userAgent string and translates given text into something we can more
+ // easily work with
ua = translate( ua, userAgentTranslations );
}
// Everything will be in lowercase from now on
ua = ua.toLowerCase();
+ // Firefox Mobile: Remove 'Android' identifier so it matches to 'Firefox' instead
+ if ( ua.match( /android/ ) && ua.match( /firefox/ ) ) {
+ ua = ua.replace( new RegExp( 'android' + versionSuffix ), '' );
+ }
+
// Extraction
- if ( match = new RegExp( '(' + names.join( '|' ) + ')' ).exec( ua ) ) {
+ if ( ( match = new RegExp( '(' + names.join( '|' ) + ')' ).exec( ua ) ) ) {
name = translate( match[ 1 ], nameTranslations );
}
- if ( match = new RegExp( '(' + layouts.join( '|' ) + ')' ).exec( ua ) ) {
+ if ( ( match = new RegExp( '(' + layouts.join( '|' ) + ')' ).exec( ua ) ) ) {
layout = translate( match[ 1 ], layoutTranslations );
}
- if ( match = new RegExp( '(' + layoutVersions.join( '|' ) + ')\\/(\\d+)' ).exec( ua ) ) {
+ if ( ( match = new RegExp( '(' + layoutVersions.join( '|' ) + ')\\/(\\d+)' ).exec( ua ) ) ) {
layoutversion = parseInt( match[ 2 ], 10 );
}
- if ( match = new RegExp( '(' + platforms.join( '|' ) + ')' ).exec( nav.platform.toLowerCase() ) ) {
+ if ( ( match = new RegExp( '(' + platforms.join( '|' ) + ')' ).exec( nav.platform.toLowerCase() ) ) ) {
platform = translate( match[ 1 ], platformTranslations );
}
- if ( match = new RegExp( '(' + versionPrefixes.join( '|' ) + ')' + versionSuffix ).exec( ua ) ) {
+ if ( ( match = new RegExp( '(' + versionPrefixes.join( '|' ) + ')' + versionSuffix ).exec( ua ) ) ) {
version = match[ 3 ];
}
layoutversion = parseInt( match[ 1 ], 10 );
}
// And Amazon Silk's lies about being Android on mobile or Safari on desktop
- if ( match = ua.match( /\bsilk\/([0-9.\-_]*)/ ) ) {
+ if ( ( match = ua.match( /\bsilk\/([0-9.\-_]*)/ ) ) ) {
if ( match[ 1 ] ) {
name = 'silk';
version = match[ 1 ];
versionNumber = parseFloat( version, 10 ) || 0.0;
// Caching
-
- return profileCache[ key ] = {
+ profileCache[ key ] = {
name: name,
layout: layout,
layoutVersion: layoutversion,
versionBase: ( version !== x ? Math.floor( versionNumber ).toString() : x ),
versionNumber: versionNumber
};
+
+ return profileCache[ key ];
},
/**
*
* @param {Object} map Browser support map
* @param {Object} [profile] A client-profile object
- * @param {boolean} [exactMatchOnly=false] Only return true if the browser is matched, otherwise
- * returns true if the browser is not found.
+ * @param {boolean} [exactMatchOnly=false] Only return true if the browser is matched,
+ * otherwise returns true if the browser is not found.
*
* @return {boolean} The current browser is in the support map
*/
test: function ( map, profile, exactMatchOnly ) {
- /* eslint-disable no-eval */
-
var conditions, dir, i, op, val, j, pieceVersion, pieceVal, compare;
profile = $.isPlainObject( profile ) ? profile : $.client.profile();
if ( map.ltr && map.rtl ) {
- dir = $( 'body' ).is( '.rtl' ) ? 'rtl' : 'ltr';
+ dir = $( document.body ).is( '.rtl' ) ? 'rtl' : 'ltr';
map = map[ dir ];
}
- // Check over each browser condition to determine if we are running in a compatible client
+ // Check over each browser condition to determine if we are running in a
+ // compatible client
if ( typeof map !== 'object' || map[ profile.name ] === undefined ) {
// Not found, return true if exactMatchOnly not set, false otherwise
return !exactMatchOnly;
op = conditions[ i ][ 0 ];
val = conditions[ i ][ 1 ];
if ( typeof val === 'string' ) {
- // Perform a component-wise comparison of versions, similar to PHP's version_compare
- // but simpler. '1.11' is larger than '1.2'.
+ // Perform a component-wise comparison of versions, similar to
+ // PHP's version_compare but simpler. '1.11' is larger than '1.2'.
pieceVersion = profile.version.toString().split( '.' );
pieceVal = val.split( '.' );
// Extend with zeroes to equal length
}
}
// compare will be -1, 0 or 1, depending on comparison result
+ // eslint-disable-next-line no-eval
if ( !( eval( String( compare + op + '0' ) ) ) ) {
return false;
}
} else if ( typeof val === 'number' ) {
+ // eslint-disable-next-line no-eval
if ( !( eval( 'profile.versionNumber' + op + val ) ) ) {
return false;
}
return true;
}
};
-}( jQuery ) );
+}() );
fileReader = new FileReader();
fileReader.onload = function () {
var fileStr, arr, i, metadata,
- jpegmeta = mw.loader.require( 'mediawiki.libs.jpegmeta' );
+ jpegmeta = require( 'mediawiki.libs.jpegmeta' );
if ( typeof fileReader.result === 'string' ) {
fileStr = fileReader.result;
return text;
},
- setSpecialCharacters: function ( data ) {
- this.specialCharacters = data;
- },
-
/**
* Formats language tags according the BCP 47 standard.
* See LanguageCode::bcp47 for the PHP implementation.
( function () {
var specialCharacters = require( './specialcharacters.json' );
- mw.language.setSpecialCharacters( specialCharacters );
+ // Deprecated since 1.33
+ mw.log.deprecate( mw.language, 'specialCharacters', specialCharacters,
+ 'Use require( \'mediawiki.language.specialCharacters\' ) instead',
+ 'mw.language.specialCharacters'
+ );
module.exports = specialCharacters;
}() );
/* global JpegMeta */
-( function () {
- // Export as module
- module.exports = function ( fileReaderResult, fileName ) {
- return new JpegMeta.JpegFile( fileReaderResult, fileName );
- };
-
- // Back-compat: Also expose via mw.lib
- // @deprecated since 1.31
- mw.log.deprecate( mw.libs, 'jpegmeta', module.exports );
-}() );
+// Export as module
+module.exports = function ( fileReaderResult, fileName ) {
+ return new JpegMeta.JpegFile( fileReaderResult, fileName );
+};
};
img.src = dataURL;
}, mw.config.get( 'wgFileCanRotate' ) ? function ( data ) {
- var jpegmeta = mw.loader.require( 'mediawiki.libs.jpegmeta' );
+ var jpegmeta = require( 'mediawiki.libs.jpegmeta' );
try {
meta = jpegmeta( data, file.fileName );
// eslint-disable-next-line no-underscore-dangle, camelcase
}
} );
- /**
- * @method stickyRandomId
- * @deprecated since 1.32 use getPageviewToken instead
- */
- mw.log.deprecate( mw.user, 'stickyRandomId', mw.user.getPageviewToken, 'Please use getPageviewToken instead' );
-
}() );
'use strict';
var mw, StringSet, log,
- hasOwn = Object.prototype.hasOwnProperty,
- trackQueue = [];
+ hasOwn = Object.prototype.hasOwnProperty;
/**
* FNV132 hash function
* @return {string} hash as an seven-character base 36 string
*/
function fnv132( str ) {
- /* eslint-disable no-bitwise */
var hash = 0x811C9DC5,
i;
+ /* eslint-disable no-bitwise */
for ( i = 0; i < str.length; i++ ) {
hash += ( hash << 1 ) + ( hash << 4 ) + ( hash << 7 ) + ( hash << 8 ) + ( hash << 24 );
hash ^= str.charCodeAt( i );
while ( hash.length < 7 ) {
hash = '0' + hash;
}
+ /* eslint-enable no-bitwise */
return hash;
- /* eslint-enable no-bitwise */
}
function defineFallbacks() {
function logError( topic, data ) {
var msg,
e = data.exception,
- source = data.source,
- module = data.module,
console = window.console;
if ( console && console.log ) {
- msg = ( e ? 'Exception' : 'Error' ) + ' in ' + source;
- if ( module ) {
- msg += ' in module ' + module;
- }
- msg += ( e ? ':' : '.' );
+ msg = ( e ? 'Exception' : 'Error' ) +
+ ' in ' + data.source +
+ ( data.module ? ' in module ' + data.module : '' ) +
+ ( e ? ':' : '.' );
+
console.log( msg );
// If we have an exception object, log it to the warning channel to trigger
this.set = function ( selection, value ) {
var s;
if ( arguments.length > 1 ) {
- if ( typeof selection !== 'string' ) {
- return false;
+ if ( typeof selection === 'string' ) {
+ setGlobalMapValue( this, selection, value );
+ return true;
}
- setGlobalMapValue( this, selection, value );
- return true;
- }
- if ( typeof selection === 'object' ) {
+ } else if ( typeof selection === 'object' ) {
for ( s in selection ) {
setGlobalMapValue( this, s, selection[ s ] );
}
var s;
// Use `arguments.length` because `undefined` is also a valid value.
if ( arguments.length > 1 ) {
- if ( typeof selection !== 'string' ) {
- return false;
+ // Set one key
+ if ( typeof selection === 'string' ) {
+ this.values[ selection ] = value;
+ return true;
}
- this.values[ selection ] = value;
- return true;
- }
- if ( typeof selection === 'object' ) {
+ } else if ( typeof selection === 'object' ) {
+ // Set multiple keys
for ( s in selection ) {
this.values[ s ] = selection[ s ];
}
* @param {string} key Name of property to create in `obj`
* @param {Mixed} val The value this property should return when accessed
* @param {string} [msg] Optional text to include in the deprecation message
- * @param {string} [logName=key] Optional custom name for the feature.
- * This is used instead of `key` in the message and `mw.deprecate` tracking.
+ * @param {string} [logName] Name for the feature for logging and tracking
+ * purposes. Except for properties of the window object, tracking is only
+ * enabled if logName is set.
*/
log.deprecate = function ( obj, key, val, msg, logName ) {
var stacks;
function maybeLog() {
- var name,
+ var name = logName || key,
trace = new Error().stack;
if ( !stacks ) {
stacks = new StringSet();
}
if ( !stacks.has( trace ) ) {
stacks.add( trace );
- name = logName || key;
- mw.track( 'mw.deprecate', name );
+ if ( logName || obj === window ) {
+ mw.track( 'mw.deprecate', name );
+ }
mw.log.warn(
- 'Use of "' + name + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' )
+ 'Use of "' + name + '" is deprecated.' + ( msg ? ' ' + msg : '' )
);
}
}
mw = {
redefineFallbacksForTest: function () {
if ( !window.QUnit ) {
- throw new Error( 'Reset not allowed outside unit tests' );
+ throw new Error( 'Not allowed' );
}
defineFallbacks();
},
* @return {number} Current time
*/
now: function () {
- // Optimisation: Define the shortcut on first call, not at module definition.
+ // Optimisation: Make startup initialisation faster by defining the
+ // shortcut on first call, not at module definition.
var perf = window.performance,
navStart = perf && perf.timing && perf.timing.navigationStart;
// Define the relevant shortcut
- mw.now = navStart && typeof perf.now === 'function' ?
+ mw.now = navStart && perf.now ?
function () { return navStart + perf.now(); } :
Date.now;
/**
* List of all analytic events emitted so far.
*
+ * Exposed only for use by mediawiki.base.
+ *
* @private
* @property {Array}
*/
- trackQueue: trackQueue,
+ trackQueue: [],
track: function ( topic, data ) {
- trackQueue.push( { topic: topic, timeStamp: mw.now(), data: data } );
- // The base module extends this method to fire events here
+ mw.trackQueue.push( { topic: topic, timeStamp: mw.now(), data: data } );
+ // This method is extended by mediawiki.base to also fire events.
},
/**
i -= 1;
try {
if ( failed && job.error ) {
- job.error( new Error( 'Module has failed dependencies' ), job.dependencies );
+ job.error( new Error( 'Failed dependencies' ), job.dependencies );
} else if ( !failed && job.ready ) {
job.ready();
}
// Add base modules
if ( baseModules.indexOf( module ) === -1 ) {
- baseModules.forEach( function ( baseModule ) {
- if ( resolved.indexOf( baseModule ) === -1 ) {
- resolved.push( baseModule );
+ for ( i = 0; i < baseModules.length; i++ ) {
+ if ( resolved.indexOf( baseModules[ i ] ) === -1 ) {
+ resolved.push( baseModules[ i ] );
}
- } );
+ }
}
// Tracks down dependencies
// these as the server will deny them anyway (T101806).
if ( registry[ module ].group === 'private' ) {
setAndPropagate( module, 'error' );
- return;
+ } else {
+ queue.push( module );
}
- queue.push( module );
}
} );
} else {
mainScript = script.files[ script.main ];
if ( typeof mainScript !== 'function' ) {
- throw new Error( 'Main script file ' + script.main + ' in module ' + module +
- 'must be of type function, is of type ' + typeof mainScript );
+ throw new Error( 'Main file ' + script.main + ' in module ' + module +
+ ' must be of type function, found ' + typeof mainScript );
}
// jQuery parameters are not passed for multi-file modules
mainScript(
return;
}
// Unknown type
- throw new Error( 'invalid type for external url, must be text/css or text/javascript. not ' + type );
+ throw new Error( 'type must be text/css or text/javascript, found ' + type );
}
// Called with single module
modules = [ modules ];
// Only ready modules can be required
if ( state !== 'ready' ) {
// Module may've forgotten to declare a dependency
- throw new Error( 'Module "' + moduleName + '" is not loaded.' );
+ throw new Error( 'Module "' + moduleName + '" is not loaded' );
}
return registry[ moduleName ].module.exports;
this.stats.hits++;
return this.items[ key ];
}
+
this.stats.misses++;
return false;
},
!Array.isArray( descriptor.script )
) {
encodedScript = '{' +
- '"main":' + JSON.stringify( descriptor.script.main ) + ',' +
- '"files":{' +
+ 'main:' + JSON.stringify( descriptor.script.main ) + ',' +
+ 'files:{' +
Object.keys( descriptor.script.files ).map( function ( key ) {
var value = descriptor.script.files[ key ];
return JSON.stringify( key ) + ':' +
$this->assertSame( $expected, $actual, $title->getPrefixedDBkey() );
}
- /**
- * @dataProvider provideCanHaveTalkPage
- * @covers Title::canTalk
- *
- * @param Title $title
- * @param bool $expected
- */
- public function testCanTalk( Title $title, $expected ) {
- $actual = $title->canTalk();
- $this->assertSame( $expected, $actual, $title->getPrefixedDBkey() );
- }
-
public static function provideGetTalkPage_good() {
return [
[ Title::makeTitle( NS_MAIN, 'Test' ), Title::makeTitle( NS_TALK, 'Test' ) ],
const MWBot = require( 'mwbot' ),
Page = require( './Page' ),
- FRONTPAGE_REQUESTS_MAX_RUNS = 10; // (arbitrary) safe-guard against endless execution
+ MAINPAGE_REQUESTS_MAX_RUNS = 10; // (arbitrary) safe-guard against endless execution
+
+function getJobCount() {
+ let bot = new MWBot( {
+ apiUrl: `${browser.options.baseUrl}/api.php`
+ } );
+ return bot.request( {
+ action: 'query',
+ meta: 'siteinfo',
+ siprop: 'statistics'
+ } ).then( ( response ) => {
+ return response.query.statistics.jobs;
+ } );
+}
+
+function log( message ) {
+ process.stdout.write( `RunJobs ${message}\n` );
+}
+
+function runThroughMainPageRequests( runCount = 1 ) {
+ let page = new Page();
+ log( `through requests to the main page (run ${runCount}).` );
+
+ page.openTitle( '' );
+
+ return getJobCount().then( ( jobCount ) => {
+ if ( jobCount === 0 ) {
+ log( 'found no more queued jobs.' );
+ return;
+ }
+ log( `detected ${jobCount} more queued job(s).` );
+ if ( runCount >= MAINPAGE_REQUESTS_MAX_RUNS ) {
+ log( 'stopping requests to the main page due to reached limit.' );
+ return;
+ }
+ return runThroughMainPageRequests( ++runCount );
+ } );
+}
/**
* Trigger the execution of jobs
static run() {
browser.call( () => {
- return this.runThroughFrontPageRequests();
+ return runThroughMainPageRequests();
} );
}
-
- static getJobCount() {
- let bot = new MWBot( {
- apiUrl: `${browser.options.baseUrl}/api.php`
- } );
- return new Promise( ( resolve ) => {
- return bot.request( {
- action: 'query',
- meta: 'siteinfo',
- siprop: 'statistics'
- } ).then( ( response ) => {
- resolve( response.query.statistics.jobs );
- } );
- } );
- }
-
- static runThroughFrontPageRequests( runCount = 1 ) {
- let page = new Page();
- this.log( `through requests to the front page (run ${runCount}).` );
-
- page.openTitle( '' );
-
- return this.getJobCount().then( ( jobCount ) => {
- if ( jobCount === 0 ) {
- this.log( 'found no more queued jobs.' );
- return;
- }
- this.log( `detected ${jobCount} more queued job(s).` );
- if ( runCount >= FRONTPAGE_REQUESTS_MAX_RUNS ) {
- this.log( 'stopping requests to the front page due to reached limit.' );
- return;
- }
- return this.runThroughFrontPageRequests( ++runCount );
- } );
- }
-
- static log( message ) {
- process.stdout.write( `RunJobs ${message}\n` );
- }
}
module.exports = RunJobs;