resourceloader: Remove 'require' and 'module' from debug mode
[lhc/web/wiklou.git] / resources / src / mediawiki / mediawiki.js
index b04e01c..9d799db 100644 (file)
                /**
                 * Get a message object.
                 *
-                * Shorcut for `new mw.Message( mw.messages, key, parameters )`.
+                * Shortcut for `new mw.Message( mw.messages, key, parameters )`.
                 *
                 * @see mw.Message
                 * @param {string} key Key of message to get
                         */
 
                        /**
-                        * Write a message the console's warning channel.
+                        * Write a message to the console's warning channel.
                         * Actions not supported by the browser console are silently ignored.
                         *
                         * @param {...string} msg Messages to output to console
                                $.noop;
 
                        /**
-                        * Write a message the console's error channel.
+                        * Write a message to the console's error channel.
                         *
                         * Most browsers provide a stacktrace by default if the argument
                         * is a caught Error object.
                         *             '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 = [],
 
                        /**
                         * A module has entered state 'ready', 'error', or 'missing'. Automatically update
                         * pending jobs and modules that depend upon this module. If the given module failed,
-                        * propagate the 'error' state up the dependency tree. Otherwise, go ahead an execute
+                        * propagate the 'error' state up the dependency tree. Otherwise, go ahead and execute
                         * all jobs/modules now having their dependencies satisfied.
                         *
                         * Jobs that depend on a failed module, will have their error callback ran (if any).
                                } );
                        }
 
+                       /**
+                        * 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.
+                                                               // 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
                                                                // to use string manipulation to undo the function wrapper.
                                                                if ( module === 'user' ) {
                        }
 
                        /**
-                        * Adds a dependencies to the queue with optional callbacks to be run
+                        * Adds all dependencies to the queue with optional callbacks to be run
                         * when the dependencies are ready or fail
                         *
                         * @private
                                        }
                                        // 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,
                                 * When #load or #using requests one or more modules, the server
                                 * response contain calls to this function.
                                 *
-                                * All arguments are required.
-                                *
                                 * @param {string} module Name of module
-                                * @param {Function|Array} script Function with module code or Array of URLs to
+                                * @param {Function|Array} [script] Function with module code or Array of URLs to
                                 *  be used as the src attribute of a new `<script>` tag.
                                 * @param {Object} [style] Should follow one of the following patterns:
                                 *
                                        } );
                                },
 
+                               /**
+                                * 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;
                                         */
                                        clear: function () {
                                                mw.loader.store.items = {};
-                                               localStorage.removeItem( mw.loader.store.getStoreKey() );
+                                               try {
+                                                       localStorage.removeItem( mw.loader.store.getStoreKey() );
+                                               } catch ( ignored ) {}
                                        },
 
                                        /**
        /**
         * Log a message to window.console, if possible.
         *
-        * Useful to force logging of some  errors that are otherwise hard to detect (i.e., this logs
+        * Useful to force logging of some errors that are otherwise hard to detect (i.e., this logs
         * also in production mode). Gets console references in each invocation instead of caching the
         * reference, so that debugging tools loaded later are supported (e.g. Firebug Lite in IE).
         *
                        msg += ( e ? ':' : '.' );
                        console.log( msg );
 
-                       // If we have an exception object, log it to the error channel to trigger a
-                       // proper stacktraces in browsers that support it. No fallback as we have no browsers
-                       // that don't support error(), but do support log().
+                       // If we have an exception object, log it to the error channel to trigger
+                       // proper stacktraces in browsers that support it. No fallback as we have
+                       // no browsers that don't support error(), but do support log().
                        if ( e && console.error ) {
                                console.error( String( e ), e );
                        }