123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 |
- // Copyright 2005 The Closure Library Authors. 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 Class to create objects which want to handle multiple events
- * and have their listeners easily cleaned up via a dispose method.
- *
- * Example:
- * <pre>
- * function Something() {
- * Something.base(this);
- *
- * ... set up object ...
- *
- * // Add event listeners
- * this.listen(this.starEl, goog.events.EventType.CLICK, this.handleStar);
- * this.listen(this.headerEl, goog.events.EventType.CLICK, this.expand);
- * this.listen(this.collapseEl, goog.events.EventType.CLICK, this.collapse);
- * this.listen(this.infoEl, goog.events.EventType.MOUSEOVER, this.showHover);
- * this.listen(this.infoEl, goog.events.EventType.MOUSEOUT, this.hideHover);
- * }
- * goog.inherits(Something, goog.events.EventHandler);
- *
- * Something.prototype.disposeInternal = function() {
- * Something.base(this, 'disposeInternal');
- * goog.dom.removeNode(this.container);
- * };
- *
- *
- * // Then elsewhere:
- *
- * var activeSomething = null;
- * function openSomething() {
- * activeSomething = new Something();
- * }
- *
- * function closeSomething() {
- * if (activeSomething) {
- * activeSomething.dispose(); // Remove event listeners
- * activeSomething = null;
- * }
- * }
- * </pre>
- *
- */
- goog.provide('goog.events.EventHandler');
- goog.require('goog.Disposable');
- goog.require('goog.events');
- goog.require('goog.object');
- goog.forwardDeclare('goog.events.EventWrapper');
- /**
- * Super class for objects that want to easily manage a number of event
- * listeners. It allows a short cut to listen and also provides a quick way
- * to remove all events listeners belonging to this object.
- * @param {SCOPE=} opt_scope Object in whose scope to call the listeners.
- * @constructor
- * @extends {goog.Disposable}
- * @template SCOPE
- */
- goog.events.EventHandler = function(opt_scope) {
- goog.Disposable.call(this);
- // TODO(mknichel): Rename this to this.scope_ and fix the classes in google3
- // that access this private variable. :(
- this.handler_ = opt_scope;
- /**
- * Keys for events that are being listened to.
- * @type {!Object<!goog.events.Key>}
- * @private
- */
- this.keys_ = {};
- };
- goog.inherits(goog.events.EventHandler, goog.Disposable);
- /**
- * Utility array used to unify the cases of listening for an array of types
- * and listening for a single event, without using recursion or allocating
- * an array each time.
- * @type {!Array<string>}
- * @const
- * @private
- */
- goog.events.EventHandler.typeArray_ = [];
- /**
- * Listen to an event on a Listenable. If the function is omitted then the
- * EventHandler's handleEvent method will be used.
- * @param {goog.events.ListenableType} src Event source.
- * @param {string|Array<string>|
- * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
- * type Event type to listen for or array of event types.
- * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
- * opt_fn Optional callback function to be used as the listener or an object
- * with handleEvent function.
- * @param {(boolean|!AddEventListenerOptions)=} opt_options
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template EVENTOBJ, THIS
- */
- goog.events.EventHandler.prototype.listen = function(
- src, type, opt_fn, opt_options) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- return self.listen_(src, type, opt_fn, opt_options);
- };
- /**
- * Listen to an event on a Listenable. If the function is omitted then the
- * EventHandler's handleEvent method will be used.
- * @param {goog.events.ListenableType} src Event source.
- * @param {string|Array<string>|
- * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
- * type Event type to listen for or array of event types.
- * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}|
- * null|undefined} fn Optional callback function to be used as the
- * listener or an object with handleEvent function.
- * @param {boolean|!AddEventListenerOptions|undefined} options
- * @param {T} scope Object in whose scope to call the listener.
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template T, EVENTOBJ, THIS
- */
- goog.events.EventHandler.prototype.listenWithScope = function(
- src, type, fn, options, scope) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- // TODO(mknichel): Deprecate this function.
- return self.listen_(src, type, fn, options, scope);
- };
- /**
- * Listen to an event on a Listenable. If the function is omitted then the
- * EventHandler's handleEvent method will be used.
- * @param {goog.events.ListenableType} src Event source.
- * @param {string|Array<string>|
- * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
- * type Event type to listen for or array of event types.
- * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
- * Optional callback function to be used as the listener or an object with
- * handleEvent function.
- * @param {(boolean|!AddEventListenerOptions)=} opt_options
- * @param {Object=} opt_scope Object in whose scope to call the listener.
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template EVENTOBJ, THIS
- * @private
- */
- goog.events.EventHandler.prototype.listen_ = function(
- src, type, opt_fn, opt_options, opt_scope) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- if (!goog.isArray(type)) {
- if (type) {
- goog.events.EventHandler.typeArray_[0] = type.toString();
- }
- type = goog.events.EventHandler.typeArray_;
- }
- for (var i = 0; i < type.length; i++) {
- var listenerObj = goog.events.listen(
- src, type[i], opt_fn || self.handleEvent, opt_options || false,
- opt_scope || self.handler_ || self);
- if (!listenerObj) {
- // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT
- // (goog.events.CaptureSimulationMode) in IE8-, it will return null
- // value.
- return self;
- }
- var key = listenerObj.key;
- self.keys_[key] = listenerObj;
- }
- return self;
- };
- /**
- * Listen to an event on a Listenable. If the function is omitted, then the
- * EventHandler's handleEvent method will be used. After the event has fired the
- * event listener is removed from the target. If an array of event types is
- * provided, each event type will be listened to once.
- * @param {goog.events.ListenableType} src Event source.
- * @param {string|Array<string>|
- * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
- * type Event type to listen for or array of event types.
- * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
- * opt_fn
- * Optional callback function to be used as the listener or an object with
- * handleEvent function.
- * @param {(boolean|!AddEventListenerOptions)=} opt_options
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template EVENTOBJ, THIS
- */
- goog.events.EventHandler.prototype.listenOnce = function(
- src, type, opt_fn, opt_options) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- return self.listenOnce_(src, type, opt_fn, opt_options);
- };
- /**
- * Listen to an event on a Listenable. If the function is omitted, then the
- * EventHandler's handleEvent method will be used. After the event has fired the
- * event listener is removed from the target. If an array of event types is
- * provided, each event type will be listened to once.
- * @param {goog.events.ListenableType} src Event source.
- * @param {string|Array<string>|
- * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
- * type Event type to listen for or array of event types.
- * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}|
- * null|undefined} fn Optional callback function to be used as the
- * listener or an object with handleEvent function.
- * @param {boolean|undefined} capture Optional whether to use capture phase.
- * @param {T} scope Object in whose scope to call the listener.
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template T, EVENTOBJ, THIS
- */
- goog.events.EventHandler.prototype.listenOnceWithScope = function(
- src, type, fn, capture, scope) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- // TODO(mknichel): Deprecate this function.
- return self.listenOnce_(src, type, fn, capture, scope);
- };
- /**
- * Listen to an event on a Listenable. If the function is omitted, then the
- * EventHandler's handleEvent method will be used. After the event has fired
- * the event listener is removed from the target. If an array of event types is
- * provided, each event type will be listened to once.
- * @param {goog.events.ListenableType} src Event source.
- * @param {string|Array<string>|
- * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
- * type Event type to listen for or array of event types.
- * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
- * Optional callback function to be used as the listener or an object with
- * handleEvent function.
- * @param {(boolean|!AddEventListenerOptions)=} opt_options
- * @param {Object=} opt_scope Object in whose scope to call the listener.
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template EVENTOBJ, THIS
- * @private
- */
- goog.events.EventHandler.prototype.listenOnce_ = function(
- src, type, opt_fn, opt_options, opt_scope) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- if (goog.isArray(type)) {
- for (var i = 0; i < type.length; i++) {
- self.listenOnce_(src, type[i], opt_fn, opt_options, opt_scope);
- }
- } else {
- var listenerObj = goog.events.listenOnce(
- src, type, opt_fn || self.handleEvent, opt_options,
- opt_scope || self.handler_ || self);
- if (!listenerObj) {
- // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT
- // (goog.events.CaptureSimulationMode) in IE8-, it will return null
- // value.
- return self;
- }
- var key = listenerObj.key;
- self.keys_[key] = listenerObj;
- }
- return self;
- };
- /**
- * Adds an event listener with a specific event wrapper on a DOM Node or an
- * object that has implemented {@link goog.events.EventTarget}. A listener can
- * only be added once to an object.
- *
- * @param {EventTarget|goog.events.EventTarget} src The node to listen to
- * events on.
- * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
- * @param {function(this:SCOPE, ?):?|{handleEvent:function(?):?}|null} listener
- * Callback method, or an object with a handleEvent function.
- * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
- * false).
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template THIS
- */
- goog.events.EventHandler.prototype.listenWithWrapper = function(
- src, wrapper, listener, opt_capt) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- // TODO(mknichel): Remove the opt_scope from this function and then
- // templatize it.
- return self.listenWithWrapper_(src, wrapper, listener, opt_capt);
- };
- /**
- * Adds an event listener with a specific event wrapper on a DOM Node or an
- * object that has implemented {@link goog.events.EventTarget}. A listener can
- * only be added once to an object.
- *
- * @param {EventTarget|goog.events.EventTarget} src The node to listen to
- * events on.
- * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
- * @param {function(this:T, ?):?|{handleEvent:function(this:T, ?):?}|null}
- * listener Optional callback function to be used as the
- * listener or an object with handleEvent function.
- * @param {boolean|undefined} capture Optional whether to use capture phase.
- * @param {T} scope Object in whose scope to call the listener.
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template T, THIS
- */
- goog.events.EventHandler.prototype.listenWithWrapperAndScope = function(
- src, wrapper, listener, capture, scope) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- // TODO(mknichel): Deprecate this function.
- return self.listenWithWrapper_(src, wrapper, listener, capture, scope);
- };
- /**
- * Adds an event listener with a specific event wrapper on a DOM Node or an
- * object that has implemented {@link goog.events.EventTarget}. A listener can
- * only be added once to an object.
- *
- * @param {EventTarget|goog.events.EventTarget} src The node to listen to
- * events on.
- * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
- * @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
- * method, or an object with a handleEvent function.
- * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
- * false).
- * @param {Object=} opt_scope Element in whose scope to call the listener.
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template THIS
- * @private
- */
- goog.events.EventHandler.prototype.listenWithWrapper_ = function(
- src, wrapper, listener, opt_capt, opt_scope) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- wrapper.listen(
- src, listener, opt_capt, opt_scope || self.handler_ || self, self);
- return self;
- };
- /**
- * @return {number} Number of listeners registered by this handler.
- */
- goog.events.EventHandler.prototype.getListenerCount = function() {
- var count = 0;
- for (var key in this.keys_) {
- if (Object.prototype.hasOwnProperty.call(this.keys_, key)) {
- count++;
- }
- }
- return count;
- };
- /**
- * Unlistens on an event.
- * @param {goog.events.ListenableType} src Event source.
- * @param {string|Array<string>|
- * !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
- * type Event type or array of event types to unlisten to.
- * @param {function(this:?, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
- * opt_fn Optional callback function to be used as the listener or an object
- * with handleEvent function.
- * @param {(boolean|!EventListenerOptions)=} opt_options
- * @param {Object=} opt_scope Object in whose scope to call the listener.
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template EVENTOBJ, THIS
- */
- goog.events.EventHandler.prototype.unlisten = function(
- src, type, opt_fn, opt_options, opt_scope) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- if (goog.isArray(type)) {
- for (var i = 0; i < type.length; i++) {
- self.unlisten(src, type[i], opt_fn, opt_options, opt_scope);
- }
- } else {
- var capture =
- goog.isObject(opt_options) ? !!opt_options.capture : !!opt_options;
- var listener = goog.events.getListener(
- src, type, opt_fn || self.handleEvent, capture,
- opt_scope || self.handler_ || self);
- if (listener) {
- goog.events.unlistenByKey(listener);
- delete self.keys_[listener.key];
- }
- }
- return self;
- };
- /**
- * Removes an event listener which was added with listenWithWrapper().
- *
- * @param {EventTarget|goog.events.EventTarget} src The target to stop
- * listening to events on.
- * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
- * @param {function(?):?|{handleEvent:function(?):?}|null} listener The
- * listener function to remove.
- * @param {boolean=} opt_capt In DOM-compliant browsers, this determines
- * whether the listener is fired during the capture or bubble phase of the
- * event.
- * @param {Object=} opt_scope Element in whose scope to call the listener.
- * @return {THIS} This object, allowing for chaining of calls.
- * @this {THIS}
- * @template THIS
- */
- goog.events.EventHandler.prototype.unlistenWithWrapper = function(
- src, wrapper, listener, opt_capt, opt_scope) {
- var self = /** @type {!goog.events.EventHandler} */ (this);
- wrapper.unlisten(
- src, listener, opt_capt, opt_scope || self.handler_ || self, self);
- return self;
- };
- /**
- * Unlistens to all events.
- */
- goog.events.EventHandler.prototype.removeAll = function() {
- goog.object.forEach(this.keys_, function(listenerObj, key) {
- if (this.keys_.hasOwnProperty(key)) {
- goog.events.unlistenByKey(listenerObj);
- }
- }, this);
- this.keys_ = {};
- };
- /**
- * Disposes of this EventHandler and removes all listeners that it registered.
- * @override
- * @protected
- */
- goog.events.EventHandler.prototype.disposeInternal = function() {
- goog.events.EventHandler.superClass_.disposeInternal.call(this);
- this.removeAll();
- };
- /**
- * Default event handler
- * @param {goog.events.Event} e Event object.
- */
- goog.events.EventHandler.prototype.handleEvent = function(e) {
- throw Error('EventHandler.handleEvent not implemented');
- };
|