From 14bfa1c2405cca15d259c6bbb17174fdb57608f8 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 22 May 2018 11:02:05 +0200 Subject: [PATCH 01/10] Added throttle function. --- core/tools.js | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/core/tools.js b/core/tools.js index a4487f772e4..c046eb3fd9d 100644 --- a/core/tools.js +++ b/core/tools.js @@ -579,6 +579,90 @@ }, milliseconds || 0 ); }, + /** + * Throttles `input` events (or any `input` calls) + * and triggers `output` not more often than once per `minInterval`. + * + * After each `input` scheduled `output` will be destroyed and replaced with + * new one. It gives you the opportunity to modify passed parameters into `input` function and get + * different results. + * + * var buffer = CKEDITOR.tools.throttle( 200, function( message ) { + * console.log( message ); + * } ); + * + * buffer.input( 'foo!' ); + * // 'foo!' logged immediately. + * buffer.input( 'buz!' ); + * // Nothing logged. + * buffer.input( 'bar!' ); + * // Nothing logged. + * // ... after 200ms a single 'bar!' will be logged. + * + * Can be easily used with events: + * + * var buffer = CKEDITOR.tools.throttle( 200, function( evt ) { + * console.log( evt.data.text ); + * } ); + * + * editor.on( 'key', buffer.input ); + * // Note: There is no need to bind buffer as a context. + * + * @since 4.10.0 + * @param {Number} minInterval Minimum interval between `output` calls in milliseconds. + * @param {Function} output Function that will be executed as `output`. + * @param {Object} [scopeObj] The object used to scope the listener call (the `this` object). + * @returns {Object} + * @returns {Function} return.input Buffer's input method. + * Accepts parameters which will be directly passed into `output` function. + * @returns {Function} return.reset Resets buffered events — `output` will not be executed + * until next `input` is triggered. + */ + throttle: function( minInterval, output, scopeObj ) { + var scheduled, + lastOutput = 0; + + scopeObj = scopeObj || {}; + + return { + input: input, + reset: reset + }; + + function input() { + var args = Array.prototype.slice.call( arguments ); + + if ( scheduled ) { + clearTimeout( scheduled ); + scheduled = 0; + } + + var diff = ( new Date() ).getTime() - lastOutput; + + // If less than minInterval passed after last check, + // schedule next for minInterval after previous one. + if ( diff < minInterval ) { + scheduled = setTimeout( triggerOutput, minInterval - diff ); + } else { + triggerOutput(); + } + + function triggerOutput() { + lastOutput = ( new Date() ).getTime(); + scheduled = false; + + output.apply( scopeObj, args ); + } + } + + function reset() { + if ( scheduled ) { + clearTimeout( scheduled ); + scheduled = lastOutput = 0; + } + } + }, + /** * Removes spaces from the start and the end of a string. The following * characters are removed: space, tab, line break, line feed. From a359ff196f34ea8b63d95de6338b086631179eee Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 22 May 2018 11:02:25 +0200 Subject: [PATCH 02/10] Added unit tests. --- tests/core/tools.js | 93 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tests/core/tools.js b/tests/core/tools.js index 372b2be1231..7971ad3afb9 100644 --- a/tests/core/tools.js +++ b/tests/core/tools.js @@ -628,6 +628,99 @@ assert.areSame( 'ABcDeF', c( 'aBcDeF', true ) ); }, + 'test throttle': function() { + var output = 0, + foo = 'foo', + buz = 'buz', + message, + buffer = CKEDITOR.tools.throttle( 200, function( arg ) { + output++; + message = arg; + } ); + + assert.areSame( 0, output ); + + buffer.input( foo ); + + assert.areSame( 1, output ); + assert.areSame( foo, message ); + + buffer.input( buz ); + buffer.input( buz ); + buffer.input( buz ); + + assert.areSame( 1, output ); + assert.areSame( foo, message ); + + wait( function() { + assert.areSame( 1, output ); + assert.areSame( foo, message ); + + wait( function() { + assert.areSame( 2, output ); + assert.areSame( buz, message ); + + buffer.input( foo ); + + assert.areSame( 2, output ); + assert.areSame( buz, message ); + + wait( function() { + assert.areSame( 3, output ); + assert.areSame( foo, message ); + + // Check that input triggered after 70ms from previous + // buffer.input will trigger output after next 140ms (200-70). + wait( function() { + buffer.input( buz ); + + assert.areSame( 3, output ); + assert.areSame( foo, message ); + + wait( function() { + assert.areSame( 4, output ); + assert.areSame( buz, message ); + }, 140 ); + }, 70 ); + }, 210 ); + }, 110 ); + }, 100 ); + }, + + 'test throttle.reset': function() { + var output = 0, + buffer = CKEDITOR.tools.throttle( 100, function() { + output++; + } ); + + assert.areSame( 0, output ); + + buffer.input(); + + assert.areSame( 1, output ); + + buffer.input(); + buffer.reset(); + + wait( function() { + assert.areSame( 1, output ); + + buffer.input(); + + assert.areSame( 2, output ); + }, 110 ); + }, + + 'test throttle contex': function() { + var spy = sinon.spy(), + ctxObj = {}, + buffer = CKEDITOR.tools.throttle( 100, spy, ctxObj ); + + buffer.input(); + + assert.areSame( ctxObj, spy.getCall( 0 ).thisValue, 'callback was executed with the right context' ); + }, + 'test checkIfAnyObjectPropertyMatches': function() { var c = CKEDITOR.tools.checkIfAnyObjectPropertyMatches, r1 = /foo/, From affd52ecd8fa8028e6b3df8d1687709366635fbb Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 22 May 2018 11:45:44 +0200 Subject: [PATCH 03/10] Added manual test. --- tests/core/tools/manual/throttle.html | 21 +++++++++++++++++++++ tests/core/tools/manual/throttle.md | 15 +++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/core/tools/manual/throttle.html create mode 100644 tests/core/tools/manual/throttle.md diff --git a/tests/core/tools/manual/throttle.html b/tests/core/tools/manual/throttle.html new file mode 100644 index 00000000000..c7e085b3dc3 --- /dev/null +++ b/tests/core/tools/manual/throttle.html @@ -0,0 +1,21 @@ + + + + + diff --git a/tests/core/tools/manual/throttle.md b/tests/core/tools/manual/throttle.md new file mode 100644 index 00000000000..12b902148c1 --- /dev/null +++ b/tests/core/tools/manual/throttle.md @@ -0,0 +1,15 @@ +@bender-tags: feature, 4.10.0, 1993 +@bender-ui: collapsed +@bender-ckeditor-plugins: toolbar, wysiwygarea + +1. Click button `Click me` five times as fast as possible. + +## Expected + +Button changes its color: +1. After first click to blue. +1. After last click to red. + +## Unexpected + +Button changes its color in invalid order. From 73aa69d8afe56a678d8a5f82e69b2200400e49f3 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 22 May 2018 11:59:27 +0200 Subject: [PATCH 04/10] Changelog entry. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 4d125faf779..07a2be6db61 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ New Features: * [#1761](https://github.com/ckeditor/ckeditor-dev/issues/1761): [Autolink](https://ckeditor.com/cke4/addon/autolink) plugin supports email links. * [#1703](https://github.com/ckeditor/ckeditor-dev/issues/1703): Introduced Mentions plugin providing autocompletion feature for usernames. +* [#1993](https://github.com/ckeditor/ckeditor-dev/issues/1993): Added [`CKEDITOR.tools.throttle`](http://docs.ckeditor.com/ckeditor4/docs/#!/api/CKEDITOR_tools.html#method-throttle) function. Fixed Issues: From 9f83ca55d52685059c2ef02d79302c64632254a5 Mon Sep 17 00:00:00 2001 From: Marek Lewandowski Date: Tue, 29 May 2018 18:27:09 +0200 Subject: [PATCH 05/10] Tests: added a test case ensuring that throttle always use the last argument for throttled calls. --- tests/core/tools.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/core/tools.js b/tests/core/tools.js index 7971ad3afb9..deb1847cd21 100644 --- a/tests/core/tools.js +++ b/tests/core/tools.js @@ -687,6 +687,25 @@ }, 100 ); }, + 'test throttle always uses the most recent argument': function() { + var input = sinon.stub(), + buffer = CKEDITOR.tools.throttle( 50, input ); + + buffer.input( 'first' ); + + assert.areSame( 1, input.callCount, 'Call count after the first call' ); + sinon.assert.calledWithExactly( input.getCall( 0 ), 'first' ); + + buffer.input( 'second' ); + + buffer.input( 'third' ); + + wait( function() { + assert.areSame( 2, input.callCount, 'Call count after the timeout' ); + sinon.assert.calledWithExactly( input.getCall( 1 ), 'third' ); + }, 100 ); + }, + 'test throttle.reset': function() { var output = 0, buffer = CKEDITOR.tools.throttle( 100, function() { From b465c9df4211e83eb7a6c9b40b891fd942656c25 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 30 May 2018 12:42:21 +0200 Subject: [PATCH 06/10] Fixed unit tests. --- tests/core/tools.js | 69 ++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/tests/core/tools.js b/tests/core/tools.js index deb1847cd21..12d014706b0 100644 --- a/tests/core/tools.js +++ b/tests/core/tools.js @@ -629,57 +629,46 @@ }, 'test throttle': function() { - var output = 0, - foo = 'foo', - buz = 'buz', - message, - buffer = CKEDITOR.tools.throttle( 200, function( arg ) { - output++; - message = arg; - } ); - - assert.areSame( 0, output ); + var foo = 'foo', + baz = 'baz', + inputSpy = sinon.spy(), + buffer = CKEDITOR.tools.throttle( 200, inputSpy ); buffer.input( foo ); - assert.areSame( 1, output ); - assert.areSame( foo, message ); + assert.isTrue( inputSpy.calledOnce, 'Call count after the first call' ); + assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument after the first call' ); - buffer.input( buz ); - buffer.input( buz ); - buffer.input( buz ); + buffer.input( baz ); - assert.areSame( 1, output ); - assert.areSame( foo, message ); + assert.isTrue( inputSpy.calledOnce, 'Call count after the second call' ); + assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument the after second call' ); wait( function() { - assert.areSame( 1, output ); - assert.areSame( foo, message ); + assert.isTrue( inputSpy.calledOnce, 'Call count after the second call timeout (1st)' ); + assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument after the second call timeout (1st)' ); wait( function() { - assert.areSame( 2, output ); - assert.areSame( buz, message ); + assert.isTrue( inputSpy.calledTwice, 'Call count after the second call timeout (2nd)' ); + assert.isTrue( inputSpy.calledWithExactly( baz ), 'Call argument after the second call timeout (2nd)' ); buffer.input( foo ); - assert.areSame( 2, output ); - assert.areSame( buz, message ); - wait( function() { - assert.areSame( 3, output ); - assert.areSame( foo, message ); + assert.isTrue( inputSpy.calledThrice, 'Call count after the third call' ); + assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument after the third call' ); // Check that input triggered after 70ms from previous // buffer.input will trigger output after next 140ms (200-70). wait( function() { - buffer.input( buz ); + buffer.input( baz ); - assert.areSame( 3, output ); - assert.areSame( foo, message ); + assert.isTrue( inputSpy.calledThrice, 'Call count after the fourth call' ); + assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument after the fourth call' ); wait( function() { - assert.areSame( 4, output ); - assert.areSame( buz, message ); + assert.areSame( 4, inputSpy.callCount, 'Call count after the fourth call timeout' ); + assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument after the fourth call timeout' ); }, 140 ); }, 70 ); }, 210 ); @@ -707,27 +696,23 @@ }, 'test throttle.reset': function() { - var output = 0, - buffer = CKEDITOR.tools.throttle( 100, function() { - output++; - } ); + var inputSpy = sinon.spy(), + buffer = CKEDITOR.tools.throttle( 100, inputSpy ); - assert.areSame( 0, output ); + assert.areSame( 0, inputSpy.callCount, 'Initial call count' ); buffer.input(); - assert.areSame( 1, output ); + assert.areSame( 1, inputSpy.callCount, 'Call count after the first call' ); buffer.input(); buffer.reset(); - wait( function() { - assert.areSame( 1, output ); + assert.areSame( 1, inputSpy.callCount, 'Call count after reset' ); - buffer.input(); + buffer.input(); - assert.areSame( 2, output ); - }, 110 ); + assert.areSame( 2, inputSpy.callCount, 'Call count after the second call' ); }, 'test throttle contex': function() { From c291d41c1cc20495051c9514fdf17567c47537c6 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 30 May 2018 12:43:16 +0200 Subject: [PATCH 07/10] Fixed changelog. --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 07a2be6db61..252c4217bd1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,7 +7,6 @@ New Features: * [#1761](https://github.com/ckeditor/ckeditor-dev/issues/1761): [Autolink](https://ckeditor.com/cke4/addon/autolink) plugin supports email links. * [#1703](https://github.com/ckeditor/ckeditor-dev/issues/1703): Introduced Mentions plugin providing autocompletion feature for usernames. -* [#1993](https://github.com/ckeditor/ckeditor-dev/issues/1993): Added [`CKEDITOR.tools.throttle`](http://docs.ckeditor.com/ckeditor4/docs/#!/api/CKEDITOR_tools.html#method-throttle) function. Fixed Issues: @@ -26,6 +25,7 @@ API Changes: * [#1712](https://github.com/ckeditor/ckeditor-dev/issues/1712): [`extraPlugins`](https://docs.ckeditor.com/ckeditor4/latest/api/CKEDITOR_config.html#cfg-extraPlugins), [`removePlugins`](https://docs.ckeditor.com/ckeditor4/latest/api/CKEDITOR_config.html#cfg-removePlugins) and [`plugins`](https://docs.ckeditor.com/ckeditor4/latest/api/CKEDITOR_config.html#cfg-plugins) configuration options allow whitespace. * [#1724](https://github.com/ckeditor/ckeditor-dev/issues/1724): Added option to [`getClientRect`](https://docs.ckeditor.com/ckeditor4/latest/api/CKEDITOR_dom_element.html#method-getClientRect) function allowing to retrieve an absolute bounding rectangle of the element i.e. position relative to the upper-left corner of the topmost viewport. * [#1498](https://github.com/ckeditor/ckeditor-dev/issues/1498) : Added new method 'getClientRects()' to CKEDITOR.dom.range, which returns list of rects for each selected element. +* [#1993](https://github.com/ckeditor/ckeditor-dev/issues/1993): Added [`CKEDITOR.tools.throttle`](http://docs.ckeditor.com/ckeditor4/docs/#!/api/CKEDITOR_tools.html#method-throttle) function. ## CKEditor 4.9.2 From 030770718c6154ff45cf477702416f1c1da0941c Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 30 May 2018 13:19:18 +0200 Subject: [PATCH 08/10] Docs refactor. --- core/tools.js | 92 ++++++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/core/tools.js b/core/tools.js index c046eb3fd9d..d3349493429 100644 --- a/core/tools.js +++ b/core/tools.js @@ -583,46 +583,51 @@ * Throttles `input` events (or any `input` calls) * and triggers `output` not more often than once per `minInterval`. * - * After each `input` scheduled `output` will be destroyed and replaced with - * new one. It gives you the opportunity to modify passed parameters into `input` function and get - * different results. + * If multiple calls occur within a single `minInterval` time, the most recent `input` call with its arguments will be used to schedule next `output` call, + * and the previous `output` call will be discarded. * - * var buffer = CKEDITOR.tools.throttle( 200, function( message ) { - * console.log( message ); - * } ); + * The first `input` call is always executed asynchronously which means that `output` call will be executed immediately. + * + * ```javascript + * var buffer = CKEDITOR.tools.throttle( 200, function( message ) { + * console.log( message ); + * } ); * - * buffer.input( 'foo!' ); - * // 'foo!' logged immediately. - * buffer.input( 'buz!' ); - * // Nothing logged. - * buffer.input( 'bar!' ); - * // Nothing logged. - * // ... after 200ms a single 'bar!' will be logged. + * buffer.input( 'foo!' ); + * // 'foo!' logged immediately. + * buffer.input( 'baz!' ); + * // Nothing logged. + * buffer.input( 'bar!' ); + * // Nothing logged. + * // … after 200ms a single 'bar!' will be logged. + * ``` * * Can be easily used with events: * - * var buffer = CKEDITOR.tools.throttle( 200, function( evt ) { - * console.log( evt.data.text ); - * } ); + * ```javascript + * var buffer = CKEDITOR.tools.throttle( 200, function( evt ) { + * console.log( evt.data.text ); + * } ); * - * editor.on( 'key', buffer.input ); - * // Note: There is no need to bind buffer as a context. + * editor.on( 'key', buffer.input ); + * // Note: There is no need to bind buffer as a context. + * ``` * * @since 4.10.0 * @param {Number} minInterval Minimum interval between `output` calls in milliseconds. * @param {Function} output Function that will be executed as `output`. - * @param {Object} [scopeObj] The object used to scope the listener call (the `this` object). + * @param {Object} [contextObj] The object used to context the listener call (the `this` object). * @returns {Object} * @returns {Function} return.input Buffer's input method. * Accepts parameters which will be directly passed into `output` function. * @returns {Function} return.reset Resets buffered events — `output` will not be executed * until next `input` is triggered. */ - throttle: function( minInterval, output, scopeObj ) { + throttle: function( minInterval, output, contextObj ) { var scheduled, lastOutput = 0; - scopeObj = scopeObj || {}; + contextObj = contextObj || {}; return { input: input, @@ -651,7 +656,7 @@ lastOutput = ( new Date() ).getTime(); scheduled = false; - output.apply( scopeObj, args ); + output.apply( contextObj, args ); } } @@ -1273,45 +1278,50 @@ * Buffers `input` events (or any `input` calls) * and triggers `output` not more often than once per `minInterval`. * - * var buffer = CKEDITOR.tools.eventsBuffer( 200, function() { - * console.log( 'foo!' ); - * } ); + * ```javascript + * var buffer = CKEDITOR.tools.eventsBuffer( 200, function() { + * console.log( 'foo!' ); + * } ); * - * buffer.input(); - * // 'foo!' logged immediately. - * buffer.input(); - * // Nothing logged. - * buffer.input(); - * // Nothing logged. - * // ... after 200ms a single 'foo!' will be logged. + * buffer.input(); + * // 'foo!' logged immediately. + * buffer.input(); + * // Nothing logged. + * buffer.input(); + * // Nothing logged. + * // … after 200ms a single 'foo!' will be logged. + * ``` * * Can be easily used with events: * - * var buffer = CKEDITOR.tools.eventsBuffer( 200, function() { - * console.log( 'foo!' ); - * } ); + * ```javascript + * var buffer = CKEDITOR.tools.eventsBuffer( 200, function() { + * console.log( 'foo!' ); + * } ); + * + * editor.on( 'key', buffer.input ); + * // Note: There is no need to bind buffer as a context. + * ``` * - * editor.on( 'key', buffer.input ); - * // Note: There is no need to bind buffer as a context. * * @since 4.2.1 * @param {Number} minInterval Minimum interval between `output` calls in milliseconds. * @param {Function} output Function that will be executed as `output`. - * @param {Object} [scopeObj] The object used to scope the listener call (the `this` object). + * @param {Object} [contextObj] The object used to context the listener call (the `this` object). * @returns {Object} * @returns {Function} return.input Buffer's input method. * @returns {Function} return.reset Resets buffered events — `output` will not be executed * until next `input` is triggered. */ - eventsBuffer: function( minInterval, output, scopeObj ) { + eventsBuffer: function( minInterval, output, contextObj ) { var scheduled, lastOutput = 0; function triggerOutput() { lastOutput = ( new Date() ).getTime(); scheduled = false; - if ( scopeObj ) { - output.call( scopeObj ); + if ( contextObj ) { + output.call( contextObj ); } else { output(); } From 051fd7433f8211cd1e9be623d1ce99042359664e Mon Sep 17 00:00:00 2001 From: Marek Lewandowski Date: Fri, 1 Jun 2018 14:18:10 +0200 Subject: [PATCH 09/10] Docs: adjusted CKEDITOR.tools.throttle API docs. --- core/tools.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/tools.js b/core/tools.js index d3349493429..bae122fd368 100644 --- a/core/tools.js +++ b/core/tools.js @@ -580,11 +580,11 @@ }, /** - * Throttles `input` events (or any `input` calls) - * and triggers `output` not more often than once per `minInterval`. + * Returns a wrapper that exposes an `input` function, which acts as a proxy to the given `output` function, providing a throttling. + * This proxy guarantees that the `output` function is not called more often than `minInterval`. * - * If multiple calls occur within a single `minInterval` time, the most recent `input` call with its arguments will be used to schedule next `output` call, - * and the previous `output` call will be discarded. + * If multiple calls occur within a single `minInterval` time, the most recent `input` call with its arguments will be used to schedule + * next `output` call, and the previous throttled calls will be discarded. * * The first `input` call is always executed asynchronously which means that `output` call will be executed immediately. * @@ -595,11 +595,11 @@ * * buffer.input( 'foo!' ); * // 'foo!' logged immediately. - * buffer.input( 'baz!' ); - * // Nothing logged. * buffer.input( 'bar!' ); * // Nothing logged. - * // … after 200ms a single 'bar!' will be logged. + * buffer.input( 'baz!' ); + * // Nothing logged. + * // … after 200ms a single 'baz!' will be logged. * ``` * * Can be easily used with events: @@ -620,7 +620,7 @@ * @returns {Object} * @returns {Function} return.input Buffer's input method. * Accepts parameters which will be directly passed into `output` function. - * @returns {Function} return.reset Resets buffered events — `output` will not be executed + * @returns {Function} return.reset Resets buffered calls — `output` will not be executed * until next `input` is triggered. */ throttle: function( minInterval, output, contextObj ) { From 2d2bea6e54d25cf227c612b93a9297aad7ba44ed Mon Sep 17 00:00:00 2001 From: Marek Lewandowski Date: Fri, 1 Jun 2018 14:30:07 +0200 Subject: [PATCH 10/10] Tests: adjusted assertions for CKEDITOR.tools.throttle. --- tests/core/tools.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/core/tools.js b/tests/core/tools.js index 12d014706b0..85473f12e4d 100644 --- a/tests/core/tools.js +++ b/tests/core/tools.js @@ -602,7 +602,7 @@ }, 110 ); }, - 'test eventsBuffer contex': function() { + 'test eventsBuffer context': function() { var spy = sinon.spy(), ctxObj = {}, buffer = CKEDITOR.tools.eventsBuffer( 100, spy, ctxObj ); @@ -636,39 +636,38 @@ buffer.input( foo ); - assert.isTrue( inputSpy.calledOnce, 'Call count after the first call' ); + assert.areSame( 1, inputSpy.callCount, 'Call count after the first call' ); assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument after the first call' ); buffer.input( baz ); - assert.isTrue( inputSpy.calledOnce, 'Call count after the second call' ); + assert.areSame( 1, inputSpy.callCount, 'Call count after the second call' ); assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument the after second call' ); wait( function() { - assert.isTrue( inputSpy.calledOnce, 'Call count after the second call timeout (1st)' ); + assert.areSame( 1, inputSpy.callCount, 'Call count after the second call timeout (1st)' ); assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument after the second call timeout (1st)' ); wait( function() { - assert.isTrue( inputSpy.calledTwice, 'Call count after the second call timeout (2nd)' ); - assert.isTrue( inputSpy.calledWithExactly( baz ), 'Call argument after the second call timeout (2nd)' ); + assert.areSame( 2, inputSpy.callCount, 'Call count after the second call timeout (2nd)' ); + assert.isTrue( inputSpy.getCall( 1 ).calledWithExactly( baz ), 'Call argument after the second call timeout (2nd)' ); buffer.input( foo ); wait( function() { - assert.isTrue( inputSpy.calledThrice, 'Call count after the third call' ); - assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument after the third call' ); + assert.areSame( 3, inputSpy.callCount, 'Call count after the third call' ); + assert.isTrue( inputSpy.getCall( 2 ).calledWithExactly( foo ), 'Call argument after the third call' ); // Check that input triggered after 70ms from previous // buffer.input will trigger output after next 140ms (200-70). wait( function() { buffer.input( baz ); - assert.isTrue( inputSpy.calledThrice, 'Call count after the fourth call' ); - assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument after the fourth call' ); + assert.areSame( 3, inputSpy.callCount, 'Call count after the fourth call' ); wait( function() { assert.areSame( 4, inputSpy.callCount, 'Call count after the fourth call timeout' ); - assert.isTrue( inputSpy.calledWithExactly( foo ), 'Call argument after the fourth call timeout' ); + assert.isTrue( inputSpy.getCall( 3 ).calledWithExactly( baz ), 'Call argument after the fourth call timeout' ); }, 140 ); }, 70 ); }, 210 ); @@ -715,7 +714,7 @@ assert.areSame( 2, inputSpy.callCount, 'Call count after the second call' ); }, - 'test throttle contex': function() { + 'test throttle context': function() { var spy = sinon.spy(), ctxObj = {}, buffer = CKEDITOR.tools.throttle( 100, spy, ctxObj );