resourceloader: Return a promise from mw.loader.using()
[lhc/web/wiklou.git] / resources / mediawiki / mediawiki.js
index 1080df3..d8a17f6 100644 (file)
@@ -1052,12 +1052,12 @@ var mw = ( function ( $, undefined ) {
                                        // Can't use jQuery.getScript because that only uses <script> for cross-domain,
                                        // it uses XHR and eval for same-domain scripts, which we don't want because it
                                        // messes up line numbers.
-                                       // The below is based on jQuery ([jquery@1.8.2]/src/ajax/script.js)
+                                       // The below is based on jQuery ([jquery@1.9.1]/src/ajax/script.js)
 
-                                       // IE-safe way of getting the <head>. document.head isn't supported
-                                       // in old IE, and doesn't work when in the <head>.
+                                       // IE-safe way of getting an append target. In old IE document.head isn't supported
+                                       // and its getElementsByTagName can't find <head> until </head> is parsed.
                                        done = false;
-                                       head = document.getElementsByTagName( 'head' )[0] || document.body;
+                                       head = document.head || document.getElementsByTagName( 'head' )[0] || document.documentElement;
 
                                        script = document.createElement( 'script' );
                                        script.async = true;
@@ -1099,7 +1099,9 @@ var mw = ( function ( $, undefined ) {
                                                        document.body.appendChild( script );
                                                } );
                                        } else {
-                                               head.appendChild( script );
+                                               // Circumvent IE6 bugs with base elements (jqbug.com/2709, jqbug.com/4378)
+                                               // by prepending instead of appending.
+                                               head.insertBefore( script, head.firstChild );
                                        }
                                } else {
                                        document.write( mw.html.element( 'script', { 'src': src }, '' ) );
@@ -1730,36 +1732,45 @@ var mw = ( function ( $, undefined ) {
                                 *
                                 * @param {string|Array} dependencies Module name or array of modules names the callback
                                 *  dependends on to be ready before executing
-                                * @param {Function} [ready] callback to execute when all dependencies are ready
-                                * @param {Function} [error] callback to execute when if dependencies have a errors
+                                * @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}
                                 */
                                using: function ( dependencies, ready, error ) {
-                                       var tod = typeof dependencies;
-                                       // Validate input
-                                       if ( tod !== 'object' && tod !== 'string' ) {
-                                               throw new Error( 'dependencies must be a string or an array, not a ' + tod );
-                                       }
+                                       var deferred = $.Deferred();
+
                                        // Allow calling with a single dependency as a string
-                                       if ( tod === 'string' ) {
+                                       if ( typeof dependencies === 'string' ) {
                                                dependencies = [ dependencies ];
+                                       } else if ( !$.isArray( dependencies ) ) {
+                                               // Invalid input
+                                               throw new Error( 'Dependencies must be a string or an array' );
+                                       }
+
+                                       if ( ready ) {
+                                               deferred.done( ready );
+                                       }
+                                       if ( error ) {
+                                               deferred.fail( error );
                                        }
+
                                        // Resolve entire dependency map
                                        dependencies = resolve( dependencies );
                                        if ( allReady( dependencies ) ) {
                                                // Run ready immediately
-                                               if ( $.isFunction( ready ) ) {
-                                                       ready();
-                                               }
+                                               deferred.resolve();
                                        } else if ( filter( ['error', 'missing'], dependencies ).length ) {
                                                // Execute error immediately if any dependencies have errors
-                                               if ( $.isFunction( error ) ) {
-                                                       error( new Error( 'one or more dependencies have state "error" or "missing"' ),
-                                                               dependencies );
-                                               }
+                                               deferred.reject(
+                                                       new Error( 'One or more dependencies failed to load' ),
+                                                       dependencies
+                                               );
                                        } else {
                                                // Not all dependencies are ready: queue up a request
-                                               request( dependencies, ready, error );
+                                               request( dependencies, deferred.resolve, deferred.reject );
                                        }
+
+                                       return deferred.promise();
                                },
 
                                /**
@@ -1989,7 +2000,7 @@ var mw = ( function ( $, undefined ) {
                                         * The try / catch block is used for JSON & localStorage feature detection.
                                         * See the in-line documentation for Modernizr's localStorage feature detection
                                         * code for a full account of why we need a try / catch:
-                                        * https://github.com/Modernizr/Modernizr/blob/v2.7.1/modernizr.js#L771-L796
+                                        * <https://github.com/Modernizr/Modernizr/blob/v2.7.1/modernizr.js#L771-L796>.
                                         */
                                        init: function () {
                                                var raw, data;
@@ -2224,12 +2235,13 @@ var mw = ( function ( $, undefined ) {
                                 * @param {string} name The tag name.
                                 * @param {Object} attrs An object with members mapping element names to values
                                 * @param {Mixed} contents The contents of the element. May be either:
+                                *
                                 *  - string: The string is escaped.
-                                *  - null or undefined: The short closing form is used, e.g. <br/>.
+                                *  - null or undefined: The short closing form is used, e.g. `<br/>`.
                                 *  - this.Raw: The value attribute is included without escaping.
                                 *  - this.Cdata: The value attribute is included, and an exception is
                                 *   thrown if it contains an illegal ETAGO delimiter.
-                                *   See http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.3.2
+                                *   See <http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.3.2>.
                                 */
                                element: function ( name, attrs, contents ) {
                                        var v, attrName, s = '<' + name;