Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/events/eventhandler.js
2868 views
1
// Copyright 2005 The Closure Library Authors. 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 Class to create objects which want to handle multiple events
17
* and have their listeners easily cleaned up via a dispose method.
18
*
19
* Example:
20
* <pre>
21
* function Something() {
22
* Something.base(this);
23
*
24
* ... set up object ...
25
*
26
* // Add event listeners
27
* this.listen(this.starEl, goog.events.EventType.CLICK, this.handleStar);
28
* this.listen(this.headerEl, goog.events.EventType.CLICK, this.expand);
29
* this.listen(this.collapseEl, goog.events.EventType.CLICK, this.collapse);
30
* this.listen(this.infoEl, goog.events.EventType.MOUSEOVER, this.showHover);
31
* this.listen(this.infoEl, goog.events.EventType.MOUSEOUT, this.hideHover);
32
* }
33
* goog.inherits(Something, goog.events.EventHandler);
34
*
35
* Something.prototype.disposeInternal = function() {
36
* Something.base(this, 'disposeInternal');
37
* goog.dom.removeNode(this.container);
38
* };
39
*
40
*
41
* // Then elsewhere:
42
*
43
* var activeSomething = null;
44
* function openSomething() {
45
* activeSomething = new Something();
46
* }
47
*
48
* function closeSomething() {
49
* if (activeSomething) {
50
* activeSomething.dispose(); // Remove event listeners
51
* activeSomething = null;
52
* }
53
* }
54
* </pre>
55
*
56
*/
57
58
goog.provide('goog.events.EventHandler');
59
60
goog.require('goog.Disposable');
61
goog.require('goog.events');
62
goog.require('goog.object');
63
64
goog.forwardDeclare('goog.events.EventWrapper');
65
66
67
68
/**
69
* Super class for objects that want to easily manage a number of event
70
* listeners. It allows a short cut to listen and also provides a quick way
71
* to remove all events listeners belonging to this object.
72
* @param {SCOPE=} opt_scope Object in whose scope to call the listeners.
73
* @constructor
74
* @extends {goog.Disposable}
75
* @template SCOPE
76
*/
77
goog.events.EventHandler = function(opt_scope) {
78
goog.Disposable.call(this);
79
// TODO(mknichel): Rename this to this.scope_ and fix the classes in google3
80
// that access this private variable. :(
81
this.handler_ = opt_scope;
82
83
/**
84
* Keys for events that are being listened to.
85
* @type {!Object<!goog.events.Key>}
86
* @private
87
*/
88
this.keys_ = {};
89
};
90
goog.inherits(goog.events.EventHandler, goog.Disposable);
91
92
93
/**
94
* Utility array used to unify the cases of listening for an array of types
95
* and listening for a single event, without using recursion or allocating
96
* an array each time.
97
* @type {!Array<string>}
98
* @const
99
* @private
100
*/
101
goog.events.EventHandler.typeArray_ = [];
102
103
104
/**
105
* Listen to an event on a Listenable. If the function is omitted then the
106
* EventHandler's handleEvent method will be used.
107
* @param {goog.events.ListenableType} src Event source.
108
* @param {string|Array<string>|
109
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
110
* type Event type to listen for or array of event types.
111
* @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
112
* opt_fn Optional callback function to be used as the listener or an object
113
* with handleEvent function.
114
* @param {boolean=} opt_capture Optional whether to use capture phase.
115
* @return {THIS} This object, allowing for chaining of calls.
116
* @this {THIS}
117
* @template EVENTOBJ, THIS
118
*/
119
goog.events.EventHandler.prototype.listen = function(
120
src, type, opt_fn, opt_capture) {
121
var self = /** @type {!goog.events.EventHandler} */ (this);
122
return self.listen_(src, type, opt_fn, opt_capture);
123
};
124
125
126
/**
127
* Listen to an event on a Listenable. If the function is omitted then the
128
* EventHandler's handleEvent method will be used.
129
* @param {goog.events.ListenableType} src Event source.
130
* @param {string|Array<string>|
131
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
132
* type Event type to listen for or array of event types.
133
* @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}|
134
* null|undefined} fn Optional callback function to be used as the
135
* listener or an object with handleEvent function.
136
* @param {boolean|undefined} capture Optional whether to use capture phase.
137
* @param {T} scope Object in whose scope to call the listener.
138
* @return {THIS} This object, allowing for chaining of calls.
139
* @this {THIS}
140
* @template T, EVENTOBJ, THIS
141
*/
142
goog.events.EventHandler.prototype.listenWithScope = function(
143
src, type, fn, capture, scope) {
144
var self = /** @type {!goog.events.EventHandler} */ (this);
145
// TODO(mknichel): Deprecate this function.
146
return self.listen_(src, type, fn, capture, scope);
147
};
148
149
150
/**
151
* Listen to an event on a Listenable. If the function is omitted then the
152
* EventHandler's handleEvent method will be used.
153
* @param {goog.events.ListenableType} src Event source.
154
* @param {string|Array<string>|
155
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
156
* type Event type to listen for or array of event types.
157
* @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
158
* Optional callback function to be used as the listener or an object with
159
* handleEvent function.
160
* @param {boolean=} opt_capture Optional whether to use capture phase.
161
* @param {Object=} opt_scope Object in whose scope to call the listener.
162
* @return {THIS} This object, allowing for chaining of calls.
163
* @this {THIS}
164
* @template EVENTOBJ, THIS
165
* @private
166
*/
167
goog.events.EventHandler.prototype.listen_ = function(
168
src, type, opt_fn, opt_capture, opt_scope) {
169
var self = /** @type {!goog.events.EventHandler} */ (this);
170
if (!goog.isArray(type)) {
171
if (type) {
172
goog.events.EventHandler.typeArray_[0] = type.toString();
173
}
174
type = goog.events.EventHandler.typeArray_;
175
}
176
for (var i = 0; i < type.length; i++) {
177
var listenerObj = goog.events.listen(
178
src, type[i], opt_fn || self.handleEvent, opt_capture || false,
179
opt_scope || self.handler_ || self);
180
181
if (!listenerObj) {
182
// When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT
183
// (goog.events.CaptureSimulationMode) in IE8-, it will return null
184
// value.
185
return self;
186
}
187
188
var key = listenerObj.key;
189
self.keys_[key] = listenerObj;
190
}
191
192
return self;
193
};
194
195
196
/**
197
* Listen to an event on a Listenable. If the function is omitted, then the
198
* EventHandler's handleEvent method will be used. After the event has fired the
199
* event listener is removed from the target. If an array of event types is
200
* provided, each event type will be listened to once.
201
* @param {goog.events.ListenableType} src Event source.
202
* @param {string|Array<string>|
203
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
204
* type Event type to listen for or array of event types.
205
* @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
206
* opt_fn
207
* Optional callback function to be used as the listener or an object with
208
* handleEvent function.
209
* @param {boolean=} opt_capture Optional whether to use capture phase.
210
* @return {THIS} This object, allowing for chaining of calls.
211
* @this {THIS}
212
* @template EVENTOBJ, THIS
213
*/
214
goog.events.EventHandler.prototype.listenOnce = function(
215
src, type, opt_fn, opt_capture) {
216
var self = /** @type {!goog.events.EventHandler} */ (this);
217
return self.listenOnce_(src, type, opt_fn, opt_capture);
218
};
219
220
221
/**
222
* Listen to an event on a Listenable. If the function is omitted, then the
223
* EventHandler's handleEvent method will be used. After the event has fired the
224
* event listener is removed from the target. If an array of event types is
225
* provided, each event type will be listened to once.
226
* @param {goog.events.ListenableType} src Event source.
227
* @param {string|Array<string>|
228
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
229
* type Event type to listen for or array of event types.
230
* @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}|
231
* null|undefined} fn Optional callback function to be used as the
232
* listener or an object with handleEvent function.
233
* @param {boolean|undefined} capture Optional whether to use capture phase.
234
* @param {T} scope Object in whose scope to call the listener.
235
* @return {THIS} This object, allowing for chaining of calls.
236
* @this {THIS}
237
* @template T, EVENTOBJ, THIS
238
*/
239
goog.events.EventHandler.prototype.listenOnceWithScope = function(
240
src, type, fn, capture, scope) {
241
var self = /** @type {!goog.events.EventHandler} */ (this);
242
// TODO(mknichel): Deprecate this function.
243
return self.listenOnce_(src, type, fn, capture, scope);
244
};
245
246
247
/**
248
* Listen to an event on a Listenable. If the function is omitted, then the
249
* EventHandler's handleEvent method will be used. After the event has fired
250
* the event listener is removed from the target. If an array of event types is
251
* provided, each event type will be listened to once.
252
* @param {goog.events.ListenableType} src Event source.
253
* @param {string|Array<string>|
254
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
255
* type Event type to listen for or array of event types.
256
* @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
257
* Optional callback function to be used as the listener or an object with
258
* handleEvent function.
259
* @param {boolean=} opt_capture Optional whether to use capture phase.
260
* @param {Object=} opt_scope Object in whose scope to call the listener.
261
* @return {THIS} This object, allowing for chaining of calls.
262
* @this {THIS}
263
* @template EVENTOBJ, THIS
264
* @private
265
*/
266
goog.events.EventHandler.prototype.listenOnce_ = function(
267
src, type, opt_fn, opt_capture, opt_scope) {
268
var self = /** @type {!goog.events.EventHandler} */ (this);
269
if (goog.isArray(type)) {
270
for (var i = 0; i < type.length; i++) {
271
self.listenOnce_(src, type[i], opt_fn, opt_capture, opt_scope);
272
}
273
} else {
274
var listenerObj = goog.events.listenOnce(
275
src, type, opt_fn || self.handleEvent, opt_capture,
276
opt_scope || self.handler_ || self);
277
if (!listenerObj) {
278
// When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT
279
// (goog.events.CaptureSimulationMode) in IE8-, it will return null
280
// value.
281
return self;
282
}
283
284
var key = listenerObj.key;
285
self.keys_[key] = listenerObj;
286
}
287
288
return self;
289
};
290
291
292
/**
293
* Adds an event listener with a specific event wrapper on a DOM Node or an
294
* object that has implemented {@link goog.events.EventTarget}. A listener can
295
* only be added once to an object.
296
*
297
* @param {EventTarget|goog.events.EventTarget} src The node to listen to
298
* events on.
299
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
300
* @param {function(this:SCOPE, ?):?|{handleEvent:function(?):?}|null} listener
301
* Callback method, or an object with a handleEvent function.
302
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
303
* false).
304
* @return {THIS} This object, allowing for chaining of calls.
305
* @this {THIS}
306
* @template THIS
307
*/
308
goog.events.EventHandler.prototype.listenWithWrapper = function(
309
src, wrapper, listener, opt_capt) {
310
var self = /** @type {!goog.events.EventHandler} */ (this);
311
// TODO(mknichel): Remove the opt_scope from this function and then
312
// templatize it.
313
return self.listenWithWrapper_(src, wrapper, listener, opt_capt);
314
};
315
316
317
/**
318
* Adds an event listener with a specific event wrapper on a DOM Node or an
319
* object that has implemented {@link goog.events.EventTarget}. A listener can
320
* only be added once to an object.
321
*
322
* @param {EventTarget|goog.events.EventTarget} src The node to listen to
323
* events on.
324
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
325
* @param {function(this:T, ?):?|{handleEvent:function(this:T, ?):?}|null}
326
* listener Optional callback function to be used as the
327
* listener or an object with handleEvent function.
328
* @param {boolean|undefined} capture Optional whether to use capture phase.
329
* @param {T} scope Object in whose scope to call the listener.
330
* @return {THIS} This object, allowing for chaining of calls.
331
* @this {THIS}
332
* @template T, THIS
333
*/
334
goog.events.EventHandler.prototype.listenWithWrapperAndScope = function(
335
src, wrapper, listener, capture, scope) {
336
var self = /** @type {!goog.events.EventHandler} */ (this);
337
// TODO(mknichel): Deprecate this function.
338
return self.listenWithWrapper_(src, wrapper, listener, capture, scope);
339
};
340
341
342
/**
343
* Adds an event listener with a specific event wrapper on a DOM Node or an
344
* object that has implemented {@link goog.events.EventTarget}. A listener can
345
* only be added once to an object.
346
*
347
* @param {EventTarget|goog.events.EventTarget} src The node to listen to
348
* events on.
349
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
350
* @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
351
* method, or an object with a handleEvent function.
352
* @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
353
* false).
354
* @param {Object=} opt_scope Element in whose scope to call the listener.
355
* @return {THIS} This object, allowing for chaining of calls.
356
* @this {THIS}
357
* @template THIS
358
* @private
359
*/
360
goog.events.EventHandler.prototype.listenWithWrapper_ = function(
361
src, wrapper, listener, opt_capt, opt_scope) {
362
var self = /** @type {!goog.events.EventHandler} */ (this);
363
wrapper.listen(
364
src, listener, opt_capt, opt_scope || self.handler_ || self, self);
365
return self;
366
};
367
368
369
/**
370
* @return {number} Number of listeners registered by this handler.
371
*/
372
goog.events.EventHandler.prototype.getListenerCount = function() {
373
var count = 0;
374
for (var key in this.keys_) {
375
if (Object.prototype.hasOwnProperty.call(this.keys_, key)) {
376
count++;
377
}
378
}
379
return count;
380
};
381
382
383
/**
384
* Unlistens on an event.
385
* @param {goog.events.ListenableType} src Event source.
386
* @param {string|Array<string>|
387
* !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
388
* type Event type or array of event types to unlisten to.
389
* @param {function(this:?, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
390
* opt_fn Optional callback function to be used as the listener or an object
391
* with handleEvent function.
392
* @param {boolean=} opt_capture Optional whether to use capture phase.
393
* @param {Object=} opt_scope Object in whose scope to call the listener.
394
* @return {THIS} This object, allowing for chaining of calls.
395
* @this {THIS}
396
* @template EVENTOBJ, THIS
397
*/
398
goog.events.EventHandler.prototype.unlisten = function(
399
src, type, opt_fn, opt_capture, opt_scope) {
400
var self = /** @type {!goog.events.EventHandler} */ (this);
401
if (goog.isArray(type)) {
402
for (var i = 0; i < type.length; i++) {
403
self.unlisten(src, type[i], opt_fn, opt_capture, opt_scope);
404
}
405
} else {
406
var listener = goog.events.getListener(
407
src, type, opt_fn || self.handleEvent, opt_capture,
408
opt_scope || self.handler_ || self);
409
410
if (listener) {
411
goog.events.unlistenByKey(listener);
412
delete self.keys_[listener.key];
413
}
414
}
415
416
return self;
417
};
418
419
420
/**
421
* Removes an event listener which was added with listenWithWrapper().
422
*
423
* @param {EventTarget|goog.events.EventTarget} src The target to stop
424
* listening to events on.
425
* @param {goog.events.EventWrapper} wrapper Event wrapper to use.
426
* @param {function(?):?|{handleEvent:function(?):?}|null} listener The
427
* listener function to remove.
428
* @param {boolean=} opt_capt In DOM-compliant browsers, this determines
429
* whether the listener is fired during the capture or bubble phase of the
430
* event.
431
* @param {Object=} opt_scope Element in whose scope to call the listener.
432
* @return {THIS} This object, allowing for chaining of calls.
433
* @this {THIS}
434
* @template THIS
435
*/
436
goog.events.EventHandler.prototype.unlistenWithWrapper = function(
437
src, wrapper, listener, opt_capt, opt_scope) {
438
var self = /** @type {!goog.events.EventHandler} */ (this);
439
wrapper.unlisten(
440
src, listener, opt_capt, opt_scope || self.handler_ || self, self);
441
return self;
442
};
443
444
445
/**
446
* Unlistens to all events.
447
*/
448
goog.events.EventHandler.prototype.removeAll = function() {
449
goog.object.forEach(this.keys_, function(listenerObj, key) {
450
if (this.keys_.hasOwnProperty(key)) {
451
goog.events.unlistenByKey(listenerObj);
452
}
453
}, this);
454
455
this.keys_ = {};
456
};
457
458
459
/**
460
* Disposes of this EventHandler and removes all listeners that it registered.
461
* @override
462
* @protected
463
*/
464
goog.events.EventHandler.prototype.disposeInternal = function() {
465
goog.events.EventHandler.superClass_.disposeInternal.call(this);
466
this.removeAll();
467
};
468
469
470
/**
471
* Default event handler
472
* @param {goog.events.Event} e Event object.
473
*/
474
goog.events.EventHandler.prototype.handleEvent = function(e) {
475
throw Error('EventHandler.handleEvent not implemented');
476
};
477
478