# lib/webdriver/events.js

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