@@ -118,19 +118,22 @@ const EVENT_TASKS = zoneSymbol('eventTasks');
118
118
const ADD_EVENT_LISTENER = 'addEventListener' ;
119
119
const REMOVE_EVENT_LISTENER = 'removeEventListener' ;
120
120
121
- interface NestedEventListener {
121
+ export interface NestedEventListener {
122
122
listener ?: EventListenerOrEventListenerObject ;
123
123
}
124
124
125
- declare type NestedEventListenerOrEventListenerObject =
125
+ export declare type NestedEventListenerOrEventListenerObject =
126
126
NestedEventListener | EventListener | EventListenerObject ;
127
127
128
- interface ListenerTaskMeta extends TaskData {
128
+ export interface ListenerTaskMeta extends TaskData {
129
129
useCapturing : boolean ;
130
130
eventName : string ;
131
131
handler : NestedEventListenerOrEventListenerObject ;
132
132
target : any ;
133
133
name : string ;
134
+ invokeAddFunc : ( addFnSymbol : any , delegate : Task |
135
+ NestedEventListenerOrEventListenerObject ) => any ,
136
+ invokeRemoveFunc : ( removeFnSymbol : any , delegate : Task | NestedEventListenerOrEventListenerObject ) => any
134
137
}
135
138
136
139
function findExistingRegisteredTask (
@@ -185,95 +188,113 @@ function attachRegisteredEvent(target: any, eventTask: Task, isPrepend: boolean)
185
188
}
186
189
}
187
190
191
+ const defaultListenerMetaCreator = ( self : any , args : any [ ] ) => {
192
+ return {
193
+ useCapturing : args [ 2 ] ,
194
+ eventName : args [ 0 ] ,
195
+ handler : args [ 1 ] ,
196
+ target : self || _global ,
197
+ name : args [ 0 ] ,
198
+ invokeAddFunc : function ( addFnSymbol : any , delegate : Task | NestedEventListenerOrEventListenerObject ) {
199
+ if ( delegate && ( < Task > delegate ) . invoke ) {
200
+ return this . target [ addFnSymbol ] ( this . eventName , ( < Task > delegate ) . invoke , this . useCapturing ) ;
201
+ } else {
202
+ return this . target [ addFnSymbol ] ( this . eventName , delegate , this . useCapturing ) ;
203
+ }
204
+ } ,
205
+ invokeRemoveFunc : function ( removeFnSymbol :any , delegate : Task | NestedEventListenerOrEventListenerObject ) {
206
+ if ( delegate && ( < Task > delegate ) . invoke ) {
207
+ return this . target [ removeFnSymbol ] ( this . eventName , ( < Task > delegate ) . invoke , this . useCapturing ) ;
208
+ } else {
209
+ return this . target [ removeFnSymbol ] ( this . eventName , delegate , this . useCapturing ) ;
210
+ }
211
+ }
212
+ } ;
213
+ }
214
+
188
215
export function makeZoneAwareAddListener (
189
216
addFnName : string , removeFnName : string , useCapturingParam : boolean = true ,
190
- allowDuplicates : boolean = false , isPrepend : boolean = false ) {
217
+ allowDuplicates : boolean = false , isPrepend : boolean = false ,
218
+ metaCreator : ( self : any , args : any [ ] ) => ListenerTaskMeta = defaultListenerMetaCreator ) {
191
219
const addFnSymbol = zoneSymbol ( addFnName ) ;
192
220
const removeFnSymbol = zoneSymbol ( removeFnName ) ;
193
221
const defaultUseCapturing = useCapturingParam ? false : undefined ;
194
222
195
223
function scheduleEventListener ( eventTask : Task ) : any {
196
224
const meta = < ListenerTaskMeta > eventTask . data ;
197
225
attachRegisteredEvent ( meta . target , eventTask , isPrepend ) ;
198
- return meta . target [ addFnSymbol ] ( meta . eventName , eventTask . invoke , meta . useCapturing ) ;
226
+ return meta . invokeAddFunc ( addFnSymbol , eventTask ) ;
199
227
}
200
228
201
229
function cancelEventListener ( eventTask : Task ) : void {
202
230
const meta = < ListenerTaskMeta > eventTask . data ;
203
231
findExistingRegisteredTask (
204
232
meta . target , eventTask . invoke , meta . eventName , meta . useCapturing , true ) ;
205
- meta . target [ removeFnSymbol ] ( meta . eventName , eventTask . invoke , meta . useCapturing ) ;
233
+ return meta . invokeRemoveFunc ( removeFnSymbol , eventTask ) ;
206
234
}
207
235
208
236
return function zoneAwareAddListener ( self : any , args : any [ ] ) {
209
- const eventName : string = args [ 0 ] ;
210
- const handler : EventListenerOrEventListenerObject = args [ 1 ] ;
211
- const useCapturing : boolean = args [ 2 ] || defaultUseCapturing ;
237
+ const data : ListenerTaskMeta = metaCreator ( self , args ) ;
238
+
239
+ data . useCapturing = data . useCapturing || defaultUseCapturing ;
212
240
// - Inside a Web Worker, `this` is undefined, the context is `global`
213
241
// - When `addEventListener` is called on the global context in strict mode, `this` is undefined
214
242
// see https://github.com/angular/zone.js/issues/190
215
- const target = self || _global ;
216
243
let delegate : EventListener = null ;
217
- if ( typeof handler == 'function' ) {
218
- delegate = < EventListener > handler ;
219
- } else if ( handler && ( < EventListenerObject > handler ) . handleEvent ) {
220
- delegate = ( event ) => ( < EventListenerObject > handler ) . handleEvent ( event ) ;
244
+ if ( typeof data . handler == 'function' ) {
245
+ delegate = < EventListener > data . handler ;
246
+ } else if ( data . handler && ( < EventListenerObject > data . handler ) . handleEvent ) {
247
+ delegate = ( event ) => ( < EventListenerObject > data . handler ) . handleEvent ( event ) ;
221
248
}
222
249
var validZoneHandler = false ;
223
250
try {
224
251
// In cross site contexts (such as WebDriver frameworks like Selenium),
225
252
// accessing the handler object here will cause an exception to be thrown which
226
253
// will fail tests prematurely.
227
- validZoneHandler = handler && handler . toString ( ) === '[object FunctionWrapper]' ;
254
+ validZoneHandler = data . handler && data . handler . toString ( ) === '[object FunctionWrapper]' ;
228
255
} catch ( e ) {
229
256
// Returning nothing here is fine, because objects in a cross-site context are unusable
230
257
return ;
231
258
}
232
259
// Ignore special listeners of IE11 & Edge dev tools, see
233
260
// https://github.com/angular/zone.js/issues/150
234
261
if ( ! delegate || validZoneHandler ) {
235
- return target [ addFnSymbol ] ( eventName , handler , useCapturing ) ;
262
+ return data . invokeAddFunc ( addFnSymbol , data . handler ) ;
236
263
}
237
264
238
265
if ( ! allowDuplicates ) {
239
266
const eventTask : Task =
240
- findExistingRegisteredTask ( target , handler , eventName , useCapturing , false ) ;
267
+ findExistingRegisteredTask ( data . target , data . handler , data . eventName , data . useCapturing , false ) ;
241
268
if ( eventTask ) {
242
269
// we already registered, so this will have noop.
243
- return target [ addFnSymbol ] ( eventName , eventTask . invoke , useCapturing ) ;
270
+ return data . invokeAddFunc ( addFnSymbol , eventTask ) ;
244
271
}
245
272
}
246
273
247
274
const zone : Zone = Zone . current ;
248
- const source = target . constructor [ 'name' ] + '.' + addFnName + ':' + eventName ;
249
- const data : ListenerTaskMeta = {
250
- target : target ,
251
- eventName : eventName ,
252
- name : eventName ,
253
- useCapturing : useCapturing ,
254
- handler : handler
255
- } ;
275
+ const source = data . target . constructor [ 'name' ] + '.' + addFnName + ':' + data . eventName ;
276
+
256
277
zone . scheduleEventTask ( source , delegate , data , scheduleEventListener , cancelEventListener ) ;
257
278
} ;
258
279
}
259
280
260
- export function makeZoneAwareRemoveListener ( fnName : string , useCapturingParam : boolean = true ) {
281
+ export function makeZoneAwareRemoveListener ( fnName : string , useCapturingParam : boolean = true ,
282
+ metaCreator : ( self : any , args : any [ ] ) => ListenerTaskMeta = defaultListenerMetaCreator ) {
261
283
const symbol = zoneSymbol ( fnName ) ;
262
284
const defaultUseCapturing = useCapturingParam ? false : undefined ;
263
285
264
286
return function zoneAwareRemoveListener ( self : any , args : any [ ] ) {
265
- const eventName : string = args [ 0 ] ;
266
- const handler : EventListenerOrEventListenerObject = args [ 1 ] ;
267
- const useCapturing : boolean = args [ 2 ] || defaultUseCapturing ;
287
+ const data = metaCreator ( self , args ) ;
288
+ data . useCapturing = data . useCapturing || defaultUseCapturing ;
268
289
// - Inside a Web Worker, `this` is undefined, the context is `global`
269
290
// - When `addEventListener` is called on the global context in strict mode, `this` is undefined
270
291
// see https://github.com/angular/zone.js/issues/190
271
- const target = self || _global ;
272
- const eventTask = findExistingRegisteredTask ( target , handler , eventName , useCapturing , true ) ;
292
+ const eventTask = findExistingRegisteredTask ( data . target , data . handler , data . eventName ,
293
+ data . useCapturing , true ) ;
273
294
if ( eventTask ) {
274
295
eventTask . zone . cancelTask ( eventTask ) ;
275
296
} else {
276
- target [ symbol ] ( eventName , handler , useCapturing ) ;
297
+ data . invokeRemoveFunc ( symbol , data . handler ) ;
277
298
}
278
299
} ;
279
300
}
@@ -323,17 +344,20 @@ const zoneAwareAddEventListener =
323
344
makeZoneAwareAddListener ( ADD_EVENT_LISTENER , REMOVE_EVENT_LISTENER ) ;
324
345
const zoneAwareRemoveEventListener = makeZoneAwareRemoveListener ( REMOVE_EVENT_LISTENER ) ;
325
346
326
- export function patchEventTargetMethods ( obj : any ) : boolean {
327
- if ( obj && obj . addEventListener ) {
328
- patchMethod ( obj , ADD_EVENT_LISTENER , ( ) => zoneAwareAddEventListener ) ;
329
- patchMethod ( obj , REMOVE_EVENT_LISTENER , ( ) => zoneAwareRemoveEventListener ) ;
347
+ export function patchEventTargetMethods ( obj : any , addFnName : string = ADD_EVENT_LISTENER ,
348
+ removeFnName : string = REMOVE_EVENT_LISTENER ,
349
+ metaCreator : ( self : any , args : any [ ] ) => ListenerTaskMeta = defaultListenerMetaCreator ) : boolean {
350
+ if ( obj && obj [ addFnName ] ) {
351
+ patchMethod ( obj , addFnName ,
352
+ ( ) => makeZoneAwareAddListener ( addFnName , removeFnName , true , false , false , metaCreator ) ) ;
353
+ patchMethod ( obj , removeFnName ,
354
+ ( ) => makeZoneAwareRemoveListener ( removeFnName , true , metaCreator ) ) ;
330
355
return true ;
331
356
} else {
332
357
return false ;
333
358
}
334
359
}
335
360
336
-
337
361
const originalInstanceKey = zoneSymbol ( 'originalInstance' ) ;
338
362
339
363
// wrap some native API on `window`
0 commit comments