瀏覽代碼

Merge branch 'master' into t/ckeditor5-ui/262

Oskar Wróbel 8 年之前
父節點
當前提交
ce8121d2c3

+ 22 - 4
packages/ckeditor5-utils/src/collection.js

@@ -28,10 +28,10 @@ export default class Collection {
 	/**
 	 * Creates a new Collection instance.
 	 *
-	 * @param {Object} options The options object.
+	 * @param {Object} [options={}] The options object.
 	 * @param {String} [options.idProperty='id'] The name of the property which is considered to identify an item.
 	 */
-	constructor( options ) {
+	constructor( options = {} ) {
 		/**
 		 * The internal list of items in the collection.
 		 *
@@ -54,7 +54,7 @@ export default class Collection {
 		 * @private
 		 * @member {String}
 		 */
-		this._idProperty = options && options.idProperty || 'id';
+		this._idProperty = options.idProperty || 'id';
 
 		/**
 		 * A helper mapping external items of a bound collection ({@link #bindTo})
@@ -99,6 +99,24 @@ export default class Collection {
 	}
 
 	/**
+	 * Returns the first item from the collection or null when collection is empty.
+	 *
+	 * @returns {Object|null} The first item or `null` if collection is empty.
+	 */
+	get first() {
+		return this._items[ 0 ] || null;
+	}
+
+	/**
+	 * Returns the last item from the collection or null when collection is empty.
+	 *
+	 * @returns {Object|null} The last item or `null` if collection is empty.
+	 */
+	get last() {
+		return this._items[ this.length - 1 ] || null;
+	}
+
+	/**
 	 * Adds an item into the collection.
 	 *
 	 * If the item does not have an id, then it will be automatically generated and set on the item.
@@ -162,7 +180,7 @@ export default class Collection {
 	 * Gets item by its id or index.
 	 *
 	 * @param {String|Number} idOrIndex The item id or index in the collection.
-	 * @returns {Object} The requested item or `null` if such item does not exist.
+	 * @returns {Object|null} The requested item or `null` if such item does not exist.
 	 */
 	get( idOrIndex ) {
 		let item;

+ 2 - 6
packages/ckeditor5-utils/src/dom/emittermixin.js

@@ -46,7 +46,6 @@ const DomEmitterMixin = extend( {}, EmitterMixin, {
 	 * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher
 	 * the priority value the sooner the callback will be fired. Events having the same priority are called in the
 	 * order they were added.
-	 * @param {Object} [options.context] The object that represents `this` in the callback. Defaults to the object firing the event.
 	 * @param {Boolean} [options.useCapture=false] Indicates that events of this type will be dispatched to the registered
 	 * listener before being dispatched to any EventTarget beneath it in the DOM tree.
 	 *
@@ -179,7 +178,6 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
 	 * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher
 	 * the priority value the sooner the callback will be fired. Events having the same priority are called in the
 	 * order they were added.
-	 * @param {Object} [options.context] The object that represents `this` in the callback. Defaults to the object firing the event.
 	 * @param {Boolean} [options.useCapture=false] Indicates that events of this type will be dispatched to the registered
 	 * listener before being dispatched to any EventTarget beneath it in the DOM tree.
 	 *
@@ -214,14 +212,12 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
 	 *
 	 * @param {String} event The name of the event.
 	 * @param {Function} callback The function to stop being called.
-	 * @param {Object} [context] The context object to be removed, pared with the given callback. To handle cases where
-	 * the same callback is used several times with different contexts.
 	 *
 	 * @method module:utils/dom/emittermixin~ProxyEmitter#off
 	 */
-	off( event, callback, context ) {
+	off( event, callback ) {
 		// Execute parent class method first.
-		EmitterMixin.off.call( this, event, callback, context );
+		EmitterMixin.off.call( this, event, callback );
 
 		let events;
 

+ 7 - 15
packages/ckeditor5-utils/src/emittermixin.js

@@ -25,7 +25,7 @@ const EmitterMixin = {
 	 * Registers a callback function to be executed when an event is fired.
 	 *
 	 * Events can be grouped in namespaces using `:`.
-	 * When namespaced event is fired, it additionaly fires all callbacks for that namespace.
+	 * When namespaced event is fired, it additionally fires all callbacks for that namespace.
 	 *
 	 *		myEmitter.on( 'myGroup', genericCallback );
 	 *		myEmitter.on( 'myGroup:myEvent', specificCallback );
@@ -47,7 +47,6 @@ const EmitterMixin = {
 	 * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher
 	 * the priority value the sooner the callback will be fired. Events having the same priority are called in the
 	 * order they were added.
-	 * @param {Object} [options.context] The object that represents `this` in the callback. Defaults to the object firing the event.
 	 */
 	on( event, callback, options = {} ) {
 		createEventNamespace( this, event );
@@ -56,7 +55,6 @@ const EmitterMixin = {
 
 		callback = {
 			callback,
-			context: options.context || this,
 			priority
 		};
 
@@ -92,7 +90,6 @@ const EmitterMixin = {
 	 * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher
 	 * the priority value the sooner the callback will be fired. Events having the same priority are called in the
 	 * order they were added.
-	 * @param {Object} [options.context] The object that represents `this` in the callback. Defaults to the object firing the event.
 	 */
 	once( event, callback, options ) {
 		const onceCallback = function( event, ...args ) {
@@ -113,20 +110,16 @@ const EmitterMixin = {
 	 * @method #off
 	 * @param {String} event The name of the event.
 	 * @param {Function} callback The function to stop being called.
-	 * @param {Object} [context] The context object to be removed, pared with the given callback. To handle cases where
-	 * the same callback is used several times with different contexts.
 	 */
-	off( event, callback, context ) {
+	off( event, callback ) {
 		const lists = getCallbacksListsForNamespace( this, event );
 
 		for ( const callbacks of lists ) {
 			for ( let i = 0; i < callbacks.length; i++ ) {
 				if ( callbacks[ i ].callback == callback ) {
-					if ( !context || context == callbacks[ i ].context ) {
-						// Remove the callback from the list (fixing the next index).
-						callbacks.splice( i, 1 );
-						i--;
-					}
+					// Remove the callback from the list (fixing the next index).
+					callbacks.splice( i, 1 );
+					i--;
 				}
 			}
 		}
@@ -143,7 +136,6 @@ const EmitterMixin = {
 	 * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher
 	 * the priority value the sooner the callback will be fired. Events having the same priority are called in the
 	 * order they were added.
-	 * @param {Object} [options.context] The object that represents `this` in the callback. Defaults to the object firing the event.
 	 */
 	listenTo( emitter, event, callback, options ) {
 		let emitterInfo, eventCallbacks;
@@ -278,14 +270,14 @@ const EmitterMixin = {
 			callbacks = Array.from( callbacks );
 
 			for ( let i = 0; i < callbacks.length; i++ ) {
-				callbacks[ i ].callback.apply( callbacks[ i ].context, callbackArgs );
+				callbacks[ i ].callback.apply( this, callbackArgs );
 
 				// Remove the callback from future requests if off() has been called.
 				if ( eventInfo.off.called ) {
 					// Remove the called mark for the next calls.
 					delete eventInfo.off.called;
 
-					this.off( event, callbacks[ i ].callback, callbacks[ i ].context );
+					this.off( event, callbacks[ i ].callback );
 				}
 
 				// Do not execute next callbacks if stop() was called.

+ 43 - 1
packages/ckeditor5-utils/tests/collection.js

@@ -40,6 +40,48 @@ describe( 'Collection', () => {
 		} );
 	} );
 
+	describe( 'length', () => {
+		it( 'should return collection length', () => {
+			expect( collection.length ).to.equal( 0 );
+
+			collection.add( { foo: 'bar' } );
+
+			expect( collection.length ).to.equal( 1 );
+		} );
+	} );
+
+	describe( 'first', () => {
+		it( 'should return the first item from the collection', () => {
+			const item1 = { foo: 'bar' };
+			const item2 = { bar: 'biz' };
+
+			collection.add( item1 );
+			collection.add( item2 );
+
+			expect( collection.first ).to.equal( item1 );
+		} );
+
+		it( 'should return null when collection is empty', () => {
+			expect( collection.first ).to.null;
+		} );
+	} );
+
+	describe( 'last', () => {
+		it( 'should return the last item from the collection', () => {
+			const item1 = { foo: 'bar' };
+			const item2 = { bar: 'biz' };
+
+			collection.add( item1 );
+			collection.add( item2 );
+
+			expect( collection.last ).to.equal( item2 );
+		} );
+
+		it( 'should return null when collection is empty', () => {
+			expect( collection.last ).to.null;
+		} );
+	} );
+
 	describe( 'add()', () => {
 		it( 'should be chainable', () => {
 			expect( collection.add( {} ) ).to.equal( collection );
@@ -376,7 +418,7 @@ describe( 'Collection', () => {
 		} );
 
 		it( 'should remove the model by model - custom id property', () => {
-			const collection = new Collection( null, 'name' );
+			const collection = new Collection( { idProperty: 'name' } );
 			const item = getItem( 'foo', 'name' );
 
 			collection.add( item );

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

@@ -60,25 +60,6 @@ describe( 'EmitterMixin', () => {
 			sinon.assert.calledWithExactly( spy2, sinon.match.instanceOf( EventInfo ), 1, 'b', true );
 		} );
 
-		it( 'should pass proper context to callbacks', () => {
-			const ctx1 = {};
-			const ctx2 = {};
-
-			const spy1 = sinon.spy();
-			const spy2 = sinon.spy();
-			const spy3 = sinon.spy();
-
-			emitter.on( 'test', spy1, { context: ctx1 } );
-			emitter.on( 'test', spy2, { context: ctx2 } );
-			emitter.on( 'test', spy3 );
-
-			emitter.fire( 'test' );
-
-			sinon.assert.calledOn( spy1, ctx1 );
-			sinon.assert.calledOn( spy2, ctx2 );
-			sinon.assert.calledOn( spy3, emitter );
-		} );
-
 		it( 'should fire the right event', () => {
 			const spy1 = sinon.spy();
 			const spy2 = sinon.spy();
@@ -316,21 +297,6 @@ describe( 'EmitterMixin', () => {
 			sinon.assert.calledTwice( spy3 );
 		} );
 
-		it( 'should have proper scope', () => {
-			const ctx = {};
-
-			const spy1 = sinon.spy();
-			const spy2 = sinon.spy();
-
-			emitter.once( 'test', spy1, { context: ctx } );
-			emitter.once( 'test', spy2 );
-
-			emitter.fire( 'test' );
-
-			sinon.assert.calledOn( spy1, ctx );
-			sinon.assert.calledOn( spy2, emitter );
-		} );
-
 		it( 'should have proper arguments', () => {
 			const spy = sinon.spy();
 
@@ -387,27 +353,6 @@ describe( 'EmitterMixin', () => {
 			sinon.assert.callCount( spy2, 4 );
 		} );
 
-		it( 'should remove the callback for given context only', () => {
-			const spy = sinon.spy().named( 1 );
-
-			const ctx1 = { context: 1 };
-			const ctx2 = { context: 2 };
-
-			emitter.on( 'test', spy, { context: ctx1 } );
-			emitter.on( 'test', spy, { context: ctx2 } );
-
-			emitter.fire( 'test' );
-
-			spy.reset();
-
-			emitter.off( 'test', spy, ctx1 );
-
-			emitter.fire( 'test' );
-
-			sinon.assert.calledOnce( spy );
-			sinon.assert.calledOn( spy, ctx2 );
-		} );
-
 		it( 'should properly remove callbacks for namespaced events', () => {
 			const spyFoo = sinon.spy();
 			const spyAbc = sinon.spy();