You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
5.5 KiB

// Copyright 2011 Software Freedom Conservancy. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview A light weight event system modeled after Node's EventEmitter.
*/
goog.provide('webdriver.EventEmitter');
/**
* Object that can emit events for others to listen for. This is used instead
* of Closure's event system because it is much more light weight. The API is
* based on Node's EventEmitters.
* @constructor
*/
webdriver.EventEmitter = function() {
/**
* Map of events to registered listeners.
* @private {!Object.<!Array.<{fn: !Function, oneshot: boolean,
* scope: (Object|undefined)}>>}
*/
this.events_ = {};
};
/**
* Fires an event and calls all listeners.
* @param {string} type The type of event to emit.
* @param {...*} var_args Any arguments to pass to each listener.
*/
webdriver.EventEmitter.prototype.emit = function(type, var_args) {
var args = Array.prototype.slice.call(arguments, 1);
var listeners = this.events_[type];
if (!listeners) {
return;
}
for (var i = 0; i < listeners.length;) {
var listener = listeners[i];
listener.fn.apply(listener.scope, args);
if (listeners[i] === listener) {
if (listeners[i].oneshot) {
listeners.splice(i, 1);
} else {
i += 1;
}
}
}
};
/**
* Returns a mutable list of listeners for a specific type of event.
* @param {string} type The type of event to retrieve the listeners for.
* @return {!Array.<{fn: !Function, oneshot: boolean,
* scope: (Object|undefined)}>} The registered listeners for
* the given event type.
*/
webdriver.EventEmitter.prototype.listeners = function(type) {
var listeners = this.events_[type];
if (!listeners) {
listeners = this.events_[type] = [];
}
return listeners;
};
/**
* Registers a listener.
* @param {string} type The type of event to listen for.
* @param {!Function} listenerFn The function to invoke when the event is fired.
* @param {Object=} opt_scope The object in whose scope to invoke the listener.
* @param {boolean=} opt_oneshot Whether the listener should be removed after
* the first event is fired.
* @return {!webdriver.EventEmitter} A self reference.
* @private
*/
webdriver.EventEmitter.prototype.addListener_ = function(type, listenerFn,
opt_scope, opt_oneshot) {
var listeners = this.listeners(type);
var n = listeners.length;
for (var i = 0; i < n; ++i) {
if (listeners[i].fn == listenerFn) {
return this;
}
}
listeners.push({
fn: listenerFn,
scope: opt_scope,
oneshot: !!opt_oneshot
});
return this;
};
/**
* Registers a listener.
* @param {string} type The type of event to listen for.
* @param {!Function} listenerFn The function to invoke when the event is fired.
* @param {Object=} opt_scope The object in whose scope to invoke the listener.
* @return {!webdriver.EventEmitter} A self reference.
*/
webdriver.EventEmitter.prototype.addListener = function(type, listenerFn,
opt_scope) {
return this.addListener_(type, listenerFn, opt_scope);
};
/**
* Registers a one-time listener which will be called only the first time an
* event is emitted, after which it will be removed.
* @param {string} type The type of event to listen for.
* @param {!Function} listenerFn The function to invoke when the event is fired.
* @param {Object=} opt_scope The object in whose scope to invoke the listener.
* @return {!webdriver.EventEmitter} A self reference.
*/
webdriver.EventEmitter.prototype.once = function(type, listenerFn, opt_scope) {
return this.addListener_(type, listenerFn, opt_scope, true);
};
/**
* An alias for {@code #addListener()}.
* @param {string} type The type of event to listen for.
* @param {!Function} listenerFn The function to invoke when the event is fired.
* @param {Object=} opt_scope The object in whose scope to invoke the listener.
* @return {!webdriver.EventEmitter} A self reference.
*/
webdriver.EventEmitter.prototype.on =
webdriver.EventEmitter.prototype.addListener;
/**
* Removes a previously registered event listener.
* @param {string} type The type of event to unregister.
* @param {!Function} listenerFn The handler function to remove.
* @return {!webdriver.EventEmitter} A self reference.
*/
webdriver.EventEmitter.prototype.removeListener = function(type, listenerFn) {
var listeners = this.events_[type];
if (listeners) {
var n = listeners.length;
for (var i = 0; i < n; ++i) {
if (listeners[i].fn == listenerFn) {
listeners.splice(i, 1);
return this;
}
}
}
return this;
};
/**
* Removes all listeners for a specific type of event. If no event is
* specified, all listeners across all types will be removed.
* @param {string=} opt_type The type of event to remove listeners from.
* @return {!webdriver.EventEmitter} A self reference.
*/
webdriver.EventEmitter.prototype.removeAllListeners = function(opt_type) {
goog.isDef(opt_type) ? delete this.events_[opt_type] : this.events_ = {};
return this;
};