resoureloader: Restore support for plain callbacks in mediawiki.base's RLQ
authorTimo Tijhof <krinklemail@gmail.com>
Fri, 26 Oct 2018 21:33:26 +0000 (14:33 -0700)
committerTimo Tijhof <krinklemail@gmail.com>
Fri, 26 Oct 2018 21:33:26 +0000 (14:33 -0700)
Follows-up dec800968e, which moved the processing of callbacks that require
'modules' from startup.js to mediawiki.base.js.

In doing so, it made an incorrect assumption. It assumed that the simple
signature of RLQ.push(Function) is not needed after 'mediawiki.base' loads.

It is true that RLQ.push() is mostly an internal interface, and we only
use it from within the HTML output, and that once the async pipeline has
finished and startup.js has processed the simple callbacks, only calls with
secondary signatures remain in the queue.

But, while it is true that we don't use RLQ.push() outside the HTML, it is
not true that the HTML will fully load and execute inline scripts before
any of the async scripts execute. As such, the call to RLQ.push() in the
HTML footer was sometimes being ignored because 'mediawiki.base' had already
loaded by now.

Bug: T208093
Change-Id: I25012a2c6f41968b1b4f85614a3bc0416512d530

resources/src/mediawiki.base/mediawiki.base.js
resources/src/startup/startup.js
tests/qunit/suites/resources/mediawiki/mediawiki.base.test.js

index 5820b83..8a44dcc 100644 (file)
        mw.log.deprecate( window, '$j', $, 'Use $ or jQuery instead.' );
 
        // Process callbacks for Grade A that require modules.
-       // Plain ones were already processed by startup.js.
        queue = window.RLQ;
-       // Redefine publicly to capture any late arrivals
+       // Replace temporary RLQ implementation from startup.js with the
+       // final implementation that also processes callbacks that can
+       // require modules. It must also support late arrivals of
+       // plain callbacks. (T208093)
        window.RLQ = {
                push: function ( entry ) {
-                       mw.loader.using( entry[ 0 ], entry[ 1 ] );
+                       if ( typeof entry === 'function' ) {
+                               entry();
+                       } else {
+                               mw.loader.using( entry[ 0 ], entry[ 1 ] );
+                       }
                }
        };
        while ( queue[ 0 ] ) {
index 5483ad2..bebf4dc 100644 (file)
@@ -118,9 +118,10 @@ if ( !isCompatible() ) {
                mw.config.set( $VARS.configuration );
 
                // Process callbacks for Grade A
-               // Must be after registrations and mw.config.set, which mw.loader depends on.
                var queue = window.RLQ;
-               // Redefine push(), but keep type as array for storing callbacks that require modules.
+               // Replace RLQ placeholder from ResourceLoaderClientHtml with an implementation
+               // that executes simple callbacks, but continues to store callbacks that require
+               // modules.
                window.RLQ = [];
                /* global RLQ */
                RLQ.push = function ( fn ) {
@@ -132,7 +133,7 @@ if ( !isCompatible() ) {
                        }
                };
                while ( queue && queue[ 0 ] ) {
-                       // Re-use our push()
+                       // Re-use our new push() method
                        RLQ.push( queue.shift() );
                }
 
index 33423d8..b8f0d12 100644 (file)
        QUnit.test( 'RLQ.push', function ( assert ) {
                /* global RLQ */
                var loaded = 0,
+                       called = 0,
                        done = assert.async();
                mw.loader.testCallback = function () {
                        loaded++;
                        delete mw.loader.testCallback;
                };
-               mw.loader.implement( 'test.rlq-push', [ QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/mwLoaderTestCallback.js' ) ] );
+               mw.loader.implement( 'test.rlq-push', [
+                       QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/mwLoaderTestCallback.js' )
+               ] );
+
+               // Regression test for T208093
+               RLQ.push( function () {
+                       called++;
+               } );
+               assert.strictEqual( called, 1, 'Invoke plain callbacks' );
 
                RLQ.push( [ 'test.rlq-push', function () {
                        assert.strictEqual( loaded, 1, 'Load the required module' );