Merge "Improve cache assertions in WatchedItemStoreUnitTest"
[lhc/web/wiklou.git] / resources / src / mediawiki / mediawiki.js
index 90b93dc..9d799db 100644 (file)
                         *             'group': 'somegroup', (or) null
                         *             'source': 'local', (or) 'anotherwiki'
                         *             'skip': 'return !!window.Example', (or) null
+                        *             'module': export Object
                         *
                         *             // Set from execute() or mw.loader.state()
                         *             'state': 'registered', 'loaded', 'loading', 'ready', 'error', or 'missing'
                                // List of modules which will be loaded as when ready
                                batch = [],
 
+                               // Pending queueModuleScript() requests
+                               handlingPendingRequests = false,
+                               pendingRequests = [],
+
                                // List of modules to be loaded
                                queue = [],
 
                                } );
                        }
 
+                       /**
+                        * Queue the loading and execution of a script for a particular module.
+                        *
+                        * @private
+                        * @param {string} src URL of the script
+                        * @param {string} [moduleName] Name of currently executing module
+                        * @return {jQuery.Promise}
+                        */
+                       function queueModuleScript( src ) {
+                               var r = $.Deferred();
+
+                               pendingRequests.push( function () {
+                                       addScript( src ).always( function () {
+                                               r.resolve();
+
+                                               // Start the next one (if any)
+                                               if ( pendingRequests[ 0 ] ) {
+                                                       pendingRequests.shift()();
+                                               } else {
+                                                       handlingPendingRequests = false;
+                                               }
+                                       } );
+                               } );
+                               if ( !handlingPendingRequests && pendingRequests[ 0 ] ) {
+                                       handlingPendingRequests = true;
+                                       pendingRequests.shift()();
+                               }
+                               return r.promise();
+                       }
+
                        /**
                         * Utility function for execute()
                         *
                                                        handlePending( module );
                                                };
                                                nestedAddScript = function ( arr, callback, i ) {
-                                                       // Recursively call addScript() in its own callback
+                                                       // Recursively call queueModuleScript() in its own callback
                                                        // for each element of arr.
                                                        if ( i >= arr.length ) {
                                                                // We're at the end of the array
                                                                return;
                                                        }
 
-                                                       addScript( arr[ i ] ).always( function () {
+                                                       queueModuleScript( arr[ i ], module ).always( function () {
                                                                nestedAddScript( arr, callback, i + 1 );
                                                        } );
                                                };
                                                        } else if ( $.isFunction( script ) ) {
                                                                // Pass jQuery twice so that the signature of the closure which wraps
                                                                // the script can bind both '$' and 'jQuery'.
-                                                               script( $, $ );
+                                                               script( $, $, mw.loader.require, registry[ module ].module );
                                                                markModuleReady();
+
                                                        } else if ( typeof script === 'string' ) {
                                                                // Site and user modules are legacy scripts that run in the global scope.
                                                                // This is transported as a string instead of a function to avoid needing
                                        }
                                        // List the module as registered
                                        registry[ module ] = {
+                                               // Exposed to execute() for mw.loader.implement() closures.
+                                               // Import happens via require().
+                                               module: {
+                                                       exports: {}
+                                               },
                                                version: version !== undefined ? String( version ) : '',
                                                dependencies: [],
                                                group: typeof group === 'string' ? group : null,
                                        } );
                                },
 
+                               /**
+                                * Get the exported value of a module.
+                                *
+                                * Module provide this value via their local `module.exports`.
+                                *
+                                * @since 1.27
+                                * @return {Array}
+                                */
+                               require: function ( moduleName ) {
+                                       var state = mw.loader.getState( moduleName );
+
+                                       // Only ready mudules can be required
+                                       if ( state !== 'ready' ) {
+                                               // Module may've forgotten to declare a dependency
+                                               throw new Error( 'Module "' + moduleName + '" is not loaded.' );
+                                       }
+
+                                       return registry[ moduleName ].module.exports;
+                               },
+
                                /**
                                 * @inheritdoc mw.inspect#runReports
                                 * @method
                                        // Whether the store is in use on this page.
                                        enabled: null,
 
-                                       // Modules whose string representation exceeds 100 kB (30 kB on FF) are
-                                       // ineligible for storage due to bug T66721. The quota is stricter on
-                                       // Firefox due to <https://bugzilla.mozilla.org/show_bug.cgi?id=1064466>.
-                                       MODULE_SIZE_MAX: ( /Firefox/.test( navigator.userAgent ) ? 30 : 100 ) * 1000,
+                                       MODULE_SIZE_MAX: 100 * 1000,
 
                                        // The contents of the store, mapping '[module name]@[version]' keys
                                        // to module implementations.
                                                        return;
                                                }
 
-                                               if ( !mw.config.get( 'wgResourceLoaderStorageEnabled' ) ) {
+                                               if (
+                                                       // Disabled because localStorage quotas are tight and (in Firefox's case)
+                                                       // shared by multiple origins.
+                                                       // See T66721, and <https://bugzilla.mozilla.org/show_bug.cgi?id=1064466>.
+                                                       /Firefox|Opera/.test( navigator.userAgent ) ||
+
                                                        // Disabled by configuration.
+                                                       !mw.config.get( 'wgResourceLoaderStorageEnabled' )
+                                               ) {
                                                        // Clear any previous store to free up space. (T66721)
                                                        mw.loader.store.clear();
                                                        mw.loader.store.enabled = false;