Merge "Simplify a few binary checks for bit 1"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Sun, 19 May 2019 07:54:48 +0000 (07:54 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sun, 19 May 2019 07:54:48 +0000 (07:54 +0000)
34 files changed:
RELEASE-NOTES-1.34
composer.json
includes/ForkController.php
includes/GlobalFunctions.php
includes/Revision/RevisionStore.php
includes/api/ApiUpload.php
includes/auth/LegacyHookPreAuthenticationProvider.php [deleted file]
includes/changes/ChangesList.php
includes/config/ConfigRepository.php
includes/htmlform/HTMLForm.php
includes/jobqueue/jobs/ActivityUpdateJob.php
includes/libs/IP.php
includes/libs/filebackend/SwiftFileBackend.php
includes/rcfeed/FormattedRCFeed.php
includes/search/SearchResultSet.php
includes/shell/Command.php
includes/specialpage/QueryPage.php
includes/specials/SpecialLog.php
includes/specials/pagers/DeletedContribsPager.php
includes/specials/pagers/UsersPager.php
languages/i18n/en.json
languages/i18n/qqq.json
languages/messages/MessagesSe.php
resources/Resources.php
resources/src/mediawiki.base/mediawiki.base.js
resources/src/mediawiki.jqueryMsg/mediawiki.jqueryMsg.js
resources/src/mediawiki.page.ready.js
tests/phpunit/includes/MediaWikiVersionFetcherTest.php
tests/phpunit/includes/libs/MWMessagePackTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderSkinModuleTest.php
tests/phpunit/includes/shell/ShellTest.php
tests/phpunit/includes/watcheditem/WatchedItemQueryServiceUnitTest.php
tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.test.js

index 2531be2..d9ac7bf 100644 (file)
@@ -59,6 +59,7 @@ For notes on 1.33.x and older releases, see HISTORY.
 * Updated composer/spdx-licenses from 1.4.0 to 1.5.1 (dev-only).
 * Updated mediawiki/codesniffer from 25.0.0 to 26.0.0 (dev-only).
 * Updated cssjanus/cssjanus from 1.2.1 to 1.3.0.
+* Updated wikimedia/at-ease from 1.2.0 to 2.0.0.
 * …
 
 ==== Removed external libraries ====
@@ -86,6 +87,9 @@ because of Phabricator reports.
 * (T152908) Added language support for N'Ko (nqo).
 
 === Breaking changes in 1.34 ===
+* The global functions wfSuppressWarnings and wfRestoreWarnings, deprecated in
+  1.26, have been removed. Use Wikimedia\AtEase\AtEase::suppressWarnings() and
+  Wikimedia\AtEase\AtEase::restoreWarnings() directly.
 * Preferences class, deprecated in 1.31, has been removed.
 * The following parts of code, deprecated in 1.32, were removed in favor of
   built-in PHP functions:
@@ -166,6 +170,9 @@ because of Phabricator reports.
 * The Block typehint only refers to blocks stored in the database. It should be
   updated to AbstractBlock in cases where any type of block could be expected.
 * FileRepoStatus, deprecated in 1.25, has been removed.
+* The LegacyHookPreAuthenticationProvider class, deprecated since its creation
+  in 1.27, has been removed.
+* IP::isValidBlock(), deprecated in 1.30, has been removed.
 * …
 
 === Deprecations in 1.34 ===
index 1c7f22a..11680ff 100644 (file)
@@ -34,7 +34,7 @@
                "php": ">=5.6.99",
                "psr/log": "1.0.2",
                "wikimedia/assert": "0.2.2",
-               "wikimedia/at-ease": "1.2.0",
+               "wikimedia/at-ease": "2.0.0",
                "wikimedia/base-convert": "2.0.0",
                "wikimedia/cdb": "1.4.1",
                "wikimedia/cldr-plural-rule-parser": "1.0.0",
@@ -75,7 +75,7 @@
                "wikimedia/avro": "1.8.0",
                "wikimedia/testing-access-wrapper": "~1.0",
                "wmde/hamcrest-html-matchers": "^0.1.0",
-               "mediawiki/mediawiki-phan-config": "0.5.0"
+               "mediawiki/mediawiki-phan-config": "0.6.0"
        },
        "replace": {
                "symfony/polyfill-ctype": "1.99",
index cc16964..85f3a7d 100644 (file)
@@ -123,6 +123,7 @@ class ForkController {
                                pcntl_signal_dispatch();
                        } else {
                                declare( ticks = 1 ) {
+                                       // @phan-suppress-next-line PhanPluginDuplicateExpressionAssignment
                                        $status = $status;
                                }
                        }
index 486dfe4..7256eab 100644 (file)
@@ -32,6 +32,7 @@ use MediaWiki\Session\SessionManager;
 use MediaWiki\Shell\Shell;
 use Wikimedia\ScopedCallback;
 use Wikimedia\WrappedString;
+use Wikimedia\AtEase\AtEase;
 
 /**
  * Load an extension
@@ -799,9 +800,9 @@ function wfParseUrl( $url ) {
        if ( $wasRelative ) {
                $url = "http:$url";
        }
-       Wikimedia\suppressWarnings();
+       AtEase::suppressWarnings();
        $bits = parse_url( $url );
-       Wikimedia\restoreWarnings();
+       AtEase::restoreWarnings();
        // parse_url() returns an array without scheme for some invalid URLs, e.g.
        // parse_url("%0Ahttp://example.com") == [ 'host' => '%0Ahttp', 'path' => 'example.com' ]
        if ( !$bits || !isset( $bits['scheme'] ) ) {
@@ -1846,24 +1847,6 @@ function wfNegotiateType( $cprefs, $sprefs ) {
        return $besttype;
 }
 
-/**
- * Reference-counted warning suppression
- *
- * @deprecated since 1.26, use Wikimedia\suppressWarnings() directly
- * @param bool $end
- */
-function wfSuppressWarnings( $end = false ) {
-       Wikimedia\suppressWarnings( $end );
-}
-
-/**
- * @deprecated since 1.26, use Wikimedia\restoreWarnings() directly
- * Restore error level to previous value
- */
-function wfRestoreWarnings() {
-       Wikimedia\restoreWarnings();
-}
-
 /**
  * Get a timestamp string in one of various formats
  *
@@ -1990,9 +1973,9 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) {
        }
 
        // Turn off the normal warning, we're doing our own below
-       Wikimedia\suppressWarnings();
+       AtEase::suppressWarnings();
        $ok = mkdir( $dir, $mode, true ); // PHP5 <3
-       Wikimedia\restoreWarnings();
+       AtEase::restoreWarnings();
 
        if ( !$ok ) {
                // directory may have been created on another request since we last checked
@@ -2230,9 +2213,9 @@ function wfMerge( $old, $mine, $yours, &$result, &$mergeAttemptResult = null ) {
 
        # This check may also protect against code injection in
        # case of broken installations.
-       Wikimedia\suppressWarnings();
+       AtEase::suppressWarnings();
        $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
-       Wikimedia\restoreWarnings();
+       AtEase::restoreWarnings();
 
        if ( !$haveDiff3 ) {
                wfDebug( "diff3 not found\n" );
@@ -2314,9 +2297,9 @@ function wfDiff( $before, $after, $params = '-u' ) {
        }
 
        global $wgDiff;
-       Wikimedia\suppressWarnings();
+       AtEase::suppressWarnings();
        $haveDiff = $wgDiff && file_exists( $wgDiff );
-       Wikimedia\restoreWarnings();
+       AtEase::restoreWarnings();
 
        # This check may also protect against code injection in
        # case of broken installations.
@@ -2492,7 +2475,7 @@ function wfSetupSession( $sessionId = false ) {
        if ( session_id() !== $session->getId() ) {
                session_id( $session->getId() );
        }
-       Wikimedia\quietCall( 'session_start' );
+       AtEase::quietCall( 'session_start' );
 }
 
 /**
index ea4cf88..29d7848 100644 (file)
@@ -1912,6 +1912,7 @@ class RevisionStore
                $this->initializeMutableRevisionFromArray( $revision, $fields );
 
                if ( isset( $fields['content'] ) && is_array( $fields['content'] ) ) {
+                       // @phan-suppress-next-line PhanTypeNoPropertiesForeach
                        foreach ( $fields['content'] as $role => $content ) {
                                $revision->setContent( $role, $content );
                        }
index f0d271c..fc41e4e 100644 (file)
@@ -74,8 +74,20 @@ class ApiUpload extends ApiBase {
                }
 
                // Check if the uploaded file is sane
-               wfDebug( __METHOD__ . " about to verify\n" );
-               $this->verifyUpload();
+               if ( $this->mParams['chunk'] ) {
+                       $maxSize = UploadBase::getMaxUploadSize();
+                       if ( $this->mParams['filesize'] > $maxSize ) {
+                               $this->dieWithError( 'file-too-large' );
+                       }
+                       if ( !$this->mUpload->getTitle() ) {
+                               $this->dieWithError( 'illegal-filename' );
+                       }
+               } elseif ( $this->mParams['async'] && $this->mParams['filekey'] ) {
+                       // defer verification to background process
+               } else {
+                       wfDebug( __METHOD__ . " about to verify\n" );
+                       $this->verifyUpload();
+               }
 
                // Check if the user has the rights to modify or overwrite the requested title
                // (This check is irrelevant if stashing is already requested, since the errors
diff --git a/includes/auth/LegacyHookPreAuthenticationProvider.php b/includes/auth/LegacyHookPreAuthenticationProvider.php
deleted file mode 100644 (file)
index 5f55ec5..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-/**
- * 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
- *
- * @file
- * @ingroup Auth
- */
-
-namespace MediaWiki\Auth;
-
-/**
- * A pre-authentication provider to call some legacy hooks.
- * @ingroup Auth
- * @since 1.27
- * @deprecated since 1.27
- */
-class LegacyHookPreAuthenticationProvider extends AbstractPreAuthenticationProvider {
-       public function __construct() {
-               wfDeprecated( self::class, '1.27' );
-       }
-}
index 184a2c1..6f6887b 100644 (file)
@@ -411,7 +411,7 @@ class ChangesList extends ContextSource {
                $date = $lang->userTimeAndDate( $ts, $user );
                if ( $rev->userCan( Revision::DELETED_TEXT, $user ) ) {
                        $link = MediaWikiServices::getInstance()->getLinkRenderer()->makeKnownLink(
-                               $title !== null ? $title : $rev->getTitle(),
+                               $title ?? $rev->getTitle(),
                                $date,
                                [ 'class' => 'mw-changeslist-date' ],
                                [ 'oldid' => $rev->getId() ]
index 2874c33..d48eb0e 100644 (file)
@@ -189,19 +189,12 @@ class ConfigRepository implements SalvageableService {
        public function salvage( SalvageableService $other ) {
                Assert::parameterType( self::class, $other, '$other' );
 
-               /** @var ConfigRepository $other */
-               $otherCurrentObj = $other->current();
                foreach ( $other->configItems['public'] as $name => $otherConfig ) {
                        if ( isset( $this->configItems['public'][$name] ) ) {
                                continue;
                        }
 
                        $this->add( $name, $otherConfig );
-
-                       // recover the pointer of the other config repository
-                       if ( $otherCurrentObj === $otherConfig ) {
-                               end( $this->configItems['public'] );
-                       }
                }
                foreach ( $other->configItems['private'] as $name => $otherConfig ) {
                        if ( isset( $this->configItems['private'][$name] ) ) {
@@ -209,11 +202,6 @@ class ConfigRepository implements SalvageableService {
                        }
 
                        $this->add( $name, $otherConfig );
-
-                       // recover the pointer of the other config repository
-                       if ( $otherCurrentObj === $otherConfig ) {
-                               end( $this->configItems['private'] );
-                       }
                }
 
                // disable $other
index 85a2a1b..f5be83f 100644 (file)
@@ -1287,7 +1287,7 @@ class HTMLForm extends ContextSource {
         * @return string
         */
        public function getErrors( $errors ) {
-               wfDeprecated( __METHOD__ );
+               wfDeprecated( __METHOD__, '1.28' );
                return $this->getErrorsOrWarnings( $errors, 'error' );
        }
 
index 9b08510..4de72a9 100644 (file)
@@ -59,9 +59,7 @@ class ActivityUpdateJob extends Job {
        }
 
        protected function updateWatchlistNotification() {
-               $casTimestamp = ( $this->params['notifTime'] !== null )
-                       ? $this->params['notifTime']
-                       : $this->params['curTime'];
+               $casTimestamp = $this->params['notifTime'] ?? $this->params['curTime'];
 
                $dbw = wfGetDB( DB_MASTER );
                $dbw->update( 'watchlist',
index 37e0076..e9f0258 100644 (file)
@@ -115,20 +115,6 @@ class IP {
                        || preg_match( '/^' . RE_IPV6_ADD . '$/', $ip ) );
        }
 
-       /**
-        * Validate an IP range (valid address with a valid CIDR prefix).
-        * SIIT IPv4-translated addresses are rejected.
-        * @note canonicalize() tries to convert translated addresses to IPv4.
-        *
-        * @deprecated since 1.30. Use the equivalent IP::isValidRange().
-        * @param string $ipRange
-        * @return bool True if it is valid
-        */
-       public static function isValidBlock( $ipRange ) {
-               wfDeprecated( __METHOD__, '1.30' );
-               return self::isValidRange( $ipRange );
-       }
-
        /**
         * Validate an IP range (valid address with a valid CIDR prefix).
         * SIIT IPv4-translated addresses are rejected.
index 4ba1e1c..2587812 100644 (file)
@@ -1707,9 +1707,7 @@ class SwiftFileBackend extends FileBackendStore {
                                if ( $rcode >= 200 && $rcode <= 299 ) { // OK
                                        $this->authCreds = [
                                                'auth_token' => $rhdrs['x-auth-token'],
-                                               'storage_url' => ( $this->swiftStorageUrl !== null )
-                                                       ? $this->swiftStorageUrl
-                                                       : $rhdrs['x-storage-url']
+                                               'storage_url' => $this->swiftStorageUrl ?? $rhdrs['x-storage-url']
                                        ];
 
                                        $this->srvCache->set( $cacheKey, $this->authCreds, ceil( $this->authTTL / 2 ) );
index afe900d..d0b7ae3 100644 (file)
@@ -53,6 +53,7 @@ abstract class FormattedRCFeed extends RCFeed {
        public function notify( RecentChange $rc, $actionComment = null ) {
                $params = $this->params;
                /** @var RCFeedFormatter $formatter */
+               // @phan-suppress-next-line PhanTypeExpectedObjectOrClassName
                $formatter = is_object( $params['formatter'] ) ? $params['formatter'] : new $params['formatter'];
 
                $line = $formatter->getLine( $params, $rc, $actionComment );
index 18331dd..3d3b446 100644 (file)
@@ -84,7 +84,7 @@ class SearchResultSet implements Countable, IteratorAggregate {
                        // This class will eventually be abstract. SearchEngine implementations
                        // already have to extend this class anyways to provide the actual
                        // search results.
-                       wfDeprecated( __METHOD__, 1.32 );
+                       wfDeprecated( __METHOD__, '1.32' );
                }
                $this->containedSyntax = $containedSyntax;
                $this->hasMoreResults = $hasMoreResults;
index 109097a..20b9445 100644 (file)
@@ -26,6 +26,7 @@ use MediaWiki\ShellDisabledError;
 use Profiler;
 use Psr\Log\LoggerAwareTrait;
 use Psr\Log\NullLogger;
+use Wikimedia\AtEase\AtEase;
 
 /**
  * Class used for executing shell commands
@@ -431,9 +432,9 @@ class Command {
                        // TODO replace with clear_last_error when requirements are bumped to PHP7
                        set_error_handler( function () {
                        }, 0 );
-                       \Wikimedia\suppressWarnings();
+                       AtEase::suppressWarnings();
                        trigger_error( '' );
-                       \Wikimedia\restoreWarnings();
+                       AtEase::restoreWarnings();
                        restore_error_handler();
 
                        $readPipes = array_filter( $pipes, function ( $fd ) use ( $desc ) {
index 46873b1..b8fde7d 100644 (file)
@@ -384,7 +384,7 @@ abstract class QueryPage extends SpecialPage {
 
        /**
         * Get a DB connection to be used for slow recache queries
-        * @return \Wikimedia\Rdbms\Database
+        * @return IDatabase
         */
        function getRecacheDB() {
                return wfGetDB( DB_REPLICA, [ $this->getName(), 'QueryPage::recache', 'vslow' ] );
index 21c166c..2f0c2ce 100644 (file)
@@ -185,7 +185,7 @@ class SpecialLog extends SpecialPage {
         */
        private function parseParams( FormOptions $opts, $par ) {
                # Get parameters
-               $par = $par !== null ? $par : '';
+               $par = $par ?? '';
                $parms = explode( '/', $par );
                $symsForAll = [ '*', 'all' ];
                if ( $parms[0] != '' &&
index 56b799b..11a8532 100644 (file)
@@ -50,7 +50,7 @@ class DeletedContribsPager extends IndexPager {
        public $namespace = '';
 
        /**
-        * @var \Wikimedia\Rdbms\Database
+        * @var IDatabase
         */
        public $mDb;
 
index 4453772..d08eb89 100644 (file)
@@ -49,7 +49,7 @@ class UsersPager extends AlphabeticPager {
                }
 
                $request = $this->getRequest();
-               $par = ( $par !== null ) ? $par : '';
+               $par = $par ?? '';
                $parms = explode( '/', $par );
                $symsForAll = [ '*', 'user' ];
 
index 15edfc0..04eec62 100644 (file)
        "virus-scanfailed": "scan failed (code $1)",
        "virus-unknownscanner": "unknown antivirus:",
        "logouttext": "<strong>You are now logged out.</strong>\n\nNote that some pages may continue to be displayed as if you were still logged in, until you clear your browser cache.",
+       "logging-out-notify": "You are being logged out, please wait.",
+       "logout-failed": "Cannot log out now: $1",
        "cannotlogoutnow-title": "Cannot log out now",
        "cannotlogoutnow-text": "Logging out is not possible when using $1.",
        "welcomeuser": "Welcome, $1!",
        "boteditletter": "b",
        "unpatrolledletter": "!",
        "number_of_watching_users_RCview": "[$1]",
-       "number_of_watching_users_pageview": "[$1 watching {{PLURAL:$1|user|users}}]",
        "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} after change",
        "newsectionsummary": "/* $1 */ new section",
        "img-auth-nopathinfo": "Missing path information.\nYour server must be set up to pass the REQUEST_URI and/or PATH_INFO variables.\nIf it is, try enabling $wgUsePathInfo.\nSee https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "img-auth-notindir": "Requested path is not in the configured upload directory.",
        "img-auth-badtitle": "Unable to construct a valid title from \"$1\".",
-       "img-auth-nologinnWL": "You are not logged in and \"$1\" is not in the whitelist.",
        "img-auth-nofile": "File \"$1\" does not exist.",
        "img-auth-isdir": "You are trying to access a directory \"$1\".\nOnly file access is allowed.",
        "img-auth-streaming": "Streaming \"$1\".",
index 972e37a..3862f5f 100644 (file)
        "virus-scanfailed": "Used as error message. \"scan\" stands for \"virus scan\". Parameters:\n* $1 - exit code of virus scanner",
        "virus-unknownscanner": "Used as error message. This message is followed by the virus scanner name.",
        "logouttext": "Log out message. Parameters:\n* $1 - (Unused) an URL to [[Special:Userlogin]] containing <code>returnto</code> and <code>returntoquery</code> parameters",
+       "logging-out-notify": "The message when the user is being logged out",
+       "logout-failed": "Message when log out fails in notification popup. Parameters:\n* $1 - Error message",
        "cannotlogoutnow-title": "Error page title shown when logging out is not possible.",
        "cannotlogoutnow-text": "Error page text shown when logging out is not possible. Parameters:\n* $1 - Session type in use that makes it not possible to log out, from a message like {{msg-mw|sessionprovider-mediawiki-session-cookiesessionprovider}}.",
        "welcomeuser": "Text for a welcome heading that users see after registering a user account.\n\nParameters:\n* $1 - the username of the new user. See [[phab:T44215]]",
        "boteditletter": "Abbreviation of \"'''bot'''\". Appears in [[Special:RecentChanges]] and [[Special:Watchlist]].\n\n{{Rc single letters}}",
        "unpatrolledletter": "{{optional}}\n\nUsed in {{msg-mw|Recentchanges-label-legend}}, meaning \"unpatrolled\".\n\n{{Rc single letters}}",
        "number_of_watching_users_RCview": "{{notranslate}}\nParameters:\n* $1 - number of users who are watching",
-       "number_of_watching_users_pageview": "Used if <code>$wgPageShowWatchingUsers</code> is true.\n* $1 - number of watching user(s)",
        "rc-change-size": "{{optional}}\nDoes not work under $wgMiserMode ([[mwr:48986|r48986]]).\n\nParameters:\n* $1 - size of diff",
        "rc-change-size-new": "Tooltip when hovering a change list diff size. Parameters:\n* $1 - the resulting new size (in bytes)",
        "newsectionsummary": "Default summary when adding a new section to a page. Parameters:\n* $1 - section title",
        "img-auth-nopathinfo": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Missing PATH_INFO - see english description\n{{Doc-important|This is plain text. Do not use any wiki syntax.}}",
        "img-auth-notindir": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: When the specified path is not in upload directory.",
        "img-auth-badtitle": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Bad title, $1 is the invalid title",
-       "img-auth-nologinnWL": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Logged in and file not whitelisted.  $1 is the file not in whitelist.",
        "img-auth-nofile": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Non existent file, $1 is the file that does not exist.",
        "img-auth-isdir": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Trying to access a directory instead of a file, $1 is the directory.",
        "img-auth-streaming": "[[mw:Manual:Image Authorization|Manual:Image Authorization]]: Is now streaming file specified by $1.",
index 4859719..11547f4 100644 (file)
@@ -134,6 +134,14 @@ $magicWords = [
        'img_link'                  => [ '1', 'liŋka=$1', 'link=$1' ],
 ];
 
+$defaultDateFormat = 'mdy';
+
+$dateFormats = [
+       'mdy time' => 'G.i',
+       'mdy date' => 'xg j "b." Y',
+       'mdy both' => 'xg j "b." Y "dii." G.i',
+];
+
 $separatorTransformTable = [ ',' => "\u{00A0}", '.' => ',' ];
 
 $linkTrail = '/^(:?[a-zàáâçčʒǯđðéèêëǧǥȟíìîïıǩŋñóòôõßšŧúùûýÿüžþæøåäö]+)(.*)$/sDu';
index 6b0b233..4c359ee 100644 (file)
@@ -1704,8 +1704,14 @@ return [
                'dependencies' => [
                        'jquery.accessKeyLabel',
                        'jquery.checkboxShiftClick',
+                       'mediawiki.notify',
+                       'mediawiki.api'
                ],
                'targets' => [ 'desktop', 'mobile' ],
+               'messages' => [
+                       'logout-failed',
+                       'logging-out-notify'
+               ]
        ],
        'mediawiki.page.startup' => [
                'scripts' => 'resources/src/mediawiki.page.startup.js',
index 9016c7c..00a74fe 100644 (file)
                 * @return {string} Parsed message
                 */
                parser: function () {
-                       var text;
-                       if ( mw.config.get( 'wgUserLanguage' ) === 'qqx' ) {
+                       var text = this.map.get( this.key );
+                       if (
+                               mw.config.get( 'wgUserLanguage' ) === 'qqx' &&
+                               ( !text || text === '(' + this.key + ')' )
+                       ) {
                                text = '(' + this.key + '$*)';
-                       } else {
-                               text = this.map.get( this.key );
                        }
                        return mw.format.apply( null, [ text ].concat( this.parameters ) );
                },
index 6416612..e0c9833 100644 (file)
@@ -317,13 +317,14 @@ mw.jqueryMsg.Parser.prototype = {
                var wikiText;
 
                if ( !Object.prototype.hasOwnProperty.call( this.astCache, key ) ) {
-                       if ( mw.config.get( 'wgUserLanguage' ) === 'qqx' ) {
+                       wikiText = this.settings.messages.get( key );
+                       if (
+                               mw.config.get( 'wgUserLanguage' ) === 'qqx' &&
+                               ( !wikiText || wikiText === '(' + key + ')' )
+                       ) {
                                wikiText = '(' + key + '$*)';
-                       } else {
-                               wikiText = this.settings.messages.get( key );
-                               if ( typeof wikiText !== 'string' ) {
-                                       wikiText = '⧼' + key + '⧽';
-                               }
+                       } else if ( typeof wikiText !== 'string' ) {
+                               wikiText = '⧼' + key + '⧽';
                        }
                        wikiText = mw.internalDoTransformFormatForQqx( wikiText, replacements );
                        this.astCache[ key ] = this.wikiTextToAst( wikiText );
index 12009d1..630e3a6 100644 (file)
                        window.print();
                        e.preventDefault();
                } );
+
+               // Turn logout to a POST action
+               $( '#pt-logout a' ).on( 'click', function ( e ) {
+                       var api = new mw.Api(), returnUrl;
+                       returnUrl = $( '#pt-logout a' ).attr( 'href' );
+                       mw.notify(
+                               mw.message( 'logging-out-notify' ),
+                               { tag: 'logout', autoHide: false }
+                       );
+                       api.postWithToken( 'csrf', {
+                               action: 'logout'
+                       } ).done( function () {
+                               // Horrible hack until deprecation of logoutToken in GET is done
+                               returnUrl = returnUrl.replace( /logoutToken=.+?($|&)/g, 'logoutToken=%2B%5C' );
+                               window.location = returnUrl;
+                       } ).fail( function ( e ) {
+                               mw.notify(
+                                       mw.message( 'logout-failed', e ),
+                                       { type: 'error', tag: 'logout', autoHide: false }
+                               );
+                       } );
+                       e.preventDefault();
+               } );
        } );
 
 }() );
index cb234b2..9803081 100644 (file)
@@ -12,8 +12,6 @@
  */
 class MediaWikiVersionFetcherTest extends MediaWikiTestCase {
 
-       use MediaWikiCoversValidator;
-
        public function testReturnsResult() {
                global $wgVersion;
                $versionFetcher = new MediaWikiVersionFetcher();
index 3890cf8..e9bffe1 100644 (file)
@@ -5,8 +5,6 @@
  */
 class MWMessagePackTest extends MediaWikiTestCase {
 
-       use MediaWikiCoversValidator;
-
        /**
         * Provides test cases for MWMessagePackTest::testMessagePack
         *
index 231979d..23b0cb9 100644 (file)
@@ -7,8 +7,6 @@ use Wikimedia\TestingAccessWrapper;
  */
 class ResourceLoaderSkinModuleTest extends MediaWikiTestCase {
 
-       use MediaWikiCoversValidator;
-
        public static function provideGetStyles() {
                // phpcs:disable Generic.Files.LineLength
                return [
index 3c05583..5fb3ac0 100644 (file)
@@ -10,8 +10,6 @@ use Wikimedia\TestingAccessWrapper;
  */
 class ShellTest extends MediaWikiTestCase {
 
-       use MediaWikiCoversValidator;
-
        public function testIsDisabled() {
                $this->assertInternalType( 'bool', Shell::isDisabled() ); // sanity
        }
index 3ba8773..0b1d013 100644 (file)
@@ -10,8 +10,6 @@ use Wikimedia\TestingAccessWrapper;
  */
 class WatchedItemQueryServiceUnitTest extends MediaWikiTestCase {
 
-       use MediaWikiCoversValidator;
-
        /**
         * @return PHPUnit_Framework_MockObject_MockObject|CommentStore
         */
index 1c7d8ee..2fcf61e 100644 (file)
                );
 
                mw.config.set( 'wgUserLanguage', 'qqx' );
+
                $bar = $( '<b>' ).text( 'bar' );
-               assert.strictEqual( mw.message( 'foo', $bar, 'baz' ).parse(), '(foo: <b>bar</b>, baz)', 'qqx message with parameters' );
+               mw.messages.set( 'qqx-message', '(qqx-message)' );
+               mw.messages.set( 'non-qqx-message', '<b>hello world</b>' );
+
+               assert.strictEqual( mw.message( 'missing-message' ).parse(), '(missing-message)', 'qqx message (missing)' );
+               assert.strictEqual( mw.message( 'missing-message', $bar, 'baz' ).parse(), '(missing-message: <b>bar</b>, baz)', 'qqx message (missing) with parameters' );
+               assert.strictEqual( mw.message( 'qqx-message' ).parse(), '(qqx-message)', 'qqx message (defined)' );
+               assert.strictEqual( mw.message( 'qqx-message', $bar, 'baz' ).parse(), '(qqx-message: <b>bar</b>, baz)', 'qqx message (defined) with parameters' );
+               assert.strictEqual( mw.message( 'non-qqx-message' ).parse(), '<b>hello world</b>', 'non-qqx message in qqx mode' );
        } );
 
        QUnit.test( 'setParserDefaults', function ( assert ) {
index 425e18e..08262b2 100644 (file)
                );
 
                mw.config.set( 'wgUserLanguage', 'qqx' );
-               assert.strictEqual( mw.message( 'foo' ).plain(), '(foo)', 'qqx message' );
-               assert.strictEqual( mw.message( 'foo', 'bar', 'baz' ).plain(), '(foo: bar, baz)', 'qqx message with parameters' );
+
+               mw.messages.set( 'qqx-message', '(qqx-message)' );
+               mw.messages.set( 'non-qqx-message', 'hello world' );
+
+               assert.strictEqual( mw.message( 'missing-message' ).plain(), '(missing-message)', 'qqx message (missing)' );
+               assert.strictEqual( mw.message( 'missing-message', 'bar', 'baz' ).plain(), '(missing-message: bar, baz)', 'qqx message (missing) with parameters' );
+               assert.strictEqual( mw.message( 'qqx-message' ).plain(), '(qqx-message)', 'qqx message (defined)' );
+               assert.strictEqual( mw.message( 'qqx-message', 'bar', 'baz' ).plain(), '(qqx-message: bar, baz)', 'qqx message (defined) with parameters' );
+               assert.strictEqual( mw.message( 'non-qqx-message' ).plain(), 'hello world', 'non-qqx message in qqx mode' );
        } );
 
        QUnit.test( 'mw.msg', function ( assert ) {