fix(core): should support event.stopImmediatePropagation (#19222)
This commit is contained in:
		
							parent
							
								
									dbec3ca716
								
							
						
					
					
						commit
						200d92d030
					
				| @ -34,6 +34,8 @@ const FALSE = 'FALSE'; | ||||
| const ANGULAR = 'ANGULAR'; | ||||
| const NATIVE_ADD_LISTENER = 'addEventListener'; | ||||
| const NATIVE_REMOVE_LISTENER = 'removeEventListener'; | ||||
| // use the same symbol string which is used in zone.js
 | ||||
| const stopSymbol = '__zone_symbol__propagationStopped'; | ||||
| 
 | ||||
| const blackListedEvents: string[] = | ||||
|     (typeof Zone !== 'undefined') && (Zone as any)[__symbol__('BLACK_LISTED_EVENTS')]; | ||||
| @ -81,6 +83,9 @@ const globalListener = function(event: Event) { | ||||
|     // itself or others
 | ||||
|     const copiedTasks = taskDatas.slice(); | ||||
|     for (let i = 0; i < copiedTasks.length; i++) { | ||||
|       if ((event as any)[stopSymbol] === true) { | ||||
|         break; | ||||
|       } | ||||
|       const taskData = copiedTasks[i]; | ||||
|       if (taskData.zone !== Zone.current) { | ||||
|         // only use Zone.run when Zone.current not equals to stored zone
 | ||||
| @ -94,7 +99,29 @@ const globalListener = function(event: Event) { | ||||
| 
 | ||||
| @Injectable() | ||||
| export class DomEventsPlugin extends EventManagerPlugin { | ||||
|   constructor(@Inject(DOCUMENT) doc: any, private ngZone: NgZone) { super(doc); } | ||||
|   constructor(@Inject(DOCUMENT) doc: any, private ngZone: NgZone) { | ||||
|     super(doc); | ||||
| 
 | ||||
|     this.patchEvent(); | ||||
|   } | ||||
| 
 | ||||
|   private patchEvent() { | ||||
|     if (!Event || !Event.prototype) { | ||||
|       return; | ||||
|     } | ||||
|     const symbol = '__zone_symbol__stopImmediatePropagation'; | ||||
|     if ((Event.prototype as any)[symbol]) { | ||||
|       // already patched by zone.js
 | ||||
|       return; | ||||
|     } | ||||
|     (Event.prototype as any)[symbol] = Event.prototype.stopImmediatePropagation; | ||||
|     Event.prototype.stopImmediatePropagation = function() { | ||||
|       if (this) { | ||||
|         this[stopSymbol] = true; | ||||
|       } | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   // This plugin should come last in the list of plugins, because it accepts all
 | ||||
|   // events.
 | ||||
|  | ||||
| @ -152,6 +152,42 @@ export function main() { | ||||
|       expect(receivedEvents).toEqual([]); | ||||
|     }); | ||||
| 
 | ||||
|     it('should support event.stopImmediatePropagation', () => { | ||||
|       const Zone = (window as any)['Zone']; | ||||
| 
 | ||||
|       const element = el('<div><div></div></div>'); | ||||
|       getDOM().appendChild(doc.body, element); | ||||
|       const dispatchedEvent = getDOM().createMouseEvent('click'); | ||||
|       let receivedEvents: any[] /** TODO #9100 */ = []; | ||||
|       let receivedZones: any[] = []; | ||||
|       const handler1 = (e: any /** TODO #9100 */) => { | ||||
|         receivedEvents.push(e); | ||||
|         receivedZones.push(Zone.current.name); | ||||
|         e.stopImmediatePropagation(); | ||||
|       }; | ||||
|       const handler2 = (e: any /** TODO #9100 */) => { | ||||
|         receivedEvents.push(e); | ||||
|         receivedZones.push(Zone.current.name); | ||||
|       }; | ||||
|       const manager = new EventManager([domEventPlugin], new FakeNgZone()); | ||||
| 
 | ||||
|       let remover1 = null; | ||||
|       let remover2 = null; | ||||
|       Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler1); }); | ||||
|       Zone.root.fork({name: 'test'}).run(() => { | ||||
|         remover2 = manager.addEventListener(element, 'click', handler2); | ||||
|       }); | ||||
|       getDOM().dispatchEvent(element, dispatchedEvent); | ||||
|       expect(receivedEvents).toEqual([dispatchedEvent]); | ||||
|       expect(receivedZones).toEqual([Zone.root.name]); | ||||
| 
 | ||||
|       receivedEvents = []; | ||||
|       remover1 && remover1(); | ||||
|       remover2 && remover2(); | ||||
|       getDOM().dispatchEvent(element, dispatchedEvent); | ||||
|       expect(receivedEvents).toEqual([]); | ||||
|     }); | ||||
| 
 | ||||
|     it('should handle event correctly when one handler remove itself ', () => { | ||||
|       const Zone = (window as any)['Zone']; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user