From: Timo Tijhof Date: Wed, 11 Sep 2019 04:46:50 +0000 (+0100) Subject: mediawiki.util: Add debounce() function X-Git-Tag: 1.34.0-rc.0~259^2 X-Git-Url: http://git.cyclocoop.org/%22%20.%20generer_url_aide%28?a=commitdiff_plain;h=a6827329000ec584a2614a167c79616c08c21ce7;p=lhc%2Fweb%2Fwiklou.git mediawiki.util: Add debounce() function Bug: T213426 Change-Id: If370b959b2617d0f506ac3ed344af8c6a667e70d --- diff --git a/resources/Resources.php b/resources/Resources.php index 80770221f8..0960e83961 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -940,6 +940,9 @@ return [ 'scripts' => [ 'resources/src/mediawiki.htmlform.checker.js', ], + 'dependencies' => [ + 'mediawiki.util', + ], 'targets' => [ 'desktop', 'mobile' ], ], 'mediawiki.htmlform.ooui' => [ diff --git a/resources/src/mediawiki.htmlform.checker.js b/resources/src/mediawiki.htmlform.checker.js index 33207d49a7..473635a53e 100644 --- a/resources/src/mediawiki.htmlform.checker.js +++ b/resources/src/mediawiki.htmlform.checker.js @@ -3,14 +3,6 @@ // FIXME: mw.htmlform.Element also sets this to empty object mw.htmlform = {}; - function debounce( delay, callback ) { - var timeout; - return function () { - clearTimeout( timeout ); - timeout = setTimeout( Function.prototype.apply.bind( callback, this, arguments ), delay ); - }; - } - /** * @class mw.htmlform.Checker */ @@ -60,7 +52,7 @@ if ( $extraElements ) { $e = $e.add( $extraElements ); } - $e.on( events, debounce( 1000, this.validate.bind( this ) ) ); + $e.on( events, mw.util.debounce( 1000, this.validate.bind( this ) ) ); return this; }; diff --git a/resources/src/mediawiki.util/util.js b/resources/src/mediawiki.util/util.js index 57843cb976..85216649e0 100644 --- a/resources/src/mediawiki.util/util.js +++ b/resources/src/mediawiki.util/util.js @@ -83,6 +83,27 @@ util = { return escapeIdInternal( str, config.FragmentMode[ 0 ] ); }, + /** + * Return a wrapper function that is debounced for the given duration. + * + * When it is first called, a timeout is scheduled. If before the timer + * is reached the wrapper is called again, it gets rescheduled for the + * same duration from now until it stops being called. The original function + * is called from the "tail" of such chain, with the last set of arguments. + * + * @since 1.34 + * @param {number} delay Time in milliseconds + * @param {Function} callback + * @return {Function} + */ + debounce: function ( delay, callback ) { + var timeout; + return function () { + clearTimeout( timeout ); + timeout = setTimeout( Function.prototype.apply.bind( callback, this, arguments ), delay ); + }; + }, + /** * Encode page titles for use in a URL * diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js index 4f61abd186..a05b50b462 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js @@ -474,4 +474,27 @@ assert.strictEqual( mw.util.escapeRegExp( normal ), normal, 'Alphanumerals are left alone' ); } ); + + QUnit.test( 'debounce', function ( assert ) { + var fn, + q = [], + done = assert.async(); + + fn = mw.util.debounce( 0, function ( data ) { + q.push( data ); + } ); + + fn( 1 ); + fn( 2 ); + fn( 3 ); + + setTimeout( function () { + assert.deepEqual( + q, + [ 3 ], + 'Last one ran' + ); + done(); + } ); + } ); }() );