resourceloader: Return a promise from mw.loader.using()
authorHelder.wiki <helder.wiki@gmail.com>
Tue, 23 Jul 2013 21:21:30 +0000 (18:21 -0300)
committerTimo Tijhof <krinklemail@gmail.com>
Fri, 28 Mar 2014 01:24:02 +0000 (18:24 -0700)
This implements support for:

    mw.loader.using( 'foo' ).done( callback );

Cleanup:
- Validate array input using $.isArray
- Simplify code

Change-Id: I9e145cfde24f582b123707ed20cb0fca60fccb2c

RELEASE-NOTES-1.23
resources/mediawiki/mediawiki.js
tests/qunit/suites/resources/mediawiki/mediawiki.test.js

index cd445a7..92e94ed 100644 (file)
@@ -134,6 +134,7 @@ production.
   installer has been updated to use it.
 * Changes to content typography (fonts, line-height, etc.). See
   https://www.mediawiki.org/wiki/Typography_refresh for further information.
+* ResourceLoader: mw.loader.using() now implements a Promise interface.
 
 === Bug fixes in 1.23 ===
 * (bug 41759) The "updated since last visit" markers (on history pages, recent
index 85e32e8..d8a17f6 100644 (file)
@@ -1732,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();
                                },
 
                                /**
index 441fcbc..f5091f9 100644 (file)
                } );
        } );
 
+       QUnit.asyncTest( 'mw.loader.using( .. ).promise', 2, function ( assert ) {
+               var isAwesomeDone;
+
+               mw.loader.testCallback = function () {
+                       QUnit.start();
+                       assert.strictEqual( isAwesomeDone, undefined, 'Implementing module is.awesome: isAwesomeDone should still be undefined' );
+                       isAwesomeDone = true;
+               };
+
+               mw.loader.implement( 'test.promise', [QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/callMwLoaderTestCallback.js' )], {}, {} );
+
+               mw.loader.using( 'test.promise' )
+               .done( function () {
+
+                       // /sample/awesome.js declares the "mw.loader.testCallback" function
+                       // which contains a call to start() and ok()
+                       assert.strictEqual( isAwesomeDone, true, 'test.promise module should\'ve caused isAwesomeDone to be true' );
+                       delete mw.loader.testCallback;
+
+               } )
+               .fail( function () {
+                       QUnit.start();
+                       assert.ok( false, 'Error callback fired while loader.using "test.promise" module' );
+               } );
+       } );
+
        QUnit.asyncTest( 'mw.loader.implement( styles={ "css": [text, ..] } )', 2, function ( assert ) {
                var $element = $( '<div class="mw-test-implement-a"></div>' ).appendTo( '#qunit-fixture' );