fix(core): should support event.stopImmediatePropagation (#19222)

This commit is contained in:
JiaLiPassion 2017-11-04 07:22:05 +09:00 committed by Victor Berchet
parent dbec3ca716
commit 200d92d030
2 changed files with 64 additions and 1 deletions

View File

@ -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.

View File

@ -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'];