@ -14,361 +14,393 @@ import {EventManager, EventManagerPlugin} from '@angular/platform-browser/src/do
|
||||
import {createMouseEvent, el} from '../../../testing/src/browser_util';
|
||||
|
||||
(function() {
|
||||
if (isNode) return;
|
||||
let domEventPlugin: DomEventsPlugin;
|
||||
let doc: any;
|
||||
let zone: NgZone;
|
||||
if (isNode) return;
|
||||
let domEventPlugin: DomEventsPlugin;
|
||||
let doc: any;
|
||||
let zone: NgZone;
|
||||
|
||||
describe('EventManager', () => {
|
||||
beforeEach(() => {
|
||||
doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument();
|
||||
zone = new NgZone({});
|
||||
domEventPlugin = new DomEventsPlugin(doc);
|
||||
describe('EventManager', () => {
|
||||
beforeEach(() => {
|
||||
doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument();
|
||||
zone = new NgZone({});
|
||||
domEventPlugin = new DomEventsPlugin(doc);
|
||||
});
|
||||
|
||||
it('should delegate event bindings to plugins that are passed in from the most generic one to the most specific one',
|
||||
() => {
|
||||
const element = el('<div></div>');
|
||||
const handler = (e: any /** TODO #9100 */) => e;
|
||||
const plugin = new FakeEventManagerPlugin(doc, ['click']);
|
||||
const manager = new EventManager([domEventPlugin, plugin], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
expect(plugin.eventHandler['click']).toBe(handler);
|
||||
});
|
||||
|
||||
it('should delegate event bindings to the first plugin supporting the event', () => {
|
||||
const element = el('<div></div>');
|
||||
const clickHandler = (e: any /** TODO #9100 */) => e;
|
||||
const dblClickHandler = (e: any /** TODO #9100 */) => e;
|
||||
const plugin1 = new FakeEventManagerPlugin(doc, ['dblclick']);
|
||||
const plugin2 = new FakeEventManagerPlugin(doc, ['click', 'dblclick']);
|
||||
const manager = new EventManager([plugin2, plugin1], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', clickHandler);
|
||||
manager.addEventListener(element, 'dblclick', dblClickHandler);
|
||||
expect(plugin2.eventHandler['click']).toBe(clickHandler);
|
||||
expect(plugin1.eventHandler['dblclick']).toBe(dblClickHandler);
|
||||
});
|
||||
|
||||
it('should throw when no plugin can handle the event', () => {
|
||||
const element = el('<div></div>');
|
||||
const plugin = new FakeEventManagerPlugin(doc, ['dblclick']);
|
||||
const manager = new EventManager([plugin], new FakeNgZone());
|
||||
expect(() => manager.addEventListener(element, 'click', null!))
|
||||
.toThrowError('No event manager plugin found for event click');
|
||||
});
|
||||
|
||||
it('events are caught when fired from a child', () => {
|
||||
const element = el('<div><div></div></div>');
|
||||
// Workaround for https://bugs.webkit.org/show_bug.cgi?id=122755
|
||||
doc.body.appendChild(element);
|
||||
|
||||
const child = element.firstChild as Element;
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
getDOM().dispatchEvent(child, dispatchedEvent);
|
||||
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
});
|
||||
|
||||
it('should add and remove global event listeners', () => {
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
const remover = manager.addGlobalEventListener('document', 'click', handler);
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
|
||||
receivedEvent = null;
|
||||
remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
|
||||
it('should keep zone when addEventListener', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
let receivedZone: any = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
receivedZone = Zone.current;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover: any = null;
|
||||
Zone.root.run(() => {
|
||||
remover = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
expect(receivedZone.name).toBe(Zone.root.name);
|
||||
|
||||
it('should delegate event bindings to plugins that are passed in from the most generic one to the most specific one',
|
||||
() => {
|
||||
const element = el('<div></div>');
|
||||
const handler = (e: any /** TODO #9100 */) => e;
|
||||
const plugin = new FakeEventManagerPlugin(doc, ['click']);
|
||||
const manager = new EventManager([domEventPlugin, plugin], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
expect(plugin.eventHandler['click']).toBe(handler);
|
||||
});
|
||||
receivedEvent = null;
|
||||
remover && remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
|
||||
it('should delegate event bindings to the first plugin supporting the event', () => {
|
||||
const element = el('<div></div>');
|
||||
const clickHandler = (e: any /** TODO #9100 */) => e;
|
||||
const dblClickHandler = (e: any /** TODO #9100 */) => e;
|
||||
const plugin1 = new FakeEventManagerPlugin(doc, ['dblclick']);
|
||||
const plugin2 = new FakeEventManagerPlugin(doc, ['click', 'dblclick']);
|
||||
const manager = new EventManager([plugin2, plugin1], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', clickHandler);
|
||||
manager.addEventListener(element, 'dblclick', dblClickHandler);
|
||||
expect(plugin2.eventHandler['click']).toBe(clickHandler);
|
||||
expect(plugin1.eventHandler['dblclick']).toBe(dblClickHandler);
|
||||
it('should keep zone when addEventListener multiple times', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
Zone.root.run(() => {
|
||||
remover1 = manager.addEventListener(element, 'click', handler1);
|
||||
});
|
||||
|
||||
it('should throw when no plugin can handle the event', () => {
|
||||
const element = el('<div></div>');
|
||||
const plugin = new FakeEventManagerPlugin(doc, ['dblclick']);
|
||||
const manager = new EventManager([plugin], new FakeNgZone());
|
||||
expect(() => manager.addEventListener(element, 'click', null !))
|
||||
.toThrowError('No event manager plugin found for event click');
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'test']);
|
||||
|
||||
it('events are caught when fired from a child', () => {
|
||||
const element = el('<div><div></div></div>');
|
||||
// Workaround for https://bugs.webkit.org/show_bug.cgi?id=122755
|
||||
doc.body.appendChild(element);
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
});
|
||||
|
||||
const child = element.firstChild as Element;
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
const handler = (e: any /** TODO #9100 */) => { receivedEvent = e; };
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
getDOM().dispatchEvent(child, dispatchedEvent);
|
||||
it('should support event.stopImmediatePropagation', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = 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: any = null;
|
||||
let remover2: any = null;
|
||||
Zone.root.run(() => {
|
||||
remover1 = manager.addEventListener(element, 'click', handler1);
|
||||
});
|
||||
|
||||
it('should add and remove global event listeners', () => {
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
const handler = (e: any /** TODO #9100 */) => { receivedEvent = e; };
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
const remover = manager.addGlobalEventListener('document', 'click', handler);
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
|
||||
receivedEvent = null;
|
||||
remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
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]);
|
||||
|
||||
it('should keep zone when addEventListener', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
});
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
let receivedZone: any = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
receivedZone = Zone.current;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
it('should handle event correctly when one handler remove itself ', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
let remover: any = null;
|
||||
Zone.root.run(() => { remover = manager.addEventListener(element, 'click', handler); });
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
expect(receivedZone.name).toBe(Zone.root.name);
|
||||
|
||||
receivedEvent = null;
|
||||
remover && remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
|
||||
it('should keep zone when addEventListener multiple times', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover1: any = null;
|
||||
let remover2: any = 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, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'test']);
|
||||
|
||||
receivedEvents = [];
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
Zone.root.run(() => {
|
||||
remover1 = manager.addEventListener(element, 'click', handler1);
|
||||
});
|
||||
|
||||
it('should support event.stopImmediatePropagation', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = 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: any = null;
|
||||
let remover2: any = 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([]);
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'test']);
|
||||
|
||||
it('should handle event correctly when one handler remove itself ', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
});
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
remover1 && remover1();
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
it('should only add same callback once when addEventListener', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
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, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'test']);
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
Zone.root.run(() => {
|
||||
remover1 = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
|
||||
it('should only add same callback once when addEventListener', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler); });
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
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([]);
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name]);
|
||||
|
||||
it('should be able to remove event listener which was added inside of ngZone', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
});
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
it('should be able to remove event listener which was added inside of ngZone', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
// handler1 is added in root zone
|
||||
Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler1); });
|
||||
// handler2 is added in 'angular' zone
|
||||
Zone.root.fork({name: 'fakeAngularZone', properties: {isAngularZone: true}}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'fakeAngularZone']);
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
// handler1 and handler2 are added in different zone
|
||||
// one is angular zone, the other is not
|
||||
// should still be able to remove them correctly
|
||||
expect(receivedEvents).toEqual([]);
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
// handler1 is added in root zone
|
||||
Zone.root.run(() => {
|
||||
remover1 = manager.addEventListener(element, 'click', handler1);
|
||||
});
|
||||
|
||||
it('should run blackListedEvents handler outside of ngZone', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('scroll');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
let receivedZone: any = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
receivedZone = Zone.current;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover = manager.addEventListener(element, 'scroll', handler);
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
expect(receivedZone.name).not.toEqual('angular');
|
||||
|
||||
receivedEvent = null;
|
||||
remover && remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
// handler2 is added in 'angular' zone
|
||||
Zone.root.fork({name: 'fakeAngularZone', properties: {isAngularZone: true}}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'fakeAngularZone']);
|
||||
|
||||
it('should only trigger one Change detection when bubbling', (done: DoneFn) => {
|
||||
doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument();
|
||||
zone = new NgZone({shouldCoalesceEventChangeDetection: true});
|
||||
domEventPlugin = new DomEventsPlugin(doc);
|
||||
const element = el('<div></div>');
|
||||
const child = el('<div></div>');
|
||||
element.appendChild(child);
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any = [];
|
||||
let stables: any = [];
|
||||
const handler = (e: any) => { receivedEvents.push(e); };
|
||||
const manager = new EventManager([domEventPlugin], zone);
|
||||
let removerChild: any;
|
||||
let removerParent: any;
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
// handler1 and handler2 are added in different zone
|
||||
// one is angular zone, the other is not
|
||||
// should still be able to remove them correctly
|
||||
expect(receivedEvents).toEqual([]);
|
||||
});
|
||||
|
||||
zone.run(() => {
|
||||
removerChild = manager.addEventListener(child, 'click', handler);
|
||||
removerParent = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
zone.onStable.subscribe((isStable: any) => { stables.push(isStable); });
|
||||
getDOM().dispatchEvent(child, dispatchedEvent);
|
||||
requestAnimationFrame(() => {
|
||||
expect(receivedEvents.length).toBe(2);
|
||||
expect(stables.length).toBe(1);
|
||||
it('should run blackListedEvents handler outside of ngZone', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('scroll');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
let receivedZone: any = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
receivedZone = Zone.current;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
removerChild && removerChild();
|
||||
removerParent && removerParent();
|
||||
done();
|
||||
});
|
||||
let remover = manager.addEventListener(element, 'scroll', handler);
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
expect(receivedZone.name).not.toEqual('angular');
|
||||
|
||||
receivedEvent = null;
|
||||
remover && remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
|
||||
it('should only trigger one Change detection when bubbling', (done: DoneFn) => {
|
||||
doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument();
|
||||
zone = new NgZone({shouldCoalesceEventChangeDetection: true});
|
||||
domEventPlugin = new DomEventsPlugin(doc);
|
||||
const element = el('<div></div>');
|
||||
const child = el('<div></div>');
|
||||
element.appendChild(child);
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any = [];
|
||||
let stables: any = [];
|
||||
const handler = (e: any) => {
|
||||
receivedEvents.push(e);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], zone);
|
||||
let removerChild: any;
|
||||
let removerParent: any;
|
||||
|
||||
zone.run(() => {
|
||||
removerChild = manager.addEventListener(child, 'click', handler);
|
||||
removerParent = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
zone.onStable.subscribe((isStable: any) => {
|
||||
stables.push(isStable);
|
||||
});
|
||||
getDOM().dispatchEvent(child, dispatchedEvent);
|
||||
requestAnimationFrame(() => {
|
||||
expect(receivedEvents.length).toBe(2);
|
||||
expect(stables.length).toBe(1);
|
||||
|
||||
removerChild && removerChild();
|
||||
removerParent && removerParent();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
/** @internal */
|
||||
class FakeEventManagerPlugin extends EventManagerPlugin {
|
||||
eventHandler: {[event: string]: Function} = {};
|
||||
|
||||
constructor(doc: any, public supportedEvents: string[]) { super(doc); }
|
||||
constructor(doc: any, public supportedEvents: string[]) {
|
||||
super(doc);
|
||||
}
|
||||
|
||||
supports(eventName: string): boolean { return this.supportedEvents.indexOf(eventName) > -1; }
|
||||
supports(eventName: string): boolean {
|
||||
return this.supportedEvents.indexOf(eventName) > -1;
|
||||
}
|
||||
|
||||
addEventListener(element: any, eventName: string, handler: Function) {
|
||||
this.eventHandler[eventName] = handler;
|
||||
return () => { delete this.eventHandler[eventName]; };
|
||||
return () => {
|
||||
delete this.eventHandler[eventName];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class FakeNgZone extends NgZone {
|
||||
constructor() { super({enableLongStackTrace: false, shouldCoalesceEventChangeDetection: true}); }
|
||||
run<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T { return fn(); }
|
||||
runOutsideAngular(fn: Function) { return fn(); }
|
||||
constructor() {
|
||||
super({enableLongStackTrace: false, shouldCoalesceEventChangeDetection: true});
|
||||
}
|
||||
run<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T {
|
||||
return fn();
|
||||
}
|
||||
runOutsideAngular(fn: Function) {
|
||||
return fn();
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, EventEmitter, Injector, Input, NgModule, Output, Renderer2, ViewEncapsulation, destroyPlatform} from '@angular/core';
|
||||
import {Component, destroyPlatform, EventEmitter, Injector, Input, NgModule, Output, Renderer2, ViewEncapsulation} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
|
||||
@ -15,14 +15,15 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
if (browserDetection.supportsShadowDom) {
|
||||
describe('ShadowDOM Support', () => {
|
||||
|
||||
let testContainer: HTMLDivElement;
|
||||
|
||||
beforeEach(() => { TestBed.configureTestingModule({imports: [TestModule]}); });
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({imports: [TestModule]});
|
||||
});
|
||||
|
||||
it('should attach and use a shadowRoot when ViewEncapsulation.Native is set', () => {
|
||||
const compEl = TestBed.createComponent(ShadowComponent).nativeElement;
|
||||
expect(compEl.shadowRoot !.textContent).toEqual('Hello World');
|
||||
expect(compEl.shadowRoot!.textContent).toEqual('Hello World');
|
||||
});
|
||||
|
||||
it('should use the shadow root to encapsulate styles', () => {
|
||||
@ -40,10 +41,10 @@ if (browserDetection.supportsShadowDom) {
|
||||
const el = TestBed.createComponent(ShadowSlotComponent).nativeElement;
|
||||
const projectedContent = document.createTextNode('Hello Slot!');
|
||||
el.appendChild(projectedContent);
|
||||
const slot = el.shadowRoot !.querySelector('slot');
|
||||
const slot = el.shadowRoot!.querySelector('slot');
|
||||
|
||||
expect(slot !.assignedNodes().length).toBe(1);
|
||||
expect(slot !.assignedNodes()[0].textContent).toBe('Hello Slot!');
|
||||
expect(slot!.assignedNodes().length).toBe(1);
|
||||
expect(slot!.assignedNodes()[0].textContent).toBe('Hello Slot!');
|
||||
});
|
||||
|
||||
it('should allow the usage of named <slot> elements', () => {
|
||||
@ -65,16 +66,16 @@ if (browserDetection.supportsShadowDom) {
|
||||
el.appendChild(articleContent);
|
||||
el.appendChild(articleSubcontent);
|
||||
|
||||
const headerSlot = el.shadowRoot !.querySelector('slot[name=header]') as HTMLSlotElement;
|
||||
const articleSlot = el.shadowRoot !.querySelector('slot[name=article]') as HTMLSlotElement;
|
||||
const headerSlot = el.shadowRoot!.querySelector('slot[name=header]') as HTMLSlotElement;
|
||||
const articleSlot = el.shadowRoot!.querySelector('slot[name=article]') as HTMLSlotElement;
|
||||
|
||||
expect(headerSlot !.assignedNodes().length).toBe(1);
|
||||
expect(headerSlot !.assignedNodes()[0].textContent).toBe('Header Text!');
|
||||
expect(headerSlot!.assignedNodes().length).toBe(1);
|
||||
expect(headerSlot!.assignedNodes()[0].textContent).toBe('Header Text!');
|
||||
expect(headerContent.assignedSlot).toBe(headerSlot);
|
||||
|
||||
expect(articleSlot !.assignedNodes().length).toBe(2);
|
||||
expect(articleSlot !.assignedNodes()[0].textContent).toBe('Article Text!');
|
||||
expect(articleSlot !.assignedNodes()[1].textContent).toBe('Article Subtext!');
|
||||
expect(articleSlot!.assignedNodes().length).toBe(2);
|
||||
expect(articleSlot!.assignedNodes()[0].textContent).toBe('Article Text!');
|
||||
expect(articleSlot!.assignedNodes()[1].textContent).toBe('Article Subtext!');
|
||||
expect(articleContent.assignedSlot).toBe(articleSlot);
|
||||
expect(articleSubcontent.assignedSlot).toBe(articleSlot);
|
||||
});
|
||||
|
Reference in New Issue
Block a user