2012-07-19 00:11:26 +00:00
|
|
|
/**
|
|
|
|
* VisualEditor EventEmitter class.
|
2012-07-19 21:25:16 +00:00
|
|
|
*
|
2012-07-19 00:11:26 +00:00
|
|
|
* @copyright 2011-2012 VisualEditor Team and others; see AUTHORS.txt
|
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
2011-11-02 21:00:55 +00:00
|
|
|
/**
|
|
|
|
* Event emitter.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @class
|
2011-11-03 21:48:40 +00:00
|
|
|
* @abstract
|
2011-11-02 21:00:55 +00:00
|
|
|
* @constructor
|
2012-09-17 13:30:50 +00:00
|
|
|
* @property {Object} events
|
2011-11-02 21:00:55 +00:00
|
|
|
*/
|
2012-09-06 23:15:55 +00:00
|
|
|
ve.EventEmitter = function VeEventEmitter() {
|
2012-09-17 23:53:03 +00:00
|
|
|
// Properties
|
2011-11-02 21:00:55 +00:00
|
|
|
this.events = {};
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Methods */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Emits an event.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @method
|
2012-09-17 13:30:50 +00:00
|
|
|
* @param {String} type Type of event
|
|
|
|
* @param {Mixed} args First in a list of variadic arguments passed to event handler (optional)
|
2011-11-02 21:00:55 +00:00
|
|
|
* @returns {Boolean} If event was handled by at least one listener
|
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.EventEmitter.prototype.emit = function ( type ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
if ( type === 'error' && !( 'error' in this.events ) ) {
|
2012-08-08 17:48:53 +00:00
|
|
|
throw new Error( 'Missing error handler error.' );
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
|
|
|
if ( !( type in this.events ) ) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-08-02 18:46:13 +00:00
|
|
|
var i,
|
|
|
|
listeners = this.events[type].slice(),
|
|
|
|
length = listeners.length,
|
|
|
|
args = Array.prototype.slice.call( arguments, 1 );
|
|
|
|
for ( i = 0; i < length; i++ ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
listeners[i].apply( this, args );
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a listener to events of a specific type.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @method
|
2012-09-17 13:30:50 +00:00
|
|
|
* @param {String} type Type of event to listen to
|
|
|
|
* @param {Function} listener Listener to call when event occurs
|
2012-02-06 23:50:56 +00:00
|
|
|
* @returns {ve.EventEmitter} This object
|
2011-11-02 21:00:55 +00:00
|
|
|
* @throws "Invalid listener error" if listener argument is not a function
|
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.EventEmitter.prototype.addListener = function ( type, listener ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
if ( typeof listener !== 'function' ) {
|
2012-08-08 17:48:53 +00:00
|
|
|
throw new Error( 'Invalid listener error. Function expected.' );
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
|
|
|
this.emit( 'newListener', type, listener );
|
|
|
|
if ( type in this.events ) {
|
|
|
|
this.events[type].push( listener );
|
|
|
|
} else {
|
|
|
|
this.events[type] = [listener];
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add multiple listeners at once.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @method
|
2012-09-17 13:30:50 +00:00
|
|
|
* @param {Object} listeners List of event/callback pairs
|
2012-02-06 23:50:56 +00:00
|
|
|
* @returns {ve.EventEmitter} This object
|
2011-11-02 21:00:55 +00:00
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.EventEmitter.prototype.addListeners = function ( listeners ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
for ( var event in listeners ) {
|
|
|
|
this.addListener( event, listeners[event] );
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a listener, mapped to a method on a target object.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @method
|
2012-09-17 13:30:50 +00:00
|
|
|
* @param {Object} target Object to call methods on when events occur
|
|
|
|
* @param {String} event Name of event to trigger on
|
|
|
|
* @param {String} method Name of method to call
|
2012-02-06 23:50:56 +00:00
|
|
|
* @returns {ve.EventEmitter} This object
|
2011-11-02 21:00:55 +00:00
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.EventEmitter.prototype.addListenerMethod = function ( target, event, method ) {
|
|
|
|
return this.addListener( event, function () {
|
2011-11-02 21:00:55 +00:00
|
|
|
if ( typeof target[method] === 'function' ) {
|
|
|
|
target[method].apply( target, Array.prototype.slice.call( arguments, 0 ) );
|
|
|
|
} else {
|
2012-08-08 17:48:53 +00:00
|
|
|
throw new Error( 'Listener method error. Target has no such method: ' + method );
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add multiple listeners, each mapped to a method on a target object.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @method
|
2012-09-17 13:30:50 +00:00
|
|
|
* @param {Object} target Object to call methods on when events occur
|
|
|
|
* @param {Object} methods List of event/method name pairs
|
2012-02-06 23:50:56 +00:00
|
|
|
* @returns {ve.EventEmitter} This object
|
2011-11-02 21:00:55 +00:00
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.EventEmitter.prototype.addListenerMethods = function ( target, methods ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
for ( var event in methods ) {
|
|
|
|
this.addListenerMethod( target, event, methods[event] );
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Alias for addListener
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @method
|
|
|
|
*/
|
2012-02-06 23:50:56 +00:00
|
|
|
ve.EventEmitter.prototype.on = ve.EventEmitter.prototype.addListener;
|
2011-11-02 21:00:55 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a one-time listener to a specific event.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @method
|
2012-09-17 13:30:50 +00:00
|
|
|
* @param {String} type Type of event to listen to
|
|
|
|
* @param {Function} listener Listener to call when event occurs
|
2012-02-06 23:50:56 +00:00
|
|
|
* @returns {ve.EventEmitter} This object
|
2011-11-02 21:00:55 +00:00
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.EventEmitter.prototype.once = function ( type, listener ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
var eventEmitter = this;
|
|
|
|
return this.addListener( type, function listenerWrapper() {
|
|
|
|
eventEmitter.removeListener( type, listenerWrapper );
|
|
|
|
listener.apply( eventEmitter, Array.prototype.slice.call( arguments, 0 ) );
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes a specific listener from a specific event.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @method
|
2012-09-17 13:30:50 +00:00
|
|
|
* @param {String} type Type of event to remove listener from
|
|
|
|
* @param {Function} listener Listener to remove
|
2012-02-06 23:50:56 +00:00
|
|
|
* @returns {ve.EventEmitter} This object
|
2011-11-02 21:00:55 +00:00
|
|
|
* @throws "Invalid listener error" if listener argument is not a function
|
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.EventEmitter.prototype.removeListener = function ( type, listener ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
if ( typeof listener !== 'function' ) {
|
2012-08-08 17:48:53 +00:00
|
|
|
throw new Error( 'Invalid listener error. Function expected.' );
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
|
|
|
if ( !( type in this.events ) || !this.events[type].length ) {
|
|
|
|
return this;
|
|
|
|
}
|
2012-08-02 18:46:13 +00:00
|
|
|
var i,
|
|
|
|
handlers = this.events[type];
|
2011-11-02 21:00:55 +00:00
|
|
|
if ( handlers.length === 1 && handlers[0] === listener ) {
|
|
|
|
delete this.events[type];
|
|
|
|
} else {
|
2012-08-11 08:14:56 +00:00
|
|
|
i = ve.indexOf( listener, handlers );
|
2011-11-02 21:00:55 +00:00
|
|
|
if ( i < 0 ) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
handlers.splice( i, 1 );
|
|
|
|
if ( handlers.length === 0 ) {
|
|
|
|
delete this.events[type];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes all listeners from a specific event.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @method
|
2012-09-17 13:30:50 +00:00
|
|
|
* @param {String} type Type of event to remove listeners from
|
2012-02-06 23:50:56 +00:00
|
|
|
* @returns {ve.EventEmitter} This object
|
2011-11-02 21:00:55 +00:00
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.EventEmitter.prototype.removeAllListeners = function ( type ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
if ( type in this.events ) {
|
|
|
|
delete this.events[type];
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a list of listeners attached to a specific event.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @method
|
2012-09-17 13:30:50 +00:00
|
|
|
* @param {String} type Type of event to get listeners for
|
2011-11-02 21:00:55 +00:00
|
|
|
* @returns {Array} List of listeners to an event
|
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.EventEmitter.prototype.listeners = function ( type ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
return type in this.events ? this.events[type] : [];
|
|
|
|
};
|