Browse Source

Merge pull request #12 from cksource/t/11

t/11: Introduced the Emitter mixin with the events API
Frederico Caldeira Knabben 10 years ago
parent
commit
fb8667164a

+ 284 - 0
packages/ckeditor5-ui/src/emitter.js

@@ -0,0 +1,284 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+/**
+ * Mixin that injects the events API into its host.
+ *
+ * @class Emitter
+ * @singleton
+ */
+
+CKEDITOR.define( [ 'eventinfo', 'utils' ], function( EventInfo, utils ) {
+	var EmmitterMixin = {
+		/**
+		 * Registers a callback function to be executed when an event is fired.
+		 *
+		 * @param {String} event The name of the event.
+		 * @param {Function} callback The function to be called on event.
+		 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to the object firing the
+		 * event.
+		 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
+		 * Lower values are called first.
+		 */
+		on: function( event, callback, ctx, priority ) {
+			var callbacks = getCallbacks( this, event );
+
+			// Set the priority defaults.
+			if ( typeof priority != 'number' ) {
+				priority = 10;
+			}
+
+			callback = {
+				callback: callback,
+				ctx: ctx || this,
+				priority: priority
+			};
+
+			// Add the callback to the list in the right priority position.
+			for ( var i = callbacks.length - 1; i >= 0; i-- ) {
+				if ( callbacks[ i ].priority <= priority ) {
+					callbacks.splice( i + 1, 0, callback );
+
+					return;
+				}
+			}
+
+			callbacks.unshift( callback );
+		},
+
+		/**
+		 * Registers a callback function to be executed on the next time the event is fired only. This is similar to
+		 * calling {@link #on} followed by {@link #off} in the callback.
+		 *
+		 * @param {String} event The name of the event.
+		 * @param {Function} callback The function to be called on event.
+		 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to the object firing the
+		 * event.
+		 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
+		 * Lower values are called first.
+		 */
+		once: function( event, callback, ctx, priority ) {
+			var onceCallback = function( event ) {
+				// Go off() at the first call.
+				event.off();
+
+				// Go with the original callback.
+				callback.apply( this, arguments );
+			};
+
+			// Make the a similar on() call, simply replacing the callback.
+			this.on( event, onceCallback, ctx, priority );
+		},
+
+		/**
+		 * Stops executing the callback on the given event.
+		 *
+		 * @param {String} event The name of the event.
+		 * @param {Function} callback The function to stop being called.
+		 * @param {Object} [ctx] 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: function( event, callback, ctx ) {
+			var callbacks = getCallbacksIfAny( this, event );
+
+			if ( !callbacks ) {
+				return;
+			}
+
+			for ( var i = 0; i < callbacks.length; i++ ) {
+				if ( callbacks[ i ].callback == callback ) {
+					if ( !ctx || ctx == callbacks[ i ].ctx ) {
+						// Remove the callback from the list (fixing the next index).
+						callbacks.splice( i, 1 );
+						i--;
+					}
+				}
+			}
+		},
+
+		/**
+		 * Registers a callback function to be executed when an event is fired in a specific (emitter) object.
+		 *
+		 * @param {Emitter} emitter The object that fires the event.
+		 * @param {String} event The name of the event.
+		 * @param {Function} callback The function to be called on event.
+		 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to `emitter`.
+		 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
+		 * Lower values are called first.
+		 */
+		listenTo: function( emitter, event, callback, ctx, priority ) {
+			var emitters, emitterId, emitterInfo, eventCallbacks;
+
+			// _listeningTo contains a list of emitters that this object is listening to.
+			// This list has the following format:
+			//
+			// _listeningTo: {
+			//     emitterId: {
+			//         emitter: emitter,
+			//         callbacks: {
+			//             event1: [ callback1, callback2, ... ]
+			//             ....
+			//         }
+			//     },
+			//     ...
+			// }
+
+			if ( !( emitters = this._listeningTo ) ) {
+				emitters = this._listeningTo = {};
+			}
+
+			if ( !( emitterId = emitter._emitterId ) ) {
+				emitterId = emitter._emitterId = utils.uid();
+			}
+
+			if ( !( emitterInfo = emitters[ emitterId ] ) ) {
+				emitterInfo = emitters[ emitterId ] = {
+					emitter: emitter,
+					callbacks: {}
+				};
+			}
+
+			if ( !( eventCallbacks = emitterInfo.callbacks[ event ] ) ) {
+				eventCallbacks = emitterInfo.callbacks[ event ] = [];
+			}
+
+			eventCallbacks.push( callback );
+
+			// Finally register the callback to the event.
+			emitter.on( event, callback, ctx, priority );
+		},
+
+		/**
+		 * Stops listening for events. It can be used at different levels:
+		 *
+		 * * To stop listening to a specific callback.
+		 * * To stop listening to a specific event.
+		 * * To stop listening to all events fired by a specific object.
+		 * * To stop listening to all events fired by all object.
+		 *
+		 * @param {Emitter} [emitter] The object to stop listening to. If omitted, stops it for all objects.
+		 * @param {String} [event] (Requires the `emitter`) The name of the event to stop listening to. If omitted, stops it
+		 * for all events from `emitter`.
+		 * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given
+		 * `event`.
+		 */
+		stopListening: function( emitter, event, callback ) {
+			var emitters = this._listeningTo;
+			var emitterId = emitter && emitter._emitterId;
+			var emitterInfo = emitters && emitterId && emitters[ emitterId ];
+			var eventCallbacks = emitterInfo && event && emitterInfo.callbacks[ event ];
+
+			// Stop if nothing has been listened.
+			if ( !emitters || ( emitter && !emitterInfo ) || ( event && !eventCallbacks ) ) {
+				return;
+			}
+
+			// All params provided. off() that single callback.
+			if ( callback ) {
+				emitter.off( event, callback );
+			}
+			// Only `emitter` and `event` provided. off() all callbacks for that event.
+			else if ( eventCallbacks ) {
+				while ( ( callback = eventCallbacks.pop() ) ) {
+					emitter.off( event, callback );
+				}
+				delete emitterInfo.callbacks[ event ];
+			}
+			// Only `emitter` provided. off() all events for that emitter.
+			else if ( emitterInfo ) {
+				for ( event in emitterInfo.callbacks ) {
+					this.stopListening( emitter, event );
+				}
+				delete emitters[ emitterId ];
+			}
+			// No params provided. off() all emitters.
+			else {
+				for ( emitterId in emitters ) {
+					this.stopListening( emitters[ emitterId ].emitter );
+				}
+				delete this._listeningTo;
+			}
+		},
+
+		/**
+		 * Fires an event, executing all callbacks registered for it.
+		 *
+		 * The first parameter passed to callbacks is an {@link EventInfo} object, followed by the optional `args` provided in
+		 * the `fire()` method call.
+		 *
+		 * @param {String} event The name of the event.
+		 * @param {...*} [args] Additional arguments to be passed to the callbacks.
+		 */
+		fire: function( event, args ) {
+			var callbacks = getCallbacksIfAny( this, event );
+
+			if ( !callbacks ) {
+				return;
+			}
+
+			var eventInfo = new EventInfo( event );
+
+			// Take the list of arguments to pass to the callbacks.
+			args = Array.prototype.slice.call( arguments, 1 );
+			args.unshift( eventInfo );
+
+			for ( var i = 0; i < callbacks.length; i++ ) {
+				callbacks[ i ].callback.apply( callbacks[ i ].ctx, args );
+
+				// 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;
+
+					// Remove the callback from the list (fixing the next index).
+					callbacks.splice( i, 1 );
+					i--;
+				}
+
+				// Do not execute next callbacks if stop() was called.
+				if ( eventInfo.stop.called ) {
+					break;
+				}
+			}
+		}
+	};
+
+	return EmmitterMixin;
+
+	// Gets the internal events hash of a give object.
+	function getEvents( source ) {
+		if ( !source._events ) {
+			Object.defineProperty( source, '_events', {
+				value: {}
+			} );
+		}
+
+		return source._events;
+	}
+
+	// Gets the list of callbacks for a given event.
+	function getCallbacks( source, eventName ) {
+		var events = getEvents( source );
+
+		if ( !events[ eventName ] ) {
+			events[ eventName ] = [];
+		}
+
+		return events[ eventName ];
+	}
+
+	// Get the list of callbacks for a given event only if there is any available.
+	function getCallbacksIfAny( source, event ) {
+		var callbacks;
+
+		if ( !source._events || !( callbacks = source._events[ event ] ) || !callbacks.length ) {
+			return null;
+		}
+
+		return callbacks;
+	}
+} );

+ 40 - 0
packages/ckeditor5-ui/src/eventinfo.js

@@ -0,0 +1,40 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+/**
+ * The event object passed to event callbacks. It is used to provide information about the event as well as a tool to
+ * manipulate it.
+ *
+ * @class EventInfo
+ */
+
+CKEDITOR.define( [ 'utils' ], function( utils ) {
+	function EventInfo( name ) {
+		/**
+		 * The event name.
+		 */
+		this.name = name;
+
+		// The following methods are defined in the constructor because they must be re-created per instance.
+
+		/**
+		 * Stops the event emitter to call further callbacks for this event interaction.
+		 *
+		 * @method
+		 */
+		this.stop = utils.spy();
+
+		/**
+		 * Removes the current callback from future interactions of this event.
+		 *
+		 * @method
+		 */
+		this.off = utils.spy();
+	}
+
+	return EventInfo;
+} );

+ 32 - 1
packages/ckeditor5-ui/src/utils.js

@@ -13,7 +13,38 @@
  */
 
 CKEDITOR.define( [ 'utils-lodash', 'lib/lodash/lodash-ckeditor' ], function( lodashIncludes, lodash ) {
-	var utils = {};
+	var utils = {
+		/**
+		 * Creates a spy function (ala Sinon.js) that can be used to inspect call to it.
+		 *
+		 * The following are the present features:
+		 *
+		 *  * spy.called: property set to `true` if the function has been called at least once.
+		 *
+		 * @returns {Function} The spy function.
+		 */
+		spy: function() {
+			var spy = function() {
+				spy.called = true;
+			};
+
+			return spy;
+		},
+
+		/**
+		 * Returns a unique id. This id is a number (starting from 1) which will never get repeated on successive calls
+		 * to this method.
+		 *
+		 * @returns {Number} A number representing the id.
+		 */
+		uid: ( function() {
+			var next = 1;
+
+			return function() {
+				return next++;
+			};
+		} )()
+	};
 
 	// Extend "utils" with Lo-Dash methods.
 	for ( var i = 0; i < lodashIncludes.length; i++ ) {

+ 428 - 0
packages/ckeditor5-ui/tests/emitter/emitter.js

@@ -0,0 +1,428 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* globals describe, it, expect, beforeEach, bender, sinon */
+
+'use strict';
+
+var modules = bender.amd.require( 'emitter', 'eventinfo', 'utils' );
+
+var emitter, listener;
+
+beforeEach( refreshEmitter );
+
+describe( 'fire', function() {
+	it( 'should execute callbacks in the right order without priority', function() {
+		var spy1 = sinon.spy().named( 1 );
+		var spy2 = sinon.spy().named( 2 );
+		var spy3 = sinon.spy().named( 3 );
+
+		emitter.on( 'test', spy1 );
+		emitter.on( 'test', spy2 );
+		emitter.on( 'test', spy3 );
+
+		emitter.fire( 'test' );
+
+		sinon.assert.callOrder( spy1, spy2, spy3 );
+	} );
+
+	it( 'should execute callbacks in the right order with priority defined', function() {
+		var spy1 = sinon.spy().named( 1 );
+		var spy2 = sinon.spy().named( 2 );
+		var spy3 = sinon.spy().named( 3 );
+		var spy4 = sinon.spy().named( 4 );
+		var spy5 = sinon.spy().named( 5 );
+
+		emitter.on( 'test', spy2, null, 9 );
+		emitter.on( 'test', spy3 );	// Defaults to 10.
+		emitter.on( 'test', spy4, null, 11 );
+		emitter.on( 'test', spy1, null, -1 );
+		emitter.on( 'test', spy5, null, 11 );
+
+		emitter.fire( 'test' );
+
+		sinon.assert.callOrder( spy1, spy2, spy3, spy4, spy5 );
+	} );
+
+	it( 'should pass arguments to callbacks', function() {
+		var EventInfo = modules.eventinfo;
+
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy();
+
+		emitter.on( 'test', spy1 );
+		emitter.on( 'test', spy2 );
+
+		emitter.fire( 'test', 1, 'b', true );
+
+		sinon.assert.calledWithExactly( spy1, sinon.match.instanceOf( EventInfo ), 1, 'b', true );
+		sinon.assert.calledWithExactly( spy2, sinon.match.instanceOf( EventInfo ), 1, 'b', true );
+	} );
+
+	it( 'should pass proper context to callbacks', function() {
+		var ctx1 = {};
+		var ctx2 = {};
+
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy();
+		var spy3 = sinon.spy();
+
+		emitter.on( 'test', spy1, ctx1 );
+		emitter.on( 'test', spy2, 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', function() {
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy();
+
+		emitter.on( '1', spy1 );
+		emitter.on( '2', spy2 );
+
+		emitter.fire( '2' );
+
+		sinon.assert.notCalled( spy1 );
+		sinon.assert.called( spy2 );
+	} );
+
+	it( 'should execute callbacks many times', function() {
+		var spy = sinon.spy();
+
+		emitter.on( 'test', spy );
+
+		emitter.fire( 'test' );
+		emitter.fire( 'test' );
+		emitter.fire( 'test' );
+
+		sinon.assert.calledThrice( spy );
+	} );
+
+	it( 'should do nothing for a non listened event', function() {
+		emitter.fire( 'test' );
+	} );
+
+	it( 'should accept the same callback many times', function() {
+		var spy = sinon.spy();
+
+		emitter.on( 'test', spy );
+		emitter.on( 'test', spy );
+		emitter.on( 'test', spy );
+
+		emitter.fire( 'test' );
+
+		sinon.assert.calledThrice( spy );
+	} );
+} );
+
+describe( 'on', function() {
+	it( 'should stop()', function() {
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy();
+		var spy3 = sinon.spy( function( event ) {
+			event.stop();
+		} );
+
+		emitter.on( 'test', spy1 );
+		emitter.on( 'test', spy2 );
+		emitter.on( 'test', spy3 );
+		emitter.on( 'test', sinon.stub().throws() );
+		emitter.on( 'test', sinon.stub().throws() );
+
+		emitter.fire( 'test' );
+
+		sinon.assert.called( spy1 );
+		sinon.assert.called( spy2 );
+		sinon.assert.called( spy3 );
+	} );
+
+	it( 'should take a callback off()', function() {
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy( function( event ) {
+			event.off();
+		} );
+		var spy3 = sinon.spy();
+
+		emitter.on( 'test', spy1 );
+		emitter.on( 'test', spy2 );
+		emitter.on( 'test', spy3 );
+
+		emitter.fire( 'test' );
+		emitter.fire( 'test' );
+
+		sinon.assert.calledTwice( spy1 );
+		sinon.assert.calledOnce( spy2 );
+		sinon.assert.calledTwice( spy3 );
+	} );
+
+	it( 'should take the callback off() even after stop()', function() {
+		var spy1 = sinon.spy( function( event ) {
+			event.stop();
+			event.off();
+		} );
+		var spy2 = sinon.spy();
+
+		emitter.on( 'test', spy1 );
+		emitter.on( 'test', spy2 );
+
+		emitter.fire( 'test' );
+		emitter.fire( 'test' );
+
+		sinon.assert.calledOnce( spy1 );
+		sinon.assert.calledOnce( spy2 );
+	} );
+} );
+
+describe( 'once', function() {
+	it( 'should be called just once', function() {
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy();
+		var spy3 = sinon.spy();
+
+		emitter.on( 'test', spy1 );
+		emitter.once( 'test', spy2 );
+		emitter.on( 'test', spy3 );
+
+		emitter.fire( 'test' );
+		emitter.fire( 'test' );
+
+		sinon.assert.calledTwice( spy1 );
+		sinon.assert.calledOnce( spy2 );
+		sinon.assert.calledTwice( spy3 );
+	} );
+
+	it( 'should have proper scope', function() {
+		var ctx = {};
+
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy();
+
+		emitter.once( 'test', spy1, ctx );
+		emitter.once( 'test', spy2 );
+
+		emitter.fire( 'test' );
+
+		sinon.assert.calledOn( spy1, ctx );
+		sinon.assert.calledOn( spy2, emitter );
+	} );
+
+	it( 'should have proper arguments', function() {
+		var EventInfo = modules.eventinfo;
+
+		var spy = sinon.spy();
+
+		emitter.once( 'test', spy );
+
+		emitter.fire( 'test', 1, 2, 3 );
+
+		sinon.assert.calledWithExactly( spy, sinon.match.instanceOf( EventInfo ), 1, 2, 3 );
+	} );
+} );
+
+describe( 'off', function() {
+	it( 'should get callbacks off()', function() {
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy();
+		var spy3 = sinon.spy();
+
+		emitter.on( 'test', spy1 );
+		emitter.on( 'test', spy2 );
+		emitter.on( 'test', spy3 );
+
+		emitter.fire( 'test' );
+
+		emitter.off( 'test', spy2 );
+
+		emitter.fire( 'test' );
+		emitter.fire( 'test' );
+
+		sinon.assert.calledThrice( spy1 );
+		sinon.assert.calledOnce( spy2 );
+		sinon.assert.calledThrice( spy3 );
+	} );
+
+	it( 'should not fail with unknown events', function() {
+		emitter.off( 'test', function() {} );
+	} );
+
+	it( 'should remove all entries for the same callback', function() {
+		var spy1 = sinon.spy().named( 1 );
+		var spy2 = sinon.spy().named( 2 );
+
+		emitter.on( 'test', spy1 );
+		emitter.on( 'test', spy2 );
+		emitter.on( 'test', spy1 );
+		emitter.on( 'test', spy2 );
+
+		emitter.fire( 'test' );
+
+		emitter.off( 'test', spy1 );
+
+		emitter.fire( 'test' );
+
+		sinon.assert.callCount( spy1, 2 );
+		sinon.assert.callCount( spy2, 4 );
+	} );
+
+	it( 'should remove the callback for a specific context only', function() {
+		var spy = sinon.spy().named( 1 );
+
+		var ctx1 = { ctx: 1 };
+		var ctx2 = { ctx: 2 };
+
+		emitter.on( 'test', spy, ctx1 );
+		emitter.on( 'test', spy, ctx2 );
+
+		emitter.fire( 'test' );
+
+		spy.reset();
+
+		emitter.off( 'test', spy, ctx1 );
+
+		emitter.fire( 'test' );
+
+		sinon.assert.calledOnce( spy );
+		sinon.assert.calledOn( spy, ctx2 );
+	} );
+} );
+
+describe( 'listenTo', function() {
+	beforeEach( refreshListener );
+
+	it( 'should properly register callbacks', function() {
+		var spy = sinon.spy();
+
+		listener.listenTo( emitter, 'test', spy );
+
+		emitter.fire( 'test' );
+
+		sinon.assert.called( spy );
+	} );
+} );
+
+describe( 'stopListening', function() {
+	beforeEach( refreshListener );
+
+	it( 'should stop listening to a specific event callback', function() {
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy();
+
+		listener.listenTo( emitter, 'event1', spy1 );
+		listener.listenTo( emitter, 'event2', spy2 );
+
+		emitter.fire( 'event1' );
+		emitter.fire( 'event2' );
+
+		listener.stopListening( emitter, 'event1', spy1 );
+
+		emitter.fire( 'event1' );
+		emitter.fire( 'event2' );
+
+		sinon.assert.calledOnce( spy1 );
+		sinon.assert.calledTwice( spy2 );
+	} );
+
+	it( 'should stop listening to an specific event', function() {
+		var spy1a = sinon.spy();
+		var spy1b = sinon.spy();
+		var spy2 = sinon.spy();
+
+		listener.listenTo( emitter, 'event1', spy1a );
+		listener.listenTo( emitter, 'event1', spy1b );
+		listener.listenTo( emitter, 'event2', spy2 );
+
+		emitter.fire( 'event1' );
+		emitter.fire( 'event2' );
+
+		listener.stopListening( emitter, 'event1' );
+
+		emitter.fire( 'event1' );
+		emitter.fire( 'event2' );
+
+		sinon.assert.calledOnce( spy1a );
+		sinon.assert.calledOnce( spy1b );
+		sinon.assert.calledTwice( spy2 );
+	} );
+
+	it( 'should stop listening to all events from a specific emitter', function() {
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy();
+
+		listener.listenTo( emitter, 'event1', spy1 );
+		listener.listenTo( emitter, 'event2', spy2 );
+
+		emitter.fire( 'event1' );
+		emitter.fire( 'event2' );
+
+		listener.stopListening( emitter );
+
+		emitter.fire( 'event1' );
+		emitter.fire( 'event2' );
+
+		sinon.assert.calledOnce( spy1 );
+		sinon.assert.calledOnce( spy2 );
+	} );
+
+	it( 'should stop listening to everything', function() {
+		var spy1 = sinon.spy();
+		var spy2 = sinon.spy();
+
+		var emitter1 = getEmitterInstance();
+		var emitter2 = getEmitterInstance();
+
+		listener.listenTo( emitter1, 'event1', spy1 );
+		listener.listenTo( emitter2, 'event2', spy2 );
+
+		expect( listener ).to.have.property( '_listeningTo' );
+
+		emitter1.fire( 'event1' );
+		emitter2.fire( 'event2' );
+
+		listener.stopListening();
+
+		emitter1.fire( 'event1' );
+		emitter2.fire( 'event2' );
+
+		sinon.assert.calledOnce( spy1 );
+		sinon.assert.calledOnce( spy2 );
+
+		expect( listener ).to.not.have.property( '_listeningTo' );
+	} );
+
+	it( 'should not stop other emitters when a non-listened emitter is provided', function() {
+		var spy = sinon.spy();
+
+		var emitter1 = getEmitterInstance();
+		var emitter2 = getEmitterInstance();
+
+		listener.listenTo( emitter1, 'test', spy );
+
+		listener.stopListening( emitter2 );
+
+		emitter1.fire( 'test' );
+
+		sinon.assert.called( spy );
+	} );
+} );
+
+function refreshEmitter() {
+	emitter = getEmitterInstance();
+}
+
+function refreshListener() {
+	listener = getEmitterInstance();
+}
+
+function getEmitterInstance() {
+	var Emitter = modules.emitter;
+	var utils = modules.utils;
+
+	return utils.extend( {}, Emitter );
+}

+ 48 - 0
packages/ckeditor5-ui/tests/eventinfo/eventinfo.js

@@ -0,0 +1,48 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* globals describe, it, expect, bender */
+
+'use strict';
+
+var modules = bender.amd.require( 'eventinfo' );
+
+describe( 'EventInfo', function() {
+	it( 'should be created properly', function() {
+		var EventInfo = modules.eventinfo;
+
+		var event = new EventInfo( 'test' );
+
+		expect( event.name ).to.equals( 'test' );
+		expect( event.stop.called ).to.not.be.true();
+		expect( event.off.called ).to.not.be.true();
+	} );
+
+	it( 'should have stop() and off() marked', function() {
+		var EventInfo = modules.eventinfo;
+
+		var event = new EventInfo( 'test' );
+
+		event.stop();
+		event.off();
+
+		expect( event.stop.called ).to.be.true();
+		expect( event.off.called ).to.be.true();
+	} );
+
+	it( 'should not mark "called" in future instances', function() {
+		var EventInfo = modules.eventinfo;
+
+		var event = new EventInfo( 'test' );
+
+		event.stop();
+		event.off();
+
+		event = new EventInfo( 'test' );
+
+		expect( event.stop.called ).to.not.be.true();
+		expect( event.off.called ).to.not.be.true();
+	} );
+} );