diff options
Diffstat (limited to 'node_modules/selenium-webdriver/lib/events.js')
-rw-r--r-- | node_modules/selenium-webdriver/lib/events.js | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/node_modules/selenium-webdriver/lib/events.js b/node_modules/selenium-webdriver/lib/events.js new file mode 100644 index 000000000..65e63de8c --- /dev/null +++ b/node_modules/selenium-webdriver/lib/events.js @@ -0,0 +1,210 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you 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. + +'use strict'; + +/** + * Describes an event listener registered on an {@linkplain EventEmitter}. + */ +class Listener { + /** + * @param {!Function} fn The acutal listener function. + * @param {(Object|undefined)} scope The object in whose scope to invoke the + * listener. + * @param {boolean} oneshot Whether this listener should only be used once. + */ + constructor(fn, scope, oneshot) { + this.fn = fn; + this.scope = scope; + this.oneshot = oneshot; + } +} + + +/** @type {!WeakMap<!EventEmitter, !Map<string, !Set<!Listener>>>} */ +const EVENTS = new WeakMap; + + +/** + * Object that can emit events for others to listen for. + */ +class EventEmitter { + /** + * 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. + */ + emit(type, var_args) { + let events = EVENTS.get(this); + if (!events) { + return; + } + + let args = Array.prototype.slice.call(arguments, 1); + + let listeners = events.get(type); + if (listeners) { + for (let listener of listeners) { + listener.fn.apply(listener.scope, args); + if (listener.oneshot) { + listeners.delete(listener); + } + } + } + } + + /** + * 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 {!Set<!Listener>} The registered listeners for the given event + * type. + */ + listeners(type) { + let events = EVENTS.get(this); + if (!events) { + events = new Map; + EVENTS.set(this, events); + } + + let listeners = events.get(type); + if (!listeners) { + listeners = new Set; + events.set(type, listeners); + } + return listeners; + } + + /** + * Registers a listener. + * @param {string} type The type of event to listen for. + * @param {!Function} fn The function to invoke when the event is fired. + * @param {Object=} opt_self The object in whose scope to invoke the listener. + * @param {boolean=} opt_oneshot Whether the listener should b (e removed after + * the first event is fired. + * @return {!EventEmitter} A self reference. + * @private + */ + addListener_(type, fn, opt_self, opt_oneshot) { + let listeners = this.listeners(type); + for (let listener of listeners) { + if (listener.fn === fn) { + return this; + } + } + listeners.add(new Listener(fn, opt_self || undefined, !!opt_oneshot)); + return this; + } + + /** + * Registers a listener. + * @param {string} type The type of event to listen for. + * @param {!Function} fn The function to invoke when the event is fired. + * @param {Object=} opt_self The object in whose scope to invoke the listener. + * @return {!EventEmitter} A self reference. + */ + addListener(type, fn, opt_self) { + return this.addListener_(type, fn, opt_self, false); + } + + /** + * 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} fn The function to invoke when the event is fired. + * @param {Object=} opt_self The object in whose scope to invoke the listener. + * @return {!EventEmitter} A self reference. + */ + once(type, fn, opt_self) { + return this.addListener_(type, fn, opt_self, true); + } + + /** + * An alias for {@link #addListener() addListener()}. + * @param {string} type The type of event to listen for. + * @param {!Function} fn The function to invoke when the event is fired. + * @param {Object=} opt_self The object in whose scope to invoke the listener. + * @return {!EventEmitter} A self reference. + */ + on(type, fn, opt_self) { + return this.addListener(type, fn, opt_self); + } + + /** + * Removes a previously registered event listener. + * @param {string} type The type of event to unregister. + * @param {!Function} listenerFn The handler function to remove. + * @return {!EventEmitter} A self reference. + */ + removeListener(type, listenerFn) { + if (typeof type !== 'string' || typeof listenerFn !== 'function') { + throw TypeError('invalid args: expected (string, function), got (' + + (typeof type) + ', ' + (typeof listenerFn) + ')'); + } + + let events = EVENTS.get(this); + if (!events) { + return this; + } + + let listeners = events.get(type); + if (!listeners) { + return this; + } + + let match; + for (let listener of listeners) { + if (listener.fn === listenerFn) { + match = listener; + break; + } + } + if (match) { + listeners.delete(match); + if (!listeners.size) { + events.delete(type); + } + } + 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 {!EventEmitter} A self reference. + */ + removeAllListeners(opt_type) { + let events = EVENTS.get(this); + if (events) { + if (typeof opt_type === 'string') { + events.delete(opt_type); + } else { + EVENTS.delete(this); + } + } + return this; + } +} + + +// PUBLIC API + + +module.exports = { + EventEmitter: EventEmitter, + Listener: Listener +}; |