Merge "Add part to update ctd_user_defined in populateChangeTagDef"
[lhc/web/wiklou.git] / resources / src / startup / mediawiki.js
index 30f3bff..ba8869b 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * Base library for MediaWiki.
  *
- * Exposed globally as `mediaWiki` with `mw` as shortcut.
+ * Exposed globally as `mw`, with `mediaWiki` as alias.
  *
  * @class mw
  * @alternateClassName mediaWiki
                log.deprecate = !Object.defineProperty ? function ( obj, key, val ) {
                        obj[ key ] = val;
                } : function ( obj, key, val, msg, logName ) {
-                       var logged = new StringSet();
-                       logName = logName || key;
-                       msg = 'Use of "' + logName + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' );
-                       function uniqueTrace() {
-                               var trace = new Error().stack;
-                               if ( logged.has( trace ) ) {
-                                       return false;
+                       var stacks;
+                       function maybeLog() {
+                               var name,
+                                       trace = new Error().stack;
+                               if ( !stacks ) {
+                                       stacks = new StringSet();
+                               }
+                               if ( !stacks.has( trace ) ) {
+                                       stacks.add( trace );
+                                       name = logName || key;
+                                       mw.track( 'mw.deprecate', name );
+                                       mw.log.warn(
+                                               'Use of "' + name + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' )
+                                       );
                                }
-                               logged.add( trace );
-                               return true;
                        }
                        // Support: Safari 5.0
                        // Throws "not supported on DOM Objects" for Node or Element objects (incl. document)
                                        configurable: true,
                                        enumerable: true,
                                        get: function () {
-                                               if ( uniqueTrace() ) {
-                                                       mw.track( 'mw.deprecate', logName );
-                                                       mw.log.warn( msg );
-                                               }
+                                               maybeLog();
                                                return val;
                                        },
                                        set: function ( newVal ) {
-                                               if ( uniqueTrace() ) {
-                                                       mw.track( 'mw.deprecate', logName );
-                                                       mw.log.warn( msg );
-                                               }
+                                               maybeLog();
                                                val = newVal;
                                        }
                                } );
                /**
                 * Get the current time, measured in milliseconds since January 1, 1970 (UTC).
                 *
-                * On browsers that implement the Navigation Timing API, this function will produce floating-point
-                * values with microsecond precision that are guaranteed to be monotonic. On all other browsers,
-                * it will fall back to using `Date`.
+                * On browsers that implement the Navigation Timing API, this function will produce
+                * floating-point values with microsecond precision that are guaranteed to be monotonic.
+                * On all other browsers, it will fall back to using `Date`.
                 *
                 * @return {number} Current time
                 */
-               now: ( function () {
+               now: function () {
+                       // Optimisation: Define the shortcut on first call, not at module definition.
                        var perf = window.performance,
                                navStart = perf && perf.timing && perf.timing.navigationStart;
-                       return navStart && typeof perf.now === 'function' ?
+
+                       // Define the relevant shortcut
+                       mw.now = navStart && typeof perf.now === 'function' ?
                                function () { return navStart + perf.now(); } :
-                               function () { return Date.now(); };
-               }() ),
+                               Date.now;
+
+                       return mw.now();
+               },
 
                /**
                 * List of all analytic events emitted so far.
                        /**
                         * Resolve indexed dependencies.
                         *
-                        * ResourceLoader uses an optimization to save space which replaces module names in
+                        * ResourceLoader uses an optimisation to save space which replaces module names in
                         * dependency lists with the index of that module within the array of module
                         * registration data if it exists. The benefit is a significant reduction in the data
                         * size of the startup module. This function changes those dependency lists back to
                                };
                        }
 
+                       /**
+                        * @private
+                        * @param {string} module
+                        * @param {string|number} [version]
+                        * @param {string[]} [dependencies]
+                        * @param {string} [group]
+                        * @param {string} [source]
+                        * @param {string} [skip]
+                        */
+                       function registerOne( module, version, dependencies, group, source, skip ) {
+                               if ( hasOwn.call( registry, module ) ) {
+                                       throw new Error( 'module already registered: ' + module );
+                               }
+                               registry[ module ] = {
+                                       // Exposed to execute() for mw.loader.implement() closures.
+                                       // Import happens via require().
+                                       module: {
+                                               exports: {}
+                                       },
+                                       version: String( version || '' ),
+                                       dependencies: dependencies || [],
+                                       group: typeof group === 'string' ? group : null,
+                                       source: typeof source === 'string' ? source : 'local',
+                                       state: 'registered',
+                                       skip: typeof skip === 'string' ? skip : null
+                               };
+                       }
+
                        /* Public Members */
                        return {
                                /**
                                /**
                                 * Start loading of all queued module dependencies.
                                 *
-                                * @protected
+                                * @private
                                 */
                                work: function () {
                                        var q, batch, implementations, sourceModules;
                                 *
                                 * The #work() method will use this information to split up requests by source.
                                 *
-                                *     mw.loader.addSource( 'mediawikiwiki', '//www.mediawiki.org/w/load.php' );
+                                *     mw.loader.addSource( { mediawikiwiki: 'https://www.mediawiki.org/w/load.php' } );
                                 *
-                                * @param {string|Object} id Source ID, or object mapping ids to load urls
-                                * @param {string} loadUrl Url to a load.php end point
+                                * @private
+                                * @param {Object} ids An object mapping ids to load.php end point urls
                                 * @throws {Error} If source id is already registered
                                 */
-                               addSource: function ( id, loadUrl ) {
-                                       var source;
-                                       // Allow multiple additions
-                                       if ( typeof id === 'object' ) {
-                                               for ( source in id ) {
-                                                       mw.loader.addSource( source, id[ source ] );
+                               addSource: function ( ids ) {
+                                       var id;
+                                       for ( id in ids ) {
+                                               if ( hasOwn.call( sources, id ) ) {
+                                                       throw new Error( 'source already registered: ' + id );
                                                }
-                                               return;
-                                       }
-
-                                       if ( hasOwn.call( sources, id ) ) {
-                                               throw new Error( 'source already registered: ' + id );
+                                               sources[ id ] = ids[ id ];
                                        }
-
-                                       sources[ id ] = loadUrl;
                                },
 
                                /**
                                 * Register a module, letting the system know about it and its properties.
                                 *
-                                * The startup modules contain calls to this method.
+                                * The startup module calls this method.
                                 *
                                 * When using multiple module registration by passing an array, dependencies that
                                 * are specified as references to modules within the array will be resolved before
                                 * the modules are registered.
                                 *
-                                * @param {string|Array} module Module name or array of arrays, each containing
+                                * @param {string|Array} modules Module name or array of arrays, each containing
                                 *  a list of arguments compatible with this method
-                                * @param {string|number} version Module version hash (falls backs to empty string)
+                                * @param {string|number} [version] Module version hash (falls backs to empty string)
                                 *  Can also be a number (timestamp) for compatibility with MediaWiki 1.25 and earlier.
                                 * @param {string[]} [dependencies] Array of module names on which this module depends.
                                 * @param {string} [group=null] Group which the module is in
                                 * @param {string} [source='local'] Name of the source
                                 * @param {string} [skip=null] Script body of the skip function
                                 */
-                               register: function ( module, version, dependencies, group, source, skip ) {
+                               register: function ( modules ) {
                                        var i;
-                                       // Allow multiple registration
-                                       if ( typeof module === 'object' ) {
-                                               resolveIndexedDependencies( module );
-                                               for ( i = 0; i < module.length; i++ ) {
-                                                       // module is an array of module names
-                                                       if ( typeof module[ i ] === 'string' ) {
-                                                               mw.loader.register( module[ i ] );
-                                                       // module is an array of arrays
-                                                       } else if ( typeof module[ i ] === 'object' ) {
-                                                               mw.loader.register.apply( mw.loader, module[ i ] );
-                                                       }
+                                       if ( typeof modules === 'object' ) {
+                                               resolveIndexedDependencies( modules );
+                                               // Optimisation: Up to 55% faster.
+                                               // Typically called only once, and with a batch.
+                                               // See <https://gist.github.com/Krinkle/f06fdb3de62824c6c16f02a0e6ce0e66>
+                                               // Benchmarks taught us that the code for adding an object to `registry`
+                                               // should actually be inline, or in a simple function that does no
+                                               // arguments manipulation, and isn't also the caller itself.
+                                               // JS semantics make it hard to optimise recursion to a different
+                                               // signature of itself.
+                                               for ( i = 0; i < modules.length; i++ ) {
+                                                       registerOne.apply( null, modules[ i ] );
                                                }
-                                               return;
+                                       } else {
+                                               registerOne.apply( null, arguments );
                                        }
-                                       if ( hasOwn.call( registry, module ) ) {
-                                               throw new Error( 'module already registered: ' + module );
-                                       }
-                                       // List the module as registered
-                                       registry[ module ] = {
-                                               // Exposed to execute() for mw.loader.implement() closures.
-                                               // Import happens via require().
-                                               module: {
-                                                       exports: {}
-                                               },
-                                               version: String( version || '' ),
-                                               dependencies: dependencies || [],
-                                               group: typeof group === 'string' ? group : null,
-                                               source: typeof source === 'string' ? source : 'local',
-                                               state: 'registered',
-                                               skip: typeof skip === 'string' ? skip : null
-                                       };
                                },
 
                                /**
                                 * The reason css strings are not concatenated anymore is T33676. We now check
                                 * whether it's safe to extend the stylesheet.
                                 *
-                                * @protected
+                                * @private
                                 * @param {Object} [messages] List of key/value pairs to be added to mw#messages.
                                 * @param {Object} [templates] List of key/value pairs to be added to mw#templates.
                                 */
                                                mw.loader.register( name );
                                        }
                                        // Check for duplicate implementation
-                                       if ( hasOwn.call( registry, name ) && registry[ name ].script !== undefined ) {
+                                       if ( registry[ name ].script !== undefined ) {
                                                throw new Error( 'module already implemented: ' + name );
                                        }
                                        if ( version ) {
                                                        // 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 ) ||
+                                                       /Firefox/.test( navigator.userAgent ) ||
 
                                                        // Disabled by configuration.
                                                        !mw.config.get( 'wgResourceLoaderStorageEnabled' )