Merge "SpecialAllMessages: Use cached getHtmlCode() instead of wfBCP47()"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 10 Nov 2015 19:08:39 +0000 (19:08 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 10 Nov 2015 19:08:39 +0000 (19:08 +0000)
resources/Resources.php
resources/src/mediawiki/mediawiki.requestIdleCallback.js [new file with mode: 0644]
tests/qunit/QUnitTestResources.php
tests/qunit/suites/resources/mediawiki/mediawiki.requestIdleCallback.test.js [new file with mode: 0644]

index 08c695d..fa04e41 100644 (file)
@@ -826,6 +826,7 @@ return array(
                'scripts' => array(
                        'resources/lib/phpjs-sha1/sha1.js',
                        'resources/src/mediawiki/mediawiki.js',
+                       'resources/src/mediawiki/mediawiki.requestIdleCallback.js',
                        'resources/src/mediawiki/mediawiki.errorLogger.js',
                ),
                'debugScripts' => 'resources/src/mediawiki/mediawiki.log.js',
diff --git a/resources/src/mediawiki/mediawiki.requestIdleCallback.js b/resources/src/mediawiki/mediawiki.requestIdleCallback.js
new file mode 100644 (file)
index 0000000..796639f
--- /dev/null
@@ -0,0 +1,50 @@
+/*!
+ * An interface for scheduling background tasks.
+ *
+ * Loosely based on https://w3c.github.io/requestidlecallback/
+ */
+( function ( mw, $ ) {
+       var tasks = [],
+               maxIdleDuration = 50,
+               timeout = null;
+
+       function schedule( trigger ) {
+               clearTimeout( timeout );
+               timeout = setTimeout( trigger, 700 );
+       }
+
+       function triggerIdle() {
+               var elapsed,
+                       start = mw.now();
+
+               while ( tasks.length ) {
+                       elapsed = mw.now() - start;
+                       if ( elapsed < maxIdleDuration ) {
+                               tasks.shift().callback();
+                       } else {
+                               // Idle moment expired, try again later
+                               schedule( triggerIdle );
+                               break;
+                       }
+               }
+       }
+
+       mw.requestIdleCallbackInternal = function ( callback ) {
+               var task = { callback: callback };
+               tasks.push( task );
+
+               $( function () { schedule( triggerIdle ); } );
+       };
+
+       /**
+        * Schedule a deferred task to run in the background.
+        *
+        * @member mw
+        * @param {Function} callback
+        */
+       mw.requestIdleCallback = window.requestIdleCallback
+               ? function ( callback ) {
+                       window.requestIdleCallback( callback );
+               }
+               : mw.requestIdleCallbackInternal;
+}( mediaWiki, jQuery ) );
index 26c4e08..1db0eeb 100644 (file)
@@ -63,6 +63,7 @@ return array(
                        'tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js',
                        'tests/qunit/suites/resources/jquery/jquery.textSelection.test.js',
                        'tests/qunit/data/mediawiki.jqueryMsg.data.js',
+                       'tests/qunit/suites/resources/mediawiki/mediawiki.requestIdleCallback.test.js',
                        'tests/qunit/suites/resources/mediawiki/mediawiki.errorLogger.test.js',
                        'tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js',
                        'tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js',
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.requestIdleCallback.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.requestIdleCallback.test.js
new file mode 100644 (file)
index 0000000..3772097
--- /dev/null
@@ -0,0 +1,121 @@
+( function ( mw ) {
+       QUnit.module( 'mediawiki.requestIdleCallback', QUnit.newMwEnvironment( {
+               setup: function () {
+                       var time = mw.now(),
+                               clock = this.clock = this.sandbox.useFakeTimers();
+
+                       this.tick = function ( forward ) {
+                               time += forward;
+                               clock.tick( forward );
+                       };
+                       this.sandbox.stub( mw, 'now', function () {
+                               return time;
+                       } );
+
+                       // Don't test the native version (if available)
+                       this.mwRIC = mw.requestIdleCallback;
+                       mw.requestIdleCallback = mw.requestIdleCallbackInternal;
+               },
+               teardown: function () {
+                       mw.requestIdleCallback = this.mwRIC;
+               }
+       } ) );
+
+       // Basic scheduling of callbacks
+       QUnit.test( 'callback', 3, function ( assert ) {
+               var sequence,
+                       tick = this.tick;
+
+               mw.requestIdleCallback( function () {
+                       sequence.push( 'x' );
+                       tick( 30 );
+               } );
+               mw.requestIdleCallback( function () {
+                       tick( 5 );
+                       sequence.push( 'y' );
+                       tick( 30 );
+               } );
+               // Task Z is not run in the first sequence because the
+               // first two tasks consumed the available 50ms budget.
+               mw.requestIdleCallback( function () {
+                       sequence.push( 'z' );
+                       tick( 30 );
+               } );
+
+               sequence = [];
+               tick( 1000 );
+               assert.deepEqual( sequence, [ 'x', 'y' ] );
+
+               sequence = [];
+               tick( 1000 );
+               assert.deepEqual( sequence, [ 'z' ] );
+
+               sequence = [];
+               tick( 1000 );
+               assert.deepEqual( sequence, [] );
+       } );
+
+       // Schedule new callbacks within a callback that tick
+       // the clock. If the budget is exceeded, the newly scheduled
+       // task is delayed until the next idle period.
+       QUnit.test( 'nest-tick', 3, function ( assert ) {
+               var sequence,
+                       tick = this.tick;
+
+               mw.requestIdleCallback( function () {
+                       sequence.push( 'x' );
+                       tick( 30 );
+               } );
+               // Task Y is a task that schedules another task.
+               mw.requestIdleCallback( function () {
+                       function other() {
+                               sequence.push( 'y' );
+                               tick( 35 );
+                       }
+                       mw.requestIdleCallback( other );
+               } );
+               mw.requestIdleCallback( function () {
+                       sequence.push( 'z' );
+                       tick( 30 );
+               } );
+
+               sequence = [];
+               tick( 1000 );
+               assert.deepEqual( sequence, [ 'x', 'z' ] );
+
+               sequence = [];
+               tick( 1000 );
+               assert.deepEqual( sequence, [ 'y' ] );
+
+               sequence = [];
+               tick( 1000 );
+               assert.deepEqual( sequence, [] );
+       } );
+
+       // Schedule new callbacks within a callback that run quickly.
+       // Note how the newly scheduled task gets to run as part of the
+       // current idle period (budget allowing).
+       QUnit.test( 'nest-quick', 2, function ( assert ) {
+               var sequence,
+                       tick = this.tick;
+
+               mw.requestIdleCallback( function () {
+                       sequence.push( 'x' );
+                       mw.requestIdleCallback( function () {
+                               sequence.push( 'x-expand' );
+                       } );
+               } );
+               mw.requestIdleCallback( function () {
+                       sequence.push( 'y' );
+               } );
+
+               sequence = [];
+               tick( 1000 );
+               assert.deepEqual( sequence, [ 'x', 'y', 'x-expand' ] );
+
+               sequence = [];
+               tick( 1000 );
+               assert.deepEqual( sequence, [] );
+       } );
+
+}( mediaWiki ) );