lib/webdriver/events.js

1// Copyright 2011 Software Freedom Conservancy. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/**
16 * @fileoverview A light weight event system modeled after Node's EventEmitter.
17 */
18
19goog.provide('webdriver.EventEmitter');
20
21
22
23/**
24 * Object that can emit events for others to listen for. This is used instead
25 * of Closure's event system because it is much more light weight. The API is
26 * based on Node's EventEmitters.
27 * @constructor
28 */
29webdriver.EventEmitter = function() {
30 /**
31 * Map of events to registered listeners.
32 * @private {!Object.<!Array.<{fn: !Function, oneshot: boolean,
33 * scope: (Object|undefined)}>>}
34 */
35 this.events_ = {};
36};
37
38
39/**
40 * Fires an event and calls all listeners.
41 * @param {string} type The type of event to emit.
42 * @param {...*} var_args Any arguments to pass to each listener.
43 */
44webdriver.EventEmitter.prototype.emit = function(type, var_args) {
45 var args = Array.prototype.slice.call(arguments, 1);
46 var listeners = this.events_[type];
47 if (!listeners) {
48 return;
49 }
50 for (var i = 0; i < listeners.length;) {
51 var listener = listeners[i];
52 listener.fn.apply(listener.scope, args);
53 if (listeners[i] === listener) {
54 if (listeners[i].oneshot) {
55 listeners.splice(i, 1);
56 } else {
57 i += 1;
58 }
59 }
60 }
61};
62
63
64/**
65 * Returns a mutable list of listeners for a specific type of event.
66 * @param {string} type The type of event to retrieve the listeners for.
67 * @return {!Array.<{fn: !Function, oneshot: boolean,
68 * scope: (Object|undefined)}>} The registered listeners for
69 * the given event type.
70 */
71webdriver.EventEmitter.prototype.listeners = function(type) {
72 var listeners = this.events_[type];
73 if (!listeners) {
74 listeners = this.events_[type] = [];
75 }
76 return listeners;
77};
78
79
80/**
81 * Registers a listener.
82 * @param {string} type The type of event to listen for.
83 * @param {!Function} listenerFn The function to invoke when the event is fired.
84 * @param {Object=} opt_scope The object in whose scope to invoke the listener.
85 * @param {boolean=} opt_oneshot Whether the listener should be removed after
86 * the first event is fired.
87 * @return {!webdriver.EventEmitter} A self reference.
88 * @private
89 */
90webdriver.EventEmitter.prototype.addListener_ = function(type, listenerFn,
91 opt_scope, opt_oneshot) {
92 var listeners = this.listeners(type);
93 var n = listeners.length;
94 for (var i = 0; i < n; ++i) {
95 if (listeners[i].fn == listenerFn) {
96 return this;
97 }
98 }
99
100 listeners.push({
101 fn: listenerFn,
102 scope: opt_scope,
103 oneshot: !!opt_oneshot
104 });
105 return this;
106};
107
108
109/**
110 * Registers a listener.
111 * @param {string} type The type of event to listen for.
112 * @param {!Function} listenerFn The function to invoke when the event is fired.
113 * @param {Object=} opt_scope The object in whose scope to invoke the listener.
114 * @return {!webdriver.EventEmitter} A self reference.
115 */
116webdriver.EventEmitter.prototype.addListener = function(type, listenerFn,
117 opt_scope) {
118 return this.addListener_(type, listenerFn, opt_scope);
119};
120
121
122/**
123 * Registers a one-time listener which will be called only the first time an
124 * event is emitted, after which it will be removed.
125 * @param {string} type The type of event to listen for.
126 * @param {!Function} listenerFn The function to invoke when the event is fired.
127 * @param {Object=} opt_scope The object in whose scope to invoke the listener.
128 * @return {!webdriver.EventEmitter} A self reference.
129 */
130webdriver.EventEmitter.prototype.once = function(type, listenerFn, opt_scope) {
131 return this.addListener_(type, listenerFn, opt_scope, true);
132};
133
134
135/**
136 * An alias for {@code #addListener()}.
137 * @param {string} type The type of event to listen for.
138 * @param {!Function} listenerFn The function to invoke when the event is fired.
139 * @param {Object=} opt_scope The object in whose scope to invoke the listener.
140 * @return {!webdriver.EventEmitter} A self reference.
141 */
142webdriver.EventEmitter.prototype.on =
143 webdriver.EventEmitter.prototype.addListener;
144
145
146/**
147 * Removes a previously registered event listener.
148 * @param {string} type The type of event to unregister.
149 * @param {!Function} listenerFn The handler function to remove.
150 * @return {!webdriver.EventEmitter} A self reference.
151 */
152webdriver.EventEmitter.prototype.removeListener = function(type, listenerFn) {
153 var listeners = this.events_[type];
154 if (listeners) {
155 var n = listeners.length;
156 for (var i = 0; i < n; ++i) {
157 if (listeners[i].fn == listenerFn) {
158 listeners.splice(i, 1);
159 return this;
160 }
161 }
162 }
163 return this;
164};
165
166
167/**
168 * Removes all listeners for a specific type of event. If no event is
169 * specified, all listeners across all types will be removed.
170 * @param {string=} opt_type The type of event to remove listeners from.
171 * @return {!webdriver.EventEmitter} A self reference.
172 */
173webdriver.EventEmitter.prototype.removeAllListeners = function(opt_type) {
174 goog.isDef(opt_type) ? delete this.events_[opt_type] : this.events_ = {};
175 return this;
176};