resourceloader: Add getScript() method for loading scripts with callback
authorEvad37 <evad37@gmail.com>
Sat, 2 Feb 2019 05:42:00 +0000 (13:42 +0800)
committerEvad37 <evad37@gmail.com>
Tue, 26 Feb 2019 01:12:22 +0000 (09:12 +0800)
Provides a friendly wrapper for loading scripts using $.ajax().
Returns a promise when the script dependency -- a single
script url -- has been loaded. This matches how mw.loader.load
is able to load a script url, and how mw.loader.using will
return a promised that is resolved when dependecies are loaded,
or rejected if there is an error.

Added as a separate function mw.loader.getScript(), rather
than adding this functionality to using(), as it is a separate
use case, less confusing for users, and there is no shared or
duplicated code between loading a script and loading one
or more named modules.

Bug: T27962
Change-Id: I13be426d03261a2d0c6a1631af94a9f9af58394b

resources/src/mediawiki.base/mediawiki.base.js
tests/qunit/data/mediawiki.loader.getScript.example.js [new file with mode: 0644]
tests/qunit/suites/resources/mediawiki/mediawiki.loader.test.js

index 107ab33..9016c7c 100644 (file)
                var deferred = $.Deferred();
 
                // Allow calling with a single dependency as a string
-               if ( typeof dependencies === 'string' ) {
+               if ( !Array.isArray( dependencies ) ) {
                        dependencies = [ dependencies ];
                }
 
                        return deferred.reject( e ).promise();
                }
 
-               mw.loader.enqueue( dependencies, function () {
-                       deferred.resolve( mw.loader.require );
-               }, deferred.reject );
+               mw.loader.enqueue(
+                       dependencies,
+                       function () { deferred.resolve( mw.loader.require ); },
+                       deferred.reject
+               );
 
                return deferred.promise();
        };
 
+       /**
+        * Load a script by URL.
+        *
+        * Example:
+        *
+        *     mw.loader.getScript(
+        *         'https://example.org/x-1.0.0.js'
+        *     )
+        *         .then( function () {
+        *             // Script succeeded. You can use X now.
+        *         }, function ( e ) {
+        *             // Script failed. X is not avaiable
+        *             mw.log.error( e.message ); // => "Failed to load script"
+        *         } );
+        *     } );
+        *
+        * @member mw.loader
+        * @param {string} url Script URL
+        * @return {jQuery.Promise} Resolved when the script is loaded
+        */
+       mw.loader.getScript = function ( url ) {
+               return $.ajax( url, { dataType: 'script', cache: true } )
+                       .catch( function () {
+                               throw new Error( 'Failed to load script' );
+                       } );
+       };
+
        // Alias $j to jQuery for backwards compatibility
        // @deprecated since 1.23 Use $ or jQuery instead
        mw.log.deprecate( window, '$j', $, 'Use $ or jQuery instead.' );
diff --git a/tests/qunit/data/mediawiki.loader.getScript.example.js b/tests/qunit/data/mediawiki.loader.getScript.example.js
new file mode 100644 (file)
index 0000000..e5e4759
--- /dev/null
@@ -0,0 +1 @@
+mw.getScriptExampleScriptLoaded = true;
index cb028a9..8b06bd6 100644 (file)
@@ -24,6 +24,7 @@
                        // exposed for cross-file mocks.
                        delete mw.loader.testCallback;
                        delete mw.loader.testFail;
+                       delete mw.getScriptExampleScriptLoaded;
                }
        } ) );
 
                } );
        } );
 
+       QUnit.test( '.getScript() - success', function ( assert ) {
+               var scriptUrl = QUnit.fixurl(
+                       mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/mediawiki.loader.getScript.example.js'
+               );
+
+               return mw.loader.getScript( scriptUrl ).then(
+                       function () {
+                               assert.strictEqual( mw.getScriptExampleScriptLoaded, true, 'Data attached to a global object is available' );
+                       }
+               );
+       } );
+
+       QUnit.test( '.getScript() - failure', function ( assert ) {
+               assert.rejects(
+                       mw.loader.getScript( 'https://example.test/not-found' ),
+                       /Failed to load script/,
+                       'Descriptive error message'
+               );
+       } );
+
 }() );