Merge "Update OOUI to v0.28.0"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 15 Aug 2018 17:56:16 +0000 (17:56 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 15 Aug 2018 17:56:16 +0000 (17:56 +0000)
26 files changed:
RELEASE-NOTES-1.32
docs/extension.schema.v1.json
docs/extension.schema.v2.json
includes/DefaultSettings.php
includes/Title.php
includes/api/ApiQuerySiteinfo.php
includes/externalstore/ExternalStoreDB.php
includes/libs/JavaScriptMinifier.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/parser/Parser.php
includes/registration/ExtensionProcessor.php
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/tidy/RemexCompatMunger.php
includes/tidy/RemexDriver.php
includes/title/MediaWikiTitleCodec.php
includes/title/TitleParser.php
includes/title/TitleValue.php
maintenance/populateChangeTagDef.php
maintenance/populateContentTables.php
resources/src/mediawiki.widgets.datetime/DateTimeInputWidget.less
resources/src/mediawiki.widgets.datetime/mediawiki.widgets.datetime.definitions.less
tests/phpunit/includes/MergeHistoryTest.php
tests/phpunit/includes/api/ApiQuerySiteinfoTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderTest.php

index 3c26f58..0ed2631 100644 (file)
@@ -208,6 +208,9 @@ because of Phabricator reports.
 * (T140807) The wgResourceLoaderLESSImportPaths configuration option was removed
   from ResourceLoader. Instead, use `@import` statements in LESS to import
   files directly from nearby directories within the same project.
+* (T140804) The wgResourceLoaderLESSVars configuration option, deprecated
+  since 1.30, was removed. Instead, to expose variables from PHP to LESS, use
+  the ResourceLoaderModule::getLessVars() method.
 * The protected methods PHPSessionHandler::returnSuccess() and returnFailure(),
   only needed for PHP5 compatibility, have been removed. It now uses the boolean
   values `true` and `false` respectively.
index a8f66c9..c9a887d 100644 (file)
                        "type": "object",
                        "description": "ResourceLoader sources to register"
                },
-               "ResourceLoaderLESSVars": {
-                       "type": "object",
-                       "description": "ResourceLoader LESS variables"
-               },
                "ConfigRegistry": {
                        "type": "object",
                        "description": "Registry of factory functions to create Config objects"
index c9d33e1..24212a9 100644 (file)
                        "type": "object",
                        "description": "ResourceLoader sources to register"
                },
-               "ResourceLoaderLESSVars": {
-                       "type": "object",
-                       "description": "ResourceLoader LESS variables"
-               },
                "ConfigRegistry": {
                        "type": "object",
                        "description": "Registry of factory functions to create Config objects"
index 75f9b95..e81909a 100644 (file)
@@ -3809,38 +3809,6 @@ $wgResourceLoaderValidateJS = true;
  */
 $wgResourceLoaderValidateStaticJS = false;
 
-/**
- * Global LESS variables. An associative array binding variable names to
- * LESS code snippets representing their values.
- *
- * Adding an item here is equivalent to writing `@variable: value;`
- * at the beginning of all your .less files, with all the consequences.
- * In particular, string values must be escaped and quoted.
- *
- * Changes to this configuration do NOT trigger cache invalidation.
- *
- * @par Example:
- * @code
- *   $wgResourceLoaderLESSVars = [
- *     'exampleFontSize'  => '1em',
- *     'exampleBlue' => '#36c',
- *   ];
- * @endcode
- * @since 1.22
- * @deprecated since 1.30 Use ResourceLoaderModule::getLessVars() instead to
- *  add variables to individual modules that need them.
- */
-$wgResourceLoaderLESSVars = [
-       /**
-        * Minimum available screen width at which a device can be considered a tablet
-        * The number is currently based on the device width of a Samsung Galaxy S5 mini and is low
-        * enough to cover iPad (768px). Number is prone to change with new information.
-        * @since 1.27
-        * @deprecated 1.31 Use mediawiki.ui/variables instead
-        */
-       'deviceWidthTablet' => '720px',
-];
-
 /**
  * Whether ResourceLoader should attempt to persist modules in localStorage on
  * browsers that support the Web Storage API.
index f2c6adb..01a28f5 100644 (file)
@@ -3695,13 +3695,6 @@ class Title implements LinkTarget {
         * @return bool True on success
         */
        private function secureAndSplit() {
-               # Initialisation
-               $this->mInterwiki = '';
-               $this->mFragment = '';
-               $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN
-
-               $dbkey = $this->mDbkeyform;
-
                // @note: splitTitleString() is a temporary hack to allow MediaWikiTitleCodec to share
                //        the parsing code with Title, while avoiding massive refactoring.
                // @todo: get rid of secureAndSplit, refactor parsing code.
@@ -3709,7 +3702,7 @@ class Title implements LinkTarget {
                //        splitTitleString method, but the only implementation (MediaWikiTitleCodec) does
                $titleCodec = MediaWikiServices::getInstance()->getTitleParser();
                // MalformedTitleException can be thrown here
-               $parts = $titleCodec->splitTitleString( $dbkey, $this->getDefaultNamespace() );
+               $parts = $titleCodec->splitTitleString( $this->mDbkeyform, $this->getDefaultNamespace() );
 
                # Fill fields
                $this->setFragment( '#' . $parts['fragment'] );
index c26bb62..eaa3bc1 100644 (file)
@@ -784,7 +784,6 @@ class ApiQuerySiteinfo extends ApiQueryBase {
 
        public function appendExtensionTags( $property ) {
                global $wgParser;
-               $wgParser->firstCallInit();
                $tags = array_map(
                        function ( $item ) {
                                return "<$item>";
@@ -799,7 +798,6 @@ class ApiQuerySiteinfo extends ApiQueryBase {
 
        public function appendFunctionHooks( $property ) {
                global $wgParser;
-               $wgParser->firstCallInit();
                $hooks = $wgParser->getFunctionHooks();
                ApiResult::setArrayType( $hooks, 'BCarray' );
                ApiResult::setIndexedTagName( $hooks, 'h' );
index 5a77e89..75f7ccd 100644 (file)
@@ -166,6 +166,10 @@ class ExternalStoreDB extends ExternalStoreMedium {
         * @return string|bool Database domain ID or false
         */
        private function getDomainId( array $server ) {
+               if ( isset( $this->params['wiki'] ) ) {
+                       return $this->params['wiki']; // explicit domain
+               }
+
                if ( isset( $server['dbname'] ) ) {
                        // T200471: for b/c, treat any "dbname" field as forcing which database to use.
                        // MediaWiki/LoadBalancer previously did not enforce any concept of a local DB
@@ -181,7 +185,7 @@ class ExternalStoreDB extends ExternalStoreMedium {
                        return $domain->getId();
                }
 
-               return $this->params['wiki'] ?? false; // local domain unless explictly given
+               return false; // local LB domain
        }
 
        /**
index f822805..3015825 100644 (file)
@@ -70,6 +70,8 @@ class JavaScriptMinifier {
        const TYPE_LITERAL     = 117; // all literals, identifiers and unrecognised tokens
 
        const ACTION_GOTO = 201;
+       const ACTION_PUSH = 202;
+       const ACTION_POP = 203;
 
        // Sanity limit to avoid excessive memory usage
        const STACK_LIMIT = 1000;
@@ -284,6 +286,11 @@ class JavaScriptMinifier {
 
                // $model : This is the main table for our state machine. For every state/token pair
                //          the desired action is defined.
+               //
+               // The state pushed onto the stack by ACTION_PUSH will be returned to by ACTION_POP.
+               //
+               // A given state/token pair MAY NOT specify both ACTION_POP and ACTION_GOTO.
+               // In the event of such mistake, ACTION_POP is used instead of ACTION_GOTO.
                $model = [
                        // Statement - This is the initial state.
                        self::STATEMENT => [
@@ -296,7 +303,16 @@ class JavaScriptMinifier {
                                self::TYPE_ADD_OP => [
                                        self::ACTION_GOTO => self::EXPRESSION,
                                ],
+                               self::TYPE_BRACE_OPEN => [
+                                       // Use of '{' in statement context, creates a Block.
+                                       self::ACTION_PUSH => self::STATEMENT,
+                               ],
+                               self::TYPE_BRACE_CLOSE => [
+                                       // Ends a Block
+                                       self::ACTION_POP => true,
+                               ],
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
                                self::TYPE_RETURN => [
@@ -314,6 +330,7 @@ class JavaScriptMinifier {
                        ],
                        self::CONDITION => [
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::STATEMENT,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
                        ],
@@ -322,17 +339,26 @@ class JavaScriptMinifier {
                                        self::ACTION_GOTO => self::PROPERTY_EXPRESSION,
                                ],
                                self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::PROPERTY_ASSIGNMENT,
                                        self::ACTION_GOTO => self::STATEMENT,
                                ],
+                               self::TYPE_BRACE_CLOSE => [
+                                       self::ACTION_POP => true,
+                               ],
                        ],
                        self::EXPRESSION => [
                                self::TYPE_SEMICOLON => [
                                        self::ACTION_GOTO => self::STATEMENT,
                                ],
                                self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PROPERTY_ASSIGNMENT,
                                ],
+                               self::TYPE_BRACE_CLOSE => [
+                                       self::ACTION_POP => true,
+                               ],
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
                                self::TYPE_FUNC => [
@@ -347,9 +373,14 @@ class JavaScriptMinifier {
                                        self::ACTION_GOTO => self::STATEMENT,
                                ],
                                self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PROPERTY_ASSIGNMENT,
                                ],
+                               self::TYPE_BRACE_CLOSE => [
+                                       self::ACTION_POP => true,
+                               ],
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
                                self::TYPE_FUNC => [
@@ -367,6 +398,7 @@ class JavaScriptMinifier {
                                        self::ACTION_GOTO => self::EXPRESSION,
                                ],
                                self::TYPE_HOOK => [
+                                       self::ACTION_PUSH => self::EXPRESSION,
                                        self::ACTION_GOTO => self::EXPRESSION_TERNARY,
                                ],
                                self::TYPE_COLON => [
@@ -379,19 +411,26 @@ class JavaScriptMinifier {
                                        self::ACTION_GOTO => self::STATEMENT,
                                ],
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
+                               self::TYPE_BRACE_CLOSE => [
+                                       self::ACTION_POP => true,
+                               ],
                        ],
                        self::EXPRESSION_FUNC => [
                                self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_OP,
                                        self::ACTION_GOTO => self::STATEMENT,
                                ],
                        ],
                        self::EXPRESSION_TERNARY => [
                                self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_TERNARY_OP,
                                        self::ACTION_GOTO => self::PROPERTY_ASSIGNMENT,
                                ],
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_TERNARY_OP,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
                                self::TYPE_FUNC => [
@@ -409,27 +448,38 @@ class JavaScriptMinifier {
                                        self::ACTION_GOTO => self::EXPRESSION_TERNARY,
                                ],
                                self::TYPE_HOOK => [
+                                       self::ACTION_PUSH => self::EXPRESSION_TERNARY,
                                        self::ACTION_GOTO => self::EXPRESSION_TERNARY,
                                ],
                                self::TYPE_COMMA => [
                                        self::ACTION_GOTO => self::EXPRESSION_TERNARY,
                                ],
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_TERNARY_OP,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
+                               self::TYPE_COLON => [
+                                       self::ACTION_POP => true,
+                               ],
                        ],
                        self::EXPRESSION_TERNARY_FUNC => [
                                self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::EXPRESSION_TERNARY_OP,
                                        self::ACTION_GOTO => self::STATEMENT,
                                ],
                        ],
                        self::PAREN_EXPRESSION => [
                                self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::PAREN_EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PROPERTY_ASSIGNMENT,
                                ],
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::PAREN_EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
+                               self::TYPE_PAREN_CLOSE => [
+                                       self::ACTION_POP => true,
+                               ],
                                self::TYPE_FUNC => [
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION_FUNC,
                                ],
@@ -457,19 +507,29 @@ class JavaScriptMinifier {
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::PAREN_EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
+                               self::TYPE_PAREN_CLOSE => [
+                                       self::ACTION_POP => true,
+                               ],
                        ],
                        self::PAREN_EXPRESSION_FUNC => [
                                self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::PAREN_EXPRESSION_OP,
                                        self::ACTION_GOTO => self::STATEMENT,
                                ],
                        ],
                        self::PROPERTY_EXPRESSION => [
                                self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::PROPERTY_EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PROPERTY_ASSIGNMENT,
                                ],
+                               self::TYPE_BRACE_CLOSE => [
+                                       self::ACTION_POP => true,
+                               ],
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::PROPERTY_EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
                                self::TYPE_FUNC => [
@@ -492,117 +552,48 @@ class JavaScriptMinifier {
                                self::TYPE_COMMA => [
                                        self::ACTION_GOTO => self::PROPERTY_ASSIGNMENT,
                                ],
+                               self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::PROPERTY_EXPRESSION_OP,
+                               ],
+                               self::TYPE_BRACE_CLOSE => [
+                                       self::ACTION_POP => true,
+                               ],
                                self::TYPE_PAREN_OPEN => [
+                                       self::ACTION_PUSH => self::PROPERTY_EXPRESSION_OP,
                                        self::ACTION_GOTO => self::PAREN_EXPRESSION,
                                ],
                        ],
                        self::PROPERTY_EXPRESSION_FUNC => [
                                self::TYPE_BRACE_OPEN => [
+                                       self::ACTION_PUSH => self::PROPERTY_EXPRESSION_OP,
                                        self::ACTION_GOTO => self::STATEMENT,
                                ],
-                       ]
-               ];
-
-               // $push : This table contains the rules for when to push a state onto the stack.
-               //         The pushed state is the state to return to when the corresponding
-               //         closing token is found
-               $push = [
-                       self::STATEMENT => [
-                               self::TYPE_BRACE_OPEN => self::STATEMENT,
-                               self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
-                       ],
-                       self::CONDITION => [
-                               self::TYPE_PAREN_OPEN => self::STATEMENT
-                       ],
-                       self::PROPERTY_ASSIGNMENT => [
-                               self::TYPE_BRACE_OPEN => self::PROPERTY_ASSIGNMENT
-                       ],
-                       self::EXPRESSION => [
-                               self::TYPE_BRACE_OPEN => self::EXPRESSION_OP,
-                               self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
-                       ],
-                       self::EXPRESSION_NO_NL => [
-                               self::TYPE_BRACE_OPEN => self::EXPRESSION_OP,
-                               self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
-                       ],
-                       self::EXPRESSION_OP => [
-                               self::TYPE_HOOK       => self::EXPRESSION,
-                               self::TYPE_PAREN_OPEN => self::EXPRESSION_OP
-                       ],
-                       self::EXPRESSION_FUNC => [
-                               self::TYPE_BRACE_OPEN => self::EXPRESSION_OP
-                       ],
-                       self::EXPRESSION_TERNARY => [
-                               self::TYPE_BRACE_OPEN => self::EXPRESSION_TERNARY_OP,
-                               self::TYPE_PAREN_OPEN => self::EXPRESSION_TERNARY_OP
-                       ],
-                       self::EXPRESSION_TERNARY_OP => [
-                               self::TYPE_HOOK       => self::EXPRESSION_TERNARY,
-                               self::TYPE_PAREN_OPEN => self::EXPRESSION_TERNARY_OP
-                       ],
-                       self::EXPRESSION_TERNARY_FUNC => [
-                               self::TYPE_BRACE_OPEN => self::EXPRESSION_TERNARY_OP
-                       ],
-                       self::PAREN_EXPRESSION => [
-                               self::TYPE_BRACE_OPEN => self::PAREN_EXPRESSION_OP,
-                               self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION_OP
                        ],
-                       self::PAREN_EXPRESSION_OP => [
-                               self::TYPE_PAREN_OPEN => self::PAREN_EXPRESSION_OP
-                       ],
-                       self::PAREN_EXPRESSION_FUNC => [
-                               self::TYPE_BRACE_OPEN => self::PAREN_EXPRESSION_OP
-                       ],
-                       self::PROPERTY_EXPRESSION => [
-                               self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP,
-                               self::TYPE_PAREN_OPEN => self::PROPERTY_EXPRESSION_OP
-                       ],
-                       self::PROPERTY_EXPRESSION_OP => [
-                               self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP,
-                               self::TYPE_PAREN_OPEN => self::PROPERTY_EXPRESSION_OP
-                       ],
-                       self::PROPERTY_EXPRESSION_FUNC => [
-                               self::TYPE_BRACE_OPEN => self::PROPERTY_EXPRESSION_OP
-                       ]
-               ];
-
-               // $pop : Rules for when to pop a state from the stack
-               $pop = [
-                       self::STATEMENT              => [ self::TYPE_BRACE_CLOSE => true ],
-                       self::PROPERTY_ASSIGNMENT    => [ self::TYPE_BRACE_CLOSE => true ],
-                       self::EXPRESSION             => [ self::TYPE_BRACE_CLOSE => true ],
-                       self::EXPRESSION_NO_NL       => [ self::TYPE_BRACE_CLOSE => true ],
-                       self::EXPRESSION_OP          => [ self::TYPE_BRACE_CLOSE => true ],
-                       self::EXPRESSION_TERNARY_OP  => [ self::TYPE_COLON       => true ],
-                       self::PAREN_EXPRESSION       => [ self::TYPE_PAREN_CLOSE => true ],
-                       self::PAREN_EXPRESSION_OP    => [ self::TYPE_PAREN_CLOSE => true ],
-                       self::PROPERTY_EXPRESSION    => [ self::TYPE_BRACE_CLOSE => true ],
-                       self::PROPERTY_EXPRESSION_OP => [ self::TYPE_BRACE_CLOSE => true ]
                ];
 
                // $semicolon : Rules for when a semicolon insertion is appropriate
                $semicolon = [
                        self::EXPRESSION_NO_NL => [
-                               self::TYPE_UN_OP      => true,
-                               self::TYPE_INCR_OP    => true,
-                               self::TYPE_ADD_OP     => true,
+                               self::TYPE_UN_OP => true,
+                               self::TYPE_INCR_OP => true,
+                               self::TYPE_ADD_OP => true,
                                self::TYPE_BRACE_OPEN => true,
                                self::TYPE_PAREN_OPEN => true,
-                               self::TYPE_RETURN     => true,
-                               self::TYPE_IF         => true,
-                               self::TYPE_DO         => true,
-                               self::TYPE_FUNC       => true,
-                               self::TYPE_LITERAL    => true
+                               self::TYPE_RETURN => true,
+                               self::TYPE_IF => true,
+                               self::TYPE_DO => true,
+                               self::TYPE_FUNC => true,
+                               self::TYPE_LITERAL => true
                        ],
                        self::EXPRESSION_OP => [
-                               self::TYPE_UN_OP      => true,
-                               self::TYPE_INCR_OP    => true,
+                               self::TYPE_UN_OP => true,
+                               self::TYPE_INCR_OP => true,
                                self::TYPE_BRACE_OPEN => true,
-                               self::TYPE_RETURN     => true,
-                               self::TYPE_IF         => true,
-                               self::TYPE_DO         => true,
-                               self::TYPE_FUNC       => true,
-                               self::TYPE_LITERAL    => true
+                               self::TYPE_RETURN => true,
+                               self::TYPE_IF => true,
+                               self::TYPE_DO => true,
+                               self::TYPE_FUNC => true,
+                               self::TYPE_LITERAL => true
                        ]
                ];
 
@@ -834,10 +825,12 @@ class JavaScriptMinifier {
                        $newlineFound = false;
 
                        // Now that we have output our token, transition into the new state.
-                       if ( isset( $push[$state][$type] ) && count( $stack ) < self::STACK_LIMIT ) {
-                               $stack[] = $push[$state][$type];
+                       if ( isset( $model[$state][$type][self::ACTION_PUSH] ) &&
+                               count( $stack ) < self::STACK_LIMIT
+                       ) {
+                               $stack[] = $model[$state][$type][self::ACTION_PUSH];
                        }
-                       if ( $stack && isset( $pop[$state][$type] ) ) {
+                       if ( $stack && isset( $model[$state][$type][self::ACTION_POP] ) ) {
                                $state = array_pop( $stack );
                        } elseif ( isset( $model[$state][$type][self::ACTION_GOTO] ) ) {
                                $state = $model[$state][$type][self::ACTION_GOTO];
index 92cabca..5e08094 100644 (file)
@@ -886,34 +886,7 @@ class LoadBalancer implements ILoadBalancer {
                        $conn = $this->openForeignConnection( $i, $domain, $flags );
                } else {
                        // Connection is to the local domain
-                       $connKey = $autoCommit ? self::KEY_LOCAL_NOROUND : self::KEY_LOCAL;
-                       if ( isset( $this->conns[$connKey][$i][0] ) ) {
-                               $conn = $this->conns[$connKey][$i][0];
-                       } else {
-                               if ( !isset( $this->servers[$i] ) || !is_array( $this->servers[$i] ) ) {
-                                       throw new InvalidArgumentException( "No server with index '$i'." );
-                               }
-                               // Open a new connection
-                               $server = $this->servers[$i];
-                               $server['serverIndex'] = $i;
-                               $server['autoCommitOnly'] = $autoCommit;
-                               if ( $this->localDomain->getDatabase() !== null ) {
-                                       // Use the local domain table prefix if the local domain is specified
-                                       $server['tablePrefix'] = $this->localDomain->getTablePrefix();
-                               }
-                               $conn = $this->reallyOpenConnection( $server, $this->localDomain );
-                               $host = $this->getServerName( $i );
-                               if ( $conn->isOpen() ) {
-                                       $this->connLogger->debug(
-                                               __METHOD__ . ": connected to database $i at '$host'." );
-                                       $this->conns[$connKey][$i][0] = $conn;
-                               } else {
-                                       $this->connLogger->warning(
-                                               __METHOD__ . ": failed to connect to database $i at '$host'." );
-                                       $this->errorConnection = $conn;
-                                       $conn = false;
-                               }
-                       }
+                       $conn = $this->openLocalConnection( $i, $flags );
                }
 
                if ( $conn instanceof IDatabase && !$conn->isOpen() ) {
@@ -939,6 +912,53 @@ class LoadBalancer implements ILoadBalancer {
                return $conn;
        }
 
+       /**
+        * Open a connection to a local DB, or return one if it is already open.
+        *
+        * On error, returns false, and the connection which caused the
+        * error will be available via $this->errorConnection.
+        *
+        * @note If disable() was called on this LoadBalancer, this method will throw a DBAccessError.
+        *
+        * @param int $i Server index
+        * @param int $flags Class CONN_* constant bitfield
+        * @return Database
+        */
+       private function openLocalConnection( $i, $flags = 0 ) {
+               $autoCommit = ( ( $flags & self::CONN_TRX_AUTOCOMMIT ) == self::CONN_TRX_AUTOCOMMIT );
+
+               $connKey = $autoCommit ? self::KEY_LOCAL_NOROUND : self::KEY_LOCAL;
+               if ( isset( $this->conns[$connKey][$i][0] ) ) {
+                       $conn = $this->conns[$connKey][$i][0];
+               } else {
+                       if ( !isset( $this->servers[$i] ) || !is_array( $this->servers[$i] ) ) {
+                               throw new InvalidArgumentException( "No server with index '$i'." );
+                       }
+                       // Open a new connection
+                       $server = $this->servers[$i];
+                       $server['serverIndex'] = $i;
+                       $server['autoCommitOnly'] = $autoCommit;
+                       if ( $this->localDomain->getDatabase() !== null ) {
+                               // Use the local domain table prefix if the local domain is specified
+                               $server['tablePrefix'] = $this->localDomain->getTablePrefix();
+                       }
+                       $conn = $this->reallyOpenConnection( $server, $this->localDomain );
+                       $host = $this->getServerName( $i );
+                       if ( $conn->isOpen() ) {
+                               $this->connLogger->debug(
+                                       __METHOD__ . ": connected to database $i at '$host'." );
+                               $this->conns[$connKey][$i][0] = $conn;
+                       } else {
+                               $this->connLogger->warning(
+                                       __METHOD__ . ": failed to connect to database $i at '$host'." );
+                               $this->errorConnection = $conn;
+                               $conn = false;
+                       }
+               }
+
+               return $conn;
+       }
+
        /**
         * Open a connection to a foreign DB, or return one if it is already open.
         *
index b1e3928..1fc2f92 100644 (file)
@@ -4926,6 +4926,7 @@ class Parser {
         * @return array
         */
        public function getFunctionHooks() {
+               $this->firstCallInit();
                return array_keys( $this->mFunctionHooks );
        }
 
@@ -5482,6 +5483,7 @@ class Parser {
         * @return array
         */
        public function getTags() {
+               $this->firstCallInit();
                return array_merge(
                        array_keys( $this->mTransparentTagHooks ),
                        array_keys( $this->mTagHooks ),
index d0a9871..bf61779 100644 (file)
@@ -48,7 +48,6 @@ class ExtensionProcessor implements Processor {
                'RecentChangesFlags',
                'RemoveCredentialsBlacklist',
                'RemoveGroups',
-               'ResourceLoaderLESSVars',
                'ResourceLoaderSources',
                'RevokePermissions',
                'SessionProviders',
index 45c19eb..2b25d91 100644 (file)
@@ -42,9 +42,6 @@ class ResourceLoader implements LoggerAwareInterface {
        /** @var bool */
        protected static $debugMode = null;
 
-       /** @var array */
-       private $lessVars = null;
-
        /**
         * Module name/ResourceLoaderModule object pairs
         * @var array
@@ -1744,12 +1741,10 @@ MESSAGE;
         * Get global LESS variables.
         *
         * @since 1.27
+        * @deprecated since 1.32 Use ResourceLoderModule::getLessVars() instead.
         * @return array Map of variable names to string CSS values.
         */
        public function getLessVars() {
-               if ( $this->lessVars === null ) {
-                       $this->lessVars = $this->config->get( 'ResourceLoaderLESSVars' );
-               }
-               return $this->lessVars;
+               return [];
        }
 }
index b2ca291..6ee030e 100644 (file)
@@ -959,10 +959,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                        $cache = ObjectCache::getLocalServerInstance( CACHE_ANYTHING );
                }
 
-               $vars = array_merge(
-                       $context->getResourceLoader()->getLessVars(),
-                       $this->getLessVars( $context )
-               );
+               $vars = $this->getLessVars( $context );
                // Construct a cache key from the LESS file name, and a hash digest
                // of the LESS variables used for compilation.
                ksort( $vars );
index e6351e2..78a1104 100644 (file)
@@ -89,11 +89,19 @@ class RemexCompatMunger implements TreeHandler {
                'u' => true,
        ];
 
+       /** @var Serializer */
+       private $serializer;
+
+       /** @var bool */
+       private $trace;
+
        /**
         * @param Serializer $serializer
+        * @param bool $trace
         */
-       public function __construct( Serializer $serializer ) {
+       public function __construct( Serializer $serializer, $trace = false ) {
                $this->serializer = $serializer;
+               $this->trace = $trace;
        }
 
        public function startDocument( $fragmentNamespace, $fragmentName ) {
@@ -184,7 +192,9 @@ class RemexCompatMunger implements TreeHandler {
        }
 
        private function trace( $msg ) {
-               // echo "[RCM] $msg\n";
+               if ( $this->trace ) {
+                       wfDebug( "[RCM] $msg" );
+               }
        }
 
        /**
@@ -245,12 +255,11 @@ class RemexCompatMunger implements TreeHandler {
        ) {
                list( $parent, $newRef ) = $this->getParentForInsert( $preposition, $refElement );
                $parentData = $parent->snData;
-               $parentNs = $parent->namespace;
-               $parentName = $parent->name;
                $elementName = $element->htmlName;
 
                $inline = isset( self::$onlyInlineElements[$elementName] );
                $under = $preposition === TreeBuilder::UNDER;
+               $elementToEnd = null;
 
                if ( $under && $parentData->isPWrapper && !$inline ) {
                        // [B/b] The element is non-inline and the parent is a p-wrapper,
@@ -349,7 +358,6 @@ class RemexCompatMunger implements TreeHandler {
                $root = $serializer->getRootNode();
                $nodes = [];
                $removableNodes = [];
-               $haveContent = false;
                while ( $node !== $cloneEnd ) {
                        $nextParent = $serializer->getParentNode( $node );
                        if ( $nextParent === $root ) {
index e02af88..803369a 100644 (file)
@@ -3,37 +3,50 @@
 namespace MediaWiki\Tidy;
 
 use RemexHtml\Serializer\Serializer;
+use RemexHtml\Serializer\SerializerWithTracer;
 use RemexHtml\Tokenizer\Tokenizer;
 use RemexHtml\TreeBuilder\Dispatcher;
 use RemexHtml\TreeBuilder\TreeBuilder;
 use RemexHtml\TreeBuilder\TreeMutationTracer;
 
 class RemexDriver extends TidyDriverBase {
-       private $trace;
+       private $treeMutationTrace;
+       private $serializerTrace;
+       private $mungerTrace;
        private $pwrap;
 
        public function __construct( array $config ) {
                $config += [
                        'treeMutationTrace' => false,
+                       'serializerTrace' => false,
+                       'mungerTrace' => false,
                        'pwrap' => true
                ];
-               $this->trace = $config['treeMutationTrace'];
+               $this->treeMutationTrace = $config['treeMutationTrace'];
+               $this->serializerTrace = $config['serializerTrace'];
+               $this->mungerTrace = $config['mungerTrace'];
                $this->pwrap = $config['pwrap'];
                parent::__construct( $config );
        }
 
        public function tidy( $text ) {
+               $traceCallback = function ( $msg ) {
+                       wfDebug( "RemexHtml: $msg" );
+               };
+
                $formatter = new RemexCompatFormatter;
-               $serializer = new Serializer( $formatter );
+               if ( $this->serializerTrace ) {
+                       $serializer = new SerializerWithTracer( $formatter, null, $traceCallback );
+               } else {
+                       $serializer = new Serializer( $formatter );
+               }
                if ( $this->pwrap ) {
-                       $munger = new RemexCompatMunger( $serializer );
+                       $munger = new RemexCompatMunger( $serializer, $this->mungerTrace );
                } else {
                        $munger = $serializer;
                }
-               if ( $this->trace ) {
-                       $tracer = new TreeMutationTracer( $munger, function ( $msg ) {
-                               wfDebug( "RemexHtml: $msg" );
-                       } );
+               if ( $this->treeMutationTrace ) {
+                       $tracer = new TreeMutationTracer( $munger, $traceCallback );
                } else {
                        $tracer = $munger;
                }
@@ -48,6 +61,7 @@ class RemexDriver extends TidyDriverBase {
                        'ignoreNulls' => true,
                        'skipPreprocess' => true,
                ] );
+
                $tokenizer->execute( [
                        'fragmentNamespace' => \RemexHtml\HTMLData::NS_HTML,
                        'fragmentName' => 'body'
index 890a870..a00ef1e 100644 (file)
@@ -149,7 +149,7 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
         * @throws MalformedTitleException
         * @return TitleValue
         */
-       public function parseTitle( $text, $defaultNamespace ) {
+       public function parseTitle( $text, $defaultNamespace = NS_MAIN ) {
                // NOTE: this is an ugly cludge that allows this class to share the
                // code for parsing with the old Title class. The parser code should
                // be refactored to avoid this.
index de65be8..ddffed6 100644 (file)
@@ -43,5 +43,5 @@ interface TitleParser {
         * @throws MalformedTitleException If the text is not a valid representation of a page title.
         * @return TitleValue
         */
-       public function parseTitle( $text, $defaultNamespace );
+       public function parseTitle( $text, $defaultNamespace = NS_MAIN );
 }
index 3e13300..18e578d 100644 (file)
@@ -22,6 +22,7 @@
  */
 use MediaWiki\Linker\LinkTarget;
 use Wikimedia\Assert\Assert;
+use Wikimedia\Assert\ParameterTypeException;
 
 /**
  * Represents a page (or page fragment) title within MediaWiki.
@@ -76,10 +77,18 @@ class TitleValue implements LinkTarget {
         * @throws InvalidArgumentException
         */
        public function __construct( $namespace, $dbkey, $fragment = '', $interwiki = '' ) {
-               Assert::parameterType( 'integer', $namespace, '$namespace' );
-               Assert::parameterType( 'string', $dbkey, '$dbkey' );
-               Assert::parameterType( 'string', $fragment, '$fragment' );
-               Assert::parameterType( 'string', $interwiki, '$interwiki' );
+               if ( !is_int( $namespace ) ) {
+                       throw new ParameterTypeException( '$namespace', 'int' );
+               }
+               if ( !is_string( $dbkey ) ) {
+                       throw new ParameterTypeException( '$dbkey', 'string' );
+               }
+               if ( !is_string( $fragment ) ) {
+                       throw new ParameterTypeException( '$fragment', 'string' );
+               }
+               if ( !is_string( $interwiki ) ) {
+                       throw new ParameterTypeException( '$interwiki', 'string' );
+               }
 
                // Sanity check, no full validation or normalization applied here!
                Assert::parameter( !preg_match( '/^_|[ \r\n\t]|_$/', $dbkey ), '$dbkey',
index 707eb29..b06ac2b 100644 (file)
@@ -38,6 +38,7 @@ class PopulateChangeTagDef extends Maintenance {
                        false,
                        true
                );
+               $this->addOption( 'populate-only', 'Do not update change_tag_def table' );
        }
 
        public function execute() {
@@ -47,7 +48,9 @@ class PopulateChangeTagDef extends Maintenance {
 
                $this->countDown( 5 );
                if ( $wgChangeTagsSchemaMigrationStage < MIGRATION_NEW ) {
-                       $this->updateCountTag();
+                       if ( !$this->hasOption( 'populate-only' ) ) {
+                               $this->updateCountTag();
+                       }
                        $this->backpopulateChangeTagId();
                } else {
                        $this->updateCountTagId();
index 20d6b8b..49db4fb 100644 (file)
@@ -58,6 +58,8 @@ class PopulateContentTables extends Maintenance {
                        'Reuse content table rows when the address and model are the same. '
                        . 'This will increase the script\'s time and memory usage, perhaps significantly.',
                        false, false );
+               $this->addOption( 'start-revision', 'The rev_id to start at', false, true );
+               $this->addOption( 'start-archive', 'The ar_rev_id to start at', false, true );
                $this->setBatchSize( 500 );
        }
 
@@ -165,6 +167,7 @@ class PopulateContentTables extends Maintenance {
                                'slots' => [ 'LEFT JOIN', 'rev_id=slot_revision_id' ],
                                'page' => [ 'LEFT JOIN', 'rev_page=page_id' ],
                        ];
+                       $startOption = 'start-revision';
                } else {
                        $idField = 'ar_rev_id';
                        $tables = [ 'archive', 'slots' ];
@@ -180,6 +183,7 @@ class PopulateContentTables extends Maintenance {
                        $joins = [
                                'slots' => [ 'LEFT JOIN', 'ar_rev_id=slot_revision_id' ],
                        ];
+                       $startOption = 'start-archive';
                }
 
                $minmax = $this->dbw->selectRow(
@@ -188,6 +192,9 @@ class PopulateContentTables extends Maintenance {
                        '',
                        __METHOD__
                );
+               if ( $this->hasOption( $startOption ) ) {
+                       $minmax->min = (int)$this->getOption( $startOption );
+               }
                if ( !$minmax || !is_numeric( $minmax->min ) || !is_numeric( $minmax->max ) ) {
                        // No rows?
                        $minmax = (object)[ 'min' => 1, 'max' => 0 ];
index 510eb21..f8f2642 100644 (file)
 
        &.oo-ui-widget-enabled {
                .mw-widgets-datetime-dateTimeInputWidget-handle {
-                       .oo-ui-transition( border-color @transition-medium );
+                       .oo-ui-transition( border-color @transition-ease-medium );
 
                        &:hover {
                                border-color: @border-color-input--hover;
index 601d916..2fd1993 100644 (file)
@@ -83,7 +83,7 @@
 @opacity-base--disabled: 0.51;
 
 @transition-base:             @transition-duration-base;
-@transition-medium:           @transition-duration-medium;
+@transition-ease-medium:      @transition-duration-medium;
 // Transitions > Durations
 @transition-duration-base:    100ms;
 @transition-duration-medium:  250ms;
index 54db581..4544e9b 100644 (file)
@@ -28,6 +28,12 @@ class MergeHistoryTest extends MediaWikiTestCase {
         */
        public function testIsValidMerge( $source, $dest, $timestamp, $error ) {
                $this->setMwGlobals( 'wgContentHandlerUseDB', false );
+               if ( $timestamp === true ) {
+                       // Although this timestamp is after the latest timestamp of both pages,
+                       // MergeHistory should select the latest source timestamp up to this which should
+                       // still work for the merge.
+                       $timestamp = time() + ( 24 * 3600 );
+               }
                $mh = new MergeHistory(
                        Title::newFromText( $source ),
                        Title::newFromText( $dest ),
@@ -45,10 +51,8 @@ class MergeHistoryTest extends MediaWikiTestCase {
                return [
                        // for MergeHistory::isValidMerge
                        [ 'Test', 'Test2', false, true ],
-                       // Although this timestamp is after the latest timestamp of both pages,
-                       // MergeHistory should select the latest source timestamp up to this which should
-                       // still work for the merge.
-                       [ 'Test', 'Test2', strtotime( 'tomorrow' ), true ],
+                       // Timestamp of `true` is a placeholder for "in the future""
+                       [ 'Test', 'Test2', true, true ],
                        [ 'Test', 'Test', false, 'mergehistory-fail-self-merge' ],
                        [ 'Nonexistant', 'Test2', false, 'mergehistory-fail-invalid-source' ],
                        [ 'Test', 'Nonexistant', false, 'mergehistory-fail-invalid-dest' ],
index 7b93571..fe2058f 100644 (file)
@@ -571,7 +571,6 @@ class ApiQuerySiteinfoTest extends ApiTestCase {
        public function testExtensionTags() {
                global $wgParser;
 
-               $wgParser->firstCallInit();
                $expected = array_map(
                        function ( $tag ) {
                                return "<$tag>";
@@ -585,7 +584,6 @@ class ApiQuerySiteinfoTest extends ApiTestCase {
        public function testFunctionHooks() {
                global $wgParser;
 
-               $wgParser->firstCallInit();
                $this->assertSame( $wgParser->getFunctionHooks(), $this->doQuery( 'functionhooks' ) );
        }
 
index 71966b7..20d4b54 100644 (file)
@@ -336,6 +336,23 @@ class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase {
                );
        }
 
+       /**
+        * @covers ResourceLoaderFileModule::compileLessFile
+        */
+       public function testLessFileCompilation() {
+               $context = $this->getResourceLoaderContext();
+               $basePath = __DIR__ . '/../../data/less/module';
+               $module = new ResourceLoaderFileTestModule( [
+                       'localBasePath' => $basePath,
+                       'styles' => [ 'styles.less' ],
+               ], [
+                       'lessVars' => [ 'foo' => '2px', 'Foo' => '#eeeeee' ]
+               ] );
+               $module->setName( 'test.less' );
+               $styles = $module->getStyles( $context );
+               $this->assertStringEqualsFile( $basePath . '/styles.css', $styles['all'] );
+       }
+
        /**
         * @covers ResourceLoaderFileModule::getDefinitionSummary
         * @covers ResourceLoaderFileModule::getFileHashes
index c15eb2c..d9ad711 100644 (file)
@@ -8,15 +8,6 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
                parent::setUp();
 
                $this->setMwGlobals( [
-                       'wgResourceLoaderLESSVars' => [
-                               'foo'  => '2px',
-                               'Foo' => '#eeeeee',
-                               'bar' => 5,
-                       ],
-                       // Clear ResourceLoaderGetConfigVars hooks (called by StartupModule)
-                       // to avoid notices during testMakeModuleResponse for missing
-                       // wgResourceLoaderLESSVars keys in extension hooks.
-                       'wgHooks' => [],
                        'wgShowExceptionDetails' => true,
                ] );
        }
@@ -246,27 +237,12 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
                );
        }
 
-       /**
-        * @covers ResourceLoaderFileModule::compileLessFile
-        */
-       public function testLessFileCompilation() {
-               $context = $this->getResourceLoaderContext();
-               $basePath = __DIR__ . '/../../data/less/module';
-               $module = new ResourceLoaderFileModule( [
-                       'localBasePath' => $basePath,
-                       'styles' => [ 'styles.less' ],
-               ] );
-               $module->setName( 'test.less' );
-               $styles = $module->getStyles( $context );
-               $this->assertStringEqualsFile( $basePath . '/styles.css', $styles['all'] );
-       }
-
        /**
         * @covers ResourceLoader::getLessCompiler
         */
        public function testLessImportDirs() {
                $rl = new EmptyResourceLoader();
-               $lc = $rl->getLessCompiler( $rl->getLessVars() );
+               $lc = $rl->getLessCompiler( [ 'foo'  => '2px', 'Foo' => '#eeeeee' ] );
                $basePath = dirname( dirname( __DIR__ ) ) . '/data/less';
                $lc->SetImportDirs( [
                         "$basePath/common" => '',