Merge "Move MediaHandler defaults out of global scope"
[lhc/web/wiklou.git] / resources / src / mediawiki / mediawiki.js
index 8d42b98..3600000 100644 (file)
@@ -8,7 +8,6 @@
  * @singleton
  */
 /*jshint latedef:false */
-/*global sha1 */
 ( function ( $ ) {
        'use strict';
 
                trackHandlers = [],
                trackQueue = [];
 
+       /**
+        * FNV132 hash function
+        *
+        * This function implements the 32-bit version of FNV-1.
+        * It is equivalent to hash( 'fnv132', ... ) in PHP, except
+        * its output is base 36 rather than hex.
+        * See <https://en.wikipedia.org/wiki/FNV_hash_function>
+        *
+        * @private
+        * @param {string} str String to hash
+        * @return {string} hash as an seven-character base 36 string
+        */
+       function fnv132( str ) {
+               /*jshint bitwise:false */
+               var hash = 0x811C9DC5,
+                       i;
+
+               for ( i = 0; i < str.length; i++ ) {
+                       hash += ( hash << 1 ) + ( hash << 4 ) + ( hash << 7 ) + ( hash << 8 ) + ( hash << 24 );
+                       hash ^= str.charCodeAt( i );
+               }
+
+               hash = ( hash >>> 0 ).toString( 36 );
+               while ( hash.length < 7 ) {
+                       hash = '0' + hash;
+               }
+
+               return hash;
+       }
+
        /**
         * Create an object that can be read from or written to from methods that allow
         * interaction both with single and multiple properties at once.
                        log.deprecate = !Object.defineProperty ? function ( obj, key, val ) {
                                obj[ key ] = val;
                        } : function ( obj, key, val, msg ) {
+                               /*globals Set */
                                msg = 'Use of "' + key + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' );
+                               var logged, loggedIsSet, uniqueTrace;
+                               if ( window.Set ) {
+                                       logged = new Set();
+                                       loggedIsSet = true;
+                               } else {
+                                       logged = {};
+                                       loggedIsSet = false;
+                               }
+                               uniqueTrace = function () {
+                                       var trace = new Error().stack;
+                                       if ( loggedIsSet ) {
+                                               if ( logged.has( trace ) ) {
+                                                       return false;
+                                               }
+                                               logged.add( trace );
+                                               return true;
+                                       } else {
+                                               if ( logged.hasOwnProperty( trace ) ) {
+                                                       return false;
+                                               }
+                                               logged[ trace ] = 1;
+                                               return true;
+                                       }
+                               };
                                Object.defineProperty( obj, key, {
                                        configurable: true,
                                        enumerable: true,
                                        get: function () {
-                                               mw.track( 'mw.deprecate', key );
-                                               mw.log.warn( msg );
+                                               if ( uniqueTrace() ) {
+                                                       mw.track( 'mw.deprecate', key );
+                                                       mw.log.warn( msg );
+                                               }
                                                return val;
                                        },
                                        set: function ( newVal ) {
-                                               mw.track( 'mw.deprecate', key );
-                                               mw.log.warn( msg );
+                                               if ( uniqueTrace() ) {
+                                                       mw.track( 'mw.deprecate', key );
+                                                       mw.log.warn( msg );
+                                               }
                                                val = newVal;
                                        }
                                } );
                                var hashes = $.map( modules, function ( module ) {
                                        return registry[ module ].version;
                                } );
-                               // Trim for consistency with server-side ResourceLoader::makeHash. It also helps
-                               // save precious space in the limited query string. Otherwise modules are more
-                               // likely to require multiple HTTP requests.
-                               return sha1( hashes.join( '' ) ).slice( 0, 12 );
+                               return fnv132( hashes.join( '' ) );
                        }
 
                        /**
                                 *         OO.compare( [ 1 ], [ 1 ] );
                                 *     } );
                                 *
-                                * @param {string|Array} dependencies Module name or array of modules names the callback
-                                *  dependends on to be ready before executing
+                                * @param {string|Array} dependencies Module name or array of modules names the
+                                *  callback depends on to be ready before executing
                                 * @param {Function} [ready] Callback to execute when all dependencies are ready
                                 * @param {Function} [error] Callback to execute if one or more dependencies failed
                                 * @return {jQuery.Promise}
                                require: function ( moduleName ) {
                                        var state = mw.loader.getState( moduleName );
 
-                                       // Only ready mudules can be required
+                                       // Only ready modules can be required
                                        if ( state !== 'ready' ) {
                                                // Module may've forgotten to declare a dependency
                                                throw new Error( 'Module "' + moduleName + '" is not loaded.' );