Merge "resourceloader: Omit empty parameters from mw.loader.implement calls"
[lhc/web/wiklou.git] / includes / resourceloader / ResourceLoader.php
index 15bb13f..976275b 100644 (file)
@@ -35,6 +35,9 @@ class ResourceLoader {
        /** @var bool */
        protected static $debugMode = null;
 
+       /** @var array */
+       private static $lessVars = null;
+
        /**
         * Module name/ResourceLoaderModule object pairs
         * @var array
@@ -69,6 +72,11 @@ class ResourceLoader {
         */
        protected $errors = array();
 
+       /**
+        * @var MessageBlobStore
+        */
+       protected $blobStore;
+
        /**
         * Load information stored in the database about modules.
         *
@@ -247,6 +255,7 @@ class ResourceLoader {
                        $this->registerTestModules();
                }
 
+               $this->setMessageBlobStore( new MessageBlobStore() );
        }
 
        /**
@@ -256,6 +265,14 @@ class ResourceLoader {
                return $this->config;
        }
 
+       /**
+        * @param MessageBlobStore $blobStore
+        * @since 1.25
+        */
+       public function setMessageBlobStore( MessageBlobStore $blobStore ) {
+               $this->blobStore = $blobStore;
+       }
+
        /**
         * Register a module with the ResourceLoader system.
         *
@@ -458,6 +475,17 @@ class ResourceLoader {
                }
        }
 
+       /**
+        * Check whether a ResourceLoader module is registered
+        *
+        * @since 1.25
+        * @param string $name
+        * @return bool
+        */
+       public function isModuleRegistered( $name ) {
+               return isset( $this->moduleInfos[$name] );
+       }
+
        /**
         * Get the ResourceLoaderModule object for a given module name.
         *
@@ -851,9 +879,11 @@ class ResourceLoader {
                $states = array();
 
                if ( !count( $modules ) && !count( $missing ) ) {
-                       return "/* This file is the Web entry point for MediaWiki's ResourceLoader:
+                       return <<<MESSAGE
+/* This file is the Web entry point for MediaWiki's ResourceLoader:
    <https://www.mediawiki.org/wiki/ResourceLoader>. In this request,
-   no modules were requested. Max made me put this here. */";
+   no modules were requested. Max made me put this here. */
+MESSAGE;
                }
 
                $image = $context->getImageObj();
@@ -869,7 +899,7 @@ class ResourceLoader {
                // Pre-fetch blobs
                if ( $context->shouldIncludeMessages() ) {
                        try {
-                               $blobs = MessageBlobStore::getInstance()->get( $this, $modules, $context->getLanguage() );
+                               $blobs = $this->blobStore->get( $this, $modules, $context->getLanguage() );
                        } catch ( Exception $e ) {
                                MWExceptionHandler::logException( $e );
                                wfDebugLog(
@@ -1065,23 +1095,19 @@ class ResourceLoader {
                } elseif ( !is_array( $scripts ) ) {
                        throw new MWException( 'Invalid scripts error. Array of URLs or string of code expected.' );
                }
-
-               return Xml::encodeJsCall(
-                       'mw.loader.implement',
-                       array(
-                               $name,
-                               $scripts,
-                               // Force objects. mw.loader.implement requires them to be javascript objects.
-                               // Although these variables are associative arrays, which become javascript
-                               // objects through json_encode. In many cases they will be empty arrays, and
-                               // PHP/json_encode() consider empty arrays to be numerical arrays and
-                               // output javascript "[]" instead of "{}". This fixes that.
-                               (object)$styles,
-                               (object)$messages,
-                               (object)$templates,
-                       ),
-                       ResourceLoader::inDebugMode()
+               // mw.loader.implement requires 'styles', 'messages' and 'templates' to be objects (not
+               // arrays). json_encode considers empty arrays to be numerical and outputs "[]" instead
+               // of "{}". Force them to objects.
+               $module = array(
+                       $name,
+                       $scripts,
+                       (object) $styles,
+                       (object) $messages,
+                       (object) $templates,
                );
+               self::trimArray( $module );
+
+               return Xml::encodeJsCall( 'mw.loader.implement', $module, ResourceLoader::inDebugMode() );
        }
 
        /**
@@ -1188,20 +1214,33 @@ class ResourceLoader {
                );
        }
 
+       private static function isEmptyObject( stdClass $obj ) {
+               foreach ( $obj as $key => &$value ) {
+                       return false;
+               }
+               return true;
+       }
+
        /**
         * Remove empty values from the end of an array.
         *
         * Values considered empty:
         *
         * - null
-        * - empty array
+        * - array()
+        * - new XmlJsCode( '{}' )
+        * - new stdClass() // (object) array()
         *
         * @param Array $array
         */
        private static function trimArray( Array &$array ) {
                $i = count( $array );
                while ( $i-- ) {
-                       if ( $array[$i] === null || $array[$i] === array() ) {
+                       if ( $array[$i] === null
+                               || $array[$i] === array()
+                               || ( $array[$i] instanceof XmlJsCode && $array[$i]->value === '{}' )
+                               || ( $array[$i] instanceof stdClass && self::isEmptyObject( $array[$i] ) )
+                       ) {
                                unset( $array[$i] );
                        } else {
                                break;
@@ -1557,9 +1596,13 @@ class ResourceLoader {
         * @return array Map of variable names to string CSS values.
         */
        public static function getLessVars( Config $config ) {
-               $lessVars = $config->get( 'ResourceLoaderLESSVars' );
-               // Sort by key to ensure consistent hashing for cache lookups.
-               ksort( $lessVars );
-               return $lessVars;
+               if ( !self::$lessVars ) {
+                       $lessVars = $config->get( 'ResourceLoaderLESSVars' );
+                       Hooks::run( 'ResourceLoaderGetLessVars', array( &$lessVars ) );
+                       // Sort by key to ensure consistent hashing for cache lookups.
+                       ksort( $lessVars );
+                       self::$lessVars = $lessVars;
+               }
+               return self::$lessVars;
        }
 }