@@ -181,8 +181,18 @@ export interface NestedEventListener { listener?: EventListenerOrEventListenerOb
181
181
export declare type NestedEventListenerOrEventListenerObject =
182
182
NestedEventListener | EventListener | EventListenerObject ;
183
183
184
+ export interface EventListenerOptions { capture ?: boolean ; }
185
+
186
+ export interface AddEventListenerOptions extends EventListenerOptions {
187
+ passive ?: boolean ;
188
+ once ?: boolean ;
189
+ }
190
+
191
+ export declare type EventListenerOptionsOrCapture =
192
+ EventListenerOptions | AddEventListenerOptions | boolean ;
193
+
184
194
export interface ListenerTaskMeta extends TaskData {
185
- useCapturing : boolean ;
195
+ options : EventListenerOptionsOrCapture ;
186
196
eventName : string ;
187
197
handler : NestedEventListenerOrEventListenerObject ;
188
198
target : any ;
@@ -193,16 +203,31 @@ export interface ListenerTaskMeta extends TaskData {
193
203
( removeFnSymbol : any , delegate : Task | NestedEventListenerOrEventListenerObject ) => any ;
194
204
}
195
205
206
+ // compare the EventListenerOptionsOrCapture
207
+ // 1. if the options is usCapture: boolean, compare the useCpature values directly
208
+ // 2. if the options is EventListerOptions, only compare the capture
209
+ function compareEventListenerOptions (
210
+ left : EventListenerOptionsOrCapture , right : EventListenerOptionsOrCapture ) : boolean {
211
+ const leftCapture : any = ( typeof left === 'boolean' ) ?
212
+ left :
213
+ ( ( typeof left === 'object' ) ? ( left && left . capture ) : false ) ;
214
+ const rightCapture : any = ( typeof right === 'boolean' ) ?
215
+ right :
216
+ ( ( typeof right === 'object' ) ? ( right && right . capture ) : false ) ;
217
+ return ! ! leftCapture === ! ! rightCapture ;
218
+ }
219
+
196
220
function findExistingRegisteredTask (
197
- target : any , handler : any , name : string , capture : boolean , remove : boolean ) : Task {
221
+ target : any , handler : any , name : string , options : EventListenerOptionsOrCapture ,
222
+ remove : boolean ) : Task {
198
223
const eventTasks : Task [ ] = target [ EVENT_TASKS ] ;
199
224
if ( eventTasks ) {
200
225
for ( let i = 0 ; i < eventTasks . length ; i ++ ) {
201
226
const eventTask = eventTasks [ i ] ;
202
227
const data = < ListenerTaskMeta > eventTask . data ;
203
228
const listener = < NestedEventListener > data . handler ;
204
229
if ( ( data . handler === handler || listener . listener === handler ) &&
205
- data . useCapturing === capture && data . eventName === name ) {
230
+ compareEventListenerOptions ( data . options , options ) && data . eventName === name ) {
206
231
if ( remove ) {
207
232
eventTasks . splice ( i , 1 ) ;
208
233
}
@@ -213,15 +238,14 @@ function findExistingRegisteredTask(
213
238
return null ;
214
239
}
215
240
216
- function findAllExistingRegisteredTasks (
217
- target : any , name : string , capture : boolean , remove : boolean ) : Task [ ] {
241
+ function findAllExistingRegisteredTasks ( target : any , name : string , remove : boolean ) : Task [ ] {
218
242
const eventTasks : Task [ ] = target [ EVENT_TASKS ] ;
219
243
if ( eventTasks ) {
220
244
const result = [ ] ;
221
245
for ( let i = eventTasks . length - 1 ; i >= 0 ; i -- ) {
222
246
const eventTask = eventTasks [ i ] ;
223
247
const data = < ListenerTaskMeta > eventTask . data ;
224
- if ( data . eventName === name && data . useCapturing === capture ) {
248
+ if ( data . eventName === name ) {
225
249
result . push ( eventTask ) ;
226
250
if ( remove ) {
227
251
eventTasks . splice ( i , 1 ) ;
@@ -247,7 +271,7 @@ function attachRegisteredEvent(target: any, eventTask: Task, isPrepend: boolean)
247
271
248
272
const defaultListenerMetaCreator = ( self : any , args : any [ ] ) => {
249
273
return {
250
- useCapturing : args [ 2 ] ,
274
+ options : args [ 2 ] ,
251
275
eventName : args [ 0 ] ,
252
276
handler : args [ 1 ] ,
253
277
target : self || _global ,
@@ -259,16 +283,15 @@ const defaultListenerMetaCreator = (self: any, args: any[]) => {
259
283
// remove the delegate directly and try catch error
260
284
if ( ! this . crossContext ) {
261
285
if ( delegate && ( < Task > delegate ) . invoke ) {
262
- return this . target [ addFnSymbol ] (
263
- this . eventName , ( < Task > delegate ) . invoke , this . useCapturing ) ;
286
+ return this . target [ addFnSymbol ] ( this . eventName , ( < Task > delegate ) . invoke , this . options ) ;
264
287
} else {
265
- return this . target [ addFnSymbol ] ( this . eventName , delegate , this . useCapturing ) ;
288
+ return this . target [ addFnSymbol ] ( this . eventName , delegate , this . options ) ;
266
289
}
267
290
} else {
268
291
// add a if/else branch here for performance concern, for most times
269
292
// cross site context is false, so we don't need to try/catch
270
293
try {
271
- return this . target [ addFnSymbol ] ( this . eventName , delegate , this . useCapturing ) ;
294
+ return this . target [ addFnSymbol ] ( this . eventName , delegate , this . options ) ;
272
295
} catch ( err ) {
273
296
// do nothing here is fine, because objects in a cross-site context are unusable
274
297
}
@@ -280,16 +303,15 @@ const defaultListenerMetaCreator = (self: any, args: any[]) => {
280
303
// remove the delegate directly and try catch error
281
304
if ( ! this . crossContext ) {
282
305
if ( delegate && ( < Task > delegate ) . invoke ) {
283
- return this . target [ removeFnSymbol ] (
284
- this . eventName , ( < Task > delegate ) . invoke , this . useCapturing ) ;
306
+ return this . target [ removeFnSymbol ] ( this . eventName , ( < Task > delegate ) . invoke , this . options ) ;
285
307
} else {
286
- return this . target [ removeFnSymbol ] ( this . eventName , delegate , this . useCapturing ) ;
308
+ return this . target [ removeFnSymbol ] ( this . eventName , delegate , this . options ) ;
287
309
}
288
310
} else {
289
311
// add a if/else branch here for performance concern, for most times
290
312
// cross site context is false, so we don't need to try/catch
291
313
try {
292
- return this . target [ removeFnSymbol ] ( this . eventName , delegate , this . useCapturing ) ;
314
+ return this . target [ removeFnSymbol ] ( this . eventName , delegate , this . options ) ;
293
315
} catch ( err ) {
294
316
// do nothing here is fine, because objects in a cross-site context are unusable
295
317
}
@@ -314,15 +336,14 @@ export function makeZoneAwareAddListener(
314
336
315
337
function cancelEventListener ( eventTask : Task ) : void {
316
338
const meta = < ListenerTaskMeta > eventTask . data ;
317
- findExistingRegisteredTask (
318
- meta . target , eventTask . invoke , meta . eventName , meta . useCapturing , true ) ;
339
+ findExistingRegisteredTask ( meta . target , eventTask . invoke , meta . eventName , meta . options , true ) ;
319
340
return meta . invokeRemoveFunc ( removeFnSymbol , eventTask ) ;
320
341
}
321
342
322
343
return function zoneAwareAddListener ( self : any , args : any [ ] ) {
323
344
const data : ListenerTaskMeta = metaCreator ( self , args ) ;
324
345
325
- data . useCapturing = data . useCapturing || defaultUseCapturing ;
346
+ data . options = data . options || defaultUseCapturing ;
326
347
// - Inside a Web Worker, `this` is undefined, the context is `global`
327
348
// - When `addEventListener` is called on the global context in strict mode, `this` is undefined
328
349
// see https://github.com/angular/zone.js/issues/190
@@ -351,7 +372,7 @@ export function makeZoneAwareAddListener(
351
372
352
373
if ( ! allowDuplicates ) {
353
374
const eventTask : Task = findExistingRegisteredTask (
354
- data . target , data . handler , data . eventName , data . useCapturing , false ) ;
375
+ data . target , data . handler , data . eventName , data . options , false ) ;
355
376
if ( eventTask ) {
356
377
// we already registered, so this will have noop.
357
378
return data . invokeAddFunc ( addFnSymbol , eventTask ) ;
@@ -374,7 +395,7 @@ export function makeZoneAwareRemoveListener(
374
395
return function zoneAwareRemoveListener ( self : any , args : any [ ] ) {
375
396
const data = metaCreator ( self , args ) ;
376
397
377
- data . useCapturing = data . useCapturing || defaultUseCapturing ;
398
+ data . options = data . options || defaultUseCapturing ;
378
399
// - Inside a Web Worker, `this` is undefined, the context is `global`
379
400
// - When `addEventListener` is called on the global context in strict mode, `this` is undefined
380
401
// see https://github.com/angular/zone.js/issues/190
@@ -399,8 +420,8 @@ export function makeZoneAwareRemoveListener(
399
420
if ( ! delegate || validZoneHandler ) {
400
421
return data . invokeRemoveFunc ( symbol , data . handler ) ;
401
422
}
402
- const eventTask = findExistingRegisteredTask (
403
- data . target , data . handler , data . eventName , data . useCapturing , true ) ;
423
+ const eventTask =
424
+ findExistingRegisteredTask ( data . target , data . handler , data . eventName , data . options , true ) ;
404
425
if ( eventTask ) {
405
426
eventTask . zone . cancelTask ( eventTask ) ;
406
427
} else {
@@ -409,9 +430,8 @@ export function makeZoneAwareRemoveListener(
409
430
} ;
410
431
}
411
432
412
- export function makeZoneAwareRemoveAllListeners ( fnName : string , useCapturingParam : boolean = true ) {
433
+ export function makeZoneAwareRemoveAllListeners ( fnName : string ) {
413
434
const symbol = zoneSymbol ( fnName ) ;
414
- const defaultUseCapturing = useCapturingParam ? false : undefined ;
415
435
416
436
return function zoneAwareRemoveAllListener ( self : any , args : any [ ] ) {
417
437
const target = self || _global ;
@@ -424,13 +444,12 @@ export function makeZoneAwareRemoveAllListeners(fnName: string, useCapturingPara
424
444
return ;
425
445
}
426
446
const eventName = args [ 0 ] ;
427
- const useCapturing = args [ 1 ] || defaultUseCapturing ;
428
447
// call this function just remove the related eventTask from target[EVENT_TASKS]
429
- findAllExistingRegisteredTasks ( target , eventName , useCapturing , true ) ;
430
448
// we don't need useCapturing here because useCapturing is just for DOM, and
431
449
// removeAllListeners should only be called by node eventEmitter
432
450
// and we don't cancel Task either, because call native eventEmitter.removeAllListeners will
433
451
// will do remove listener(cancelTask) for us
452
+ findAllExistingRegisteredTasks ( target , eventName , true ) ;
434
453
target [ symbol ] ( eventName ) ;
435
454
} ;
436
455
}
0 commit comments