8
0
Pārlūkot izejas kodu

Merge branch 'master' into t/120

Piotrek Koszuliński 10 gadi atpakaļ
vecāks
revīzija
0027b47635

+ 2 - 3
packages/ckeditor5-utils/.jscsrc

@@ -58,6 +58,5 @@
 	"disallowNewlineBeforeBlockStatements": true,
 	"validateLineBreaks": "LF",
 	"validateQuoteMarks": "'",
-	"validateIndentation": "\t",
-	"safeContextKeyword": [ "that" ]
-}
+	"validateIndentation": "\t"
+}

+ 0 - 4
packages/ckeditor5-utils/src/config.js

@@ -77,9 +77,7 @@ export default class Config extends Model {
 		}
 
 		// The target for this configuration is, for now, this object.
-		//jscs:disable safeContextKeyword
 		let target = this;
-		//jscs:enable
 
 		// The configuration name should be split into parts if it has dots. E.g: `resize.width`.
 		const parts = name.toLowerCase().split( '.' );
@@ -133,9 +131,7 @@ export default class Config extends Model {
 	 */
 	get( name ) {
 		// The target for this configuration is, for now, this object.
-		//jscs:disable safeContextKeyword
 		let source = this;
-		//jscs:enable
 
 		// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`]
 		const parts = name.toLowerCase().split( '.' );

+ 19 - 5
packages/ckeditor5-utils/src/emittermixin.js

@@ -5,6 +5,13 @@
 
 'use strict';
 
+import EventInfo from './eventinfo.js';
+import utils from './utils.js';
+
+// Saves how many callbacks has been already added. Does not decrement when callback is removed.
+// Used internally as a unique id for a callback.
+let eventsCounter = 0;
+
 /**
  * Mixin that injects the events API into its host.
  *
@@ -12,9 +19,6 @@
  * @singleton
  */
 
-import EventInfo from './eventinfo.js';
-import utils from './utils.js';
-
 const EmitterMixin = {
 	/**
 	 * Registers a callback function to be executed when an event is fired.
@@ -37,7 +41,9 @@ const EmitterMixin = {
 		callback = {
 			callback: callback,
 			ctx: ctx || this,
-			priority: priority
+			priority: priority,
+			// Save counter value as unique id.
+			counter: ++eventsCounter
 		};
 
 		// Add the callback to the list in the right priority position.
@@ -228,7 +234,15 @@ const EmitterMixin = {
 		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 = eventsCounter;
+
 		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.
@@ -282,4 +296,4 @@ function getCallbacksIfAny( source, event ) {
 	}
 
 	return callbacks;
-}
+}

+ 28 - 0
packages/ckeditor5-utils/tests/_tools/tools.js

@@ -63,4 +63,32 @@
 			return count;
 		}
 	};
+
+	bender.tools.treemodel = {
+		/**
+		 * Returns tree structure as a simplified string. Elements are uppercase and characters are lowercase.
+		 * Start and end of an element is marked the same way, by the element's name (in uppercase).
+		 *
+		 *		let element = new Element( 'div', [], [ 'abc', new Element( 'p', [], 'foo' ), 'xyz' ] );
+		 *		bender.tools.treemodel.getNodesAndText( element ); // abcPfooPxyz
+		 *
+		 * @param {treeModel.Range} range Range to stringify.
+		 * @returns {String} String representing element inner structure.
+		 */
+		getNodesAndText: ( range ) => {
+			let txt = '';
+
+			for ( let step of range ) {
+				let node = step.node;
+
+				if ( node.character ) {
+					txt += node.character.toLowerCase();
+				} else if ( node.name ) {
+					txt += node.name.toUpperCase();
+				}
+			}
+
+			return txt;
+		}
+	};
 } )();

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

@@ -122,6 +122,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', () => {