浏览代码

EmitterMixin fixed calling callbacks for event listeners that were created while firing that event.

Szymon Cofalik 10 年之前
父节点
当前提交
31ce039644

+ 18 - 1
packages/ckeditor5-utils/src/emittermixin.js

@@ -15,6 +15,13 @@
 CKEDITOR.define( [ 'eventinfo', 'utils' ], ( EventInfo, utils ) => {
 	const EmitterMixin = {
 		/**
+		 * Saves how many callbacks has been already added. Does not decrement when callback is removed.
+		 * Used internally as a unique id for a callback.
+		 * @private
+		 */
+		_counter: 0,
+
+		/**
 		 * Registers a callback function to be executed when an event is fired.
 		 *
 		 * @param {String} event The name of the event.
@@ -35,7 +42,9 @@ CKEDITOR.define( [ 'eventinfo', 'utils' ], ( EventInfo, utils ) => {
 			callback = {
 				callback: callback,
 				ctx: ctx || this,
-				priority: priority
+				priority: priority,
+				// Save counter value as unique id.
+				counter: ++this._counter
 			};
 
 			// Add the callback to the list in the right priority position.
@@ -226,7 +235,15 @@ CKEDITOR.define( [ 'eventinfo', 'utils' ], ( EventInfo, utils ) => {
 			args = Array.prototype.slice.call( arguments, 1 );
 			args.unshift( eventInfo );
 
+			// Save how many callbacks were added at the moment when the event has been fired.
+			const counter = this._counter;
+
 			for ( let i = 0; i < callbacks.length; i++ ) {
+				// Filter out callbacks that have been added after event has been fired.
+				if ( callbacks[ i ].counter > counter ) {
+					continue;
+				}
+
 				callbacks[ i ].callback.apply( callbacks[ i ].ctx, args );
 
 				// Remove the callback from future requests if off() has been called.

+ 12 - 0
packages/ckeditor5-utils/tests/emittermixin/emittermixin.js

@@ -118,6 +118,18 @@ describe( 'fire', () => {
 
 		sinon.assert.calledThrice( spy );
 	} );
+
+	it( 'should not fire callbacks for an event that were added while firing that event', () => {
+		let spy = sinon.spy();
+
+		emitter.on( 'test', () => {
+			emitter.on( 'test', spy );
+		} );
+
+		emitter.fire( 'test' );
+
+		sinon.assert.notCalled( spy );
+	} );
 } );
 
 describe( 'on', () => {