feat(core): remove the (^ syntax and make all DOM events bubbling
BREAKING CHANGE Before <div (^click)="onEventHandler()"> <button></button> </div> After <div (click)="onEventHandler()"> <button></button> </div> Closes #3864
This commit is contained in:
@@ -856,7 +856,9 @@ export function main() {
|
||||
|
||||
dispatchEvent(tc.nativeElement, 'domEvent');
|
||||
|
||||
expect(listener.eventType).toEqual('domEvent');
|
||||
expect(listener.eventTypes)
|
||||
.toEqual(
|
||||
['domEvent', 'body_domEvent', 'document_domEvent', 'window_domEvent']);
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -874,16 +876,16 @@ export function main() {
|
||||
var tc = rootTC.componentViewChildren[0];
|
||||
var listener = tc.inject(DirectiveListeningDomEvent);
|
||||
dispatchEvent(DOM.getGlobalEventTarget("window"), 'domEvent');
|
||||
expect(listener.eventType).toEqual('window_domEvent');
|
||||
expect(listener.eventTypes).toEqual(['window_domEvent']);
|
||||
|
||||
listener = tc.inject(DirectiveListeningDomEvent);
|
||||
listener.eventTypes = [];
|
||||
dispatchEvent(DOM.getGlobalEventTarget("document"), 'domEvent');
|
||||
expect(listener.eventType).toEqual('document_domEvent');
|
||||
expect(listener.eventTypes).toEqual(['document_domEvent', 'window_domEvent']);
|
||||
|
||||
rootTC.destroy();
|
||||
listener = tc.inject(DirectiveListeningDomEvent);
|
||||
listener.eventTypes = [];
|
||||
dispatchEvent(DOM.getGlobalEventTarget("body"), 'domEvent');
|
||||
expect(listener.eventType).toEqual('');
|
||||
expect(listener.eventTypes).toEqual([]);
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -983,7 +985,7 @@ export function main() {
|
||||
var listener = tc.inject(DirectiveListeningDomEvent);
|
||||
var listenerother = tc.inject(DirectiveListeningDomEventOther);
|
||||
dispatchEvent(DOM.getGlobalEventTarget("window"), 'domEvent');
|
||||
expect(listener.eventType).toEqual('window_domEvent');
|
||||
expect(listener.eventTypes).toEqual(['window_domEvent']);
|
||||
expect(listenerother.eventType).toEqual('other_domEvent');
|
||||
expect(globalCounter).toEqual(1);
|
||||
|
||||
@@ -1851,12 +1853,11 @@ class DirectiveListeningEvent {
|
||||
})
|
||||
@Injectable()
|
||||
class DirectiveListeningDomEvent {
|
||||
eventType: string;
|
||||
constructor() { this.eventType = ''; }
|
||||
onEvent(eventType: string) { this.eventType = eventType; }
|
||||
onWindowEvent(eventType: string) { this.eventType = "window_" + eventType; }
|
||||
onDocumentEvent(eventType: string) { this.eventType = "document_" + eventType; }
|
||||
onBodyEvent(eventType: string) { this.eventType = "body_" + eventType; }
|
||||
eventTypes: string[] = [];
|
||||
onEvent(eventType: string) { this.eventTypes.push(eventType); }
|
||||
onWindowEvent(eventType: string) { this.eventTypes.push("window_" + eventType); }
|
||||
onDocumentEvent(eventType: string) { this.eventTypes.push("document_" + eventType); }
|
||||
onBodyEvent(eventType: string) { this.eventTypes.push("body_" + eventType); }
|
||||
}
|
||||
|
||||
var globalCounter = 0;
|
||||
|
||||
@@ -182,20 +182,6 @@ export function main() {
|
||||
expect(eventBinding.fullName).toEqual('click');
|
||||
});
|
||||
|
||||
it('should detect onbubble- syntax', () => {
|
||||
var results = process(el('<div onbubble-click="b()"></div>'));
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('b()');
|
||||
expect(eventBinding.fullName).toEqual('^click');
|
||||
});
|
||||
|
||||
it('should detect onbubble- syntax with data- prefix', () => {
|
||||
var results = process(el('<div data-onbubble-click="b()"></div>'));
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
expect(eventBinding.source.source).toEqual('b()');
|
||||
expect(eventBinding.fullName).toEqual('^click');
|
||||
});
|
||||
|
||||
it('should parse event handlers using on- syntax as actions', () => {
|
||||
var results = process(el('<div on-click="foo=bar"></div>'));
|
||||
var eventBinding = results[0].eventBindings[0];
|
||||
|
||||
@@ -31,16 +31,7 @@ export function main() {
|
||||
var plugin = new FakeEventManagerPlugin(['click']);
|
||||
var manager = new EventManager([plugin, domEventPlugin], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
expect(plugin._nonBubbleEventHandlers.get('click')).toBe(handler);
|
||||
});
|
||||
|
||||
it('should delegate bubbling events to plugins', () => {
|
||||
var element = el('<div></div>');
|
||||
var handler = (e) => e;
|
||||
var plugin = new FakeEventManagerPlugin(['click']);
|
||||
var manager = new EventManager([plugin, domEventPlugin], new FakeNgZone());
|
||||
manager.addEventListener(element, '^click', handler);
|
||||
expect(plugin._bubbleEventHandlers.get('click')).toBe(handler);
|
||||
expect(plugin._eventHandler.get('click')).toBe(handler);
|
||||
});
|
||||
|
||||
it('should delegate event bindings to the first plugin supporting the event', () => {
|
||||
@@ -52,10 +43,10 @@ export function main() {
|
||||
var manager = new EventManager([plugin1, plugin2], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', clickHandler);
|
||||
manager.addEventListener(element, 'dblclick', dblClickHandler);
|
||||
expect(plugin1._nonBubbleEventHandlers.has('click')).toBe(false);
|
||||
expect(plugin2._nonBubbleEventHandlers.get('click')).toBe(clickHandler);
|
||||
expect(plugin2._nonBubbleEventHandlers.has('dblclick')).toBe(false);
|
||||
expect(plugin1._nonBubbleEventHandlers.get('dblclick')).toBe(dblClickHandler);
|
||||
expect(plugin1._eventHandler.has('click')).toBe(false);
|
||||
expect(plugin2._eventHandler.get('click')).toBe(clickHandler);
|
||||
expect(plugin2._eventHandler.has('dblclick')).toBe(false);
|
||||
expect(plugin1._eventHandler.get('dblclick')).toBe(dblClickHandler);
|
||||
});
|
||||
|
||||
it('should throw when no plugin can handle the event', () => {
|
||||
@@ -66,20 +57,7 @@ export function main() {
|
||||
.toThrowError('No event manager plugin found for event click');
|
||||
});
|
||||
|
||||
it('by default events are only caught on same element', () => {
|
||||
var element = el('<div><div></div></div>');
|
||||
var child = DOM.firstChild(element);
|
||||
var dispatchedEvent = DOM.createMouseEvent('click');
|
||||
var receivedEvent = null;
|
||||
var handler = (e) => { receivedEvent = e; };
|
||||
var manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
DOM.dispatchEvent(child, dispatchedEvent);
|
||||
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
|
||||
it('bubbled events are caught when fired from a child', () => {
|
||||
it('events are caught when fired from a child', () => {
|
||||
var element = el('<div><div></div></div>');
|
||||
// Workaround for https://bugs.webkit.org/show_bug.cgi?id=122755
|
||||
DOM.appendChild(DOM.defaultDoc().body, element);
|
||||
@@ -89,13 +67,13 @@ export function main() {
|
||||
var receivedEvent = null;
|
||||
var handler = (e) => { receivedEvent = e; };
|
||||
var manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
manager.addEventListener(element, '^click', handler);
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
DOM.dispatchEvent(child, dispatchedEvent);
|
||||
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
});
|
||||
|
||||
it('should add and remove global event listeners with correct bubbling', () => {
|
||||
it('should add and remove global event listeners', () => {
|
||||
var element = el('<div><div></div></div>');
|
||||
DOM.appendChild(DOM.defaultDoc().body, element);
|
||||
var dispatchedEvent = DOM.createMouseEvent('click');
|
||||
@@ -103,7 +81,7 @@ export function main() {
|
||||
var handler = (e) => { receivedEvent = e; };
|
||||
var manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
var remover = manager.addGlobalEventListener("document", '^click', handler);
|
||||
var remover = manager.addGlobalEventListener("document", 'click', handler);
|
||||
DOM.dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
|
||||
@@ -111,37 +89,19 @@ export function main() {
|
||||
remover();
|
||||
DOM.dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
|
||||
remover = manager.addGlobalEventListener("document", 'click', handler);
|
||||
DOM.dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class FakeEventManagerPlugin extends EventManagerPlugin {
|
||||
_supports: string[];
|
||||
_nonBubbleEventHandlers: Map<string, Function>;
|
||||
_bubbleEventHandlers: Map<string, Function>;
|
||||
constructor(supports: string[]) {
|
||||
super();
|
||||
this._supports = supports;
|
||||
this._nonBubbleEventHandlers = new Map();
|
||||
this._bubbleEventHandlers = new Map();
|
||||
}
|
||||
_eventHandler: Map<string, Function> = new Map();
|
||||
constructor(public _supports: string[]) { super(); }
|
||||
|
||||
supports(eventName: string): boolean { return ListWrapper.contains(this._supports, eventName); }
|
||||
|
||||
addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
|
||||
if (shouldSupportBubble) {
|
||||
this._bubbleEventHandlers.set(eventName, handler);
|
||||
} else {
|
||||
this._nonBubbleEventHandlers.set(eventName, handler);
|
||||
}
|
||||
return () => {
|
||||
MapWrapper.delete(
|
||||
shouldSupportBubble ? this._bubbleEventHandlers : this._nonBubbleEventHandlers, eventName)
|
||||
};
|
||||
addEventListener(element, eventName: string, handler: Function) {
|
||||
this._eventHandler.set(eventName, handler);
|
||||
return () => { MapWrapper.delete(this._eventHandler, eventName) };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ export function main() {
|
||||
.then((testComponent) => {
|
||||
testComponent.detectChanges();
|
||||
// TODO: shouldn't this be just 'click' rather than '^click'?
|
||||
testComponent.query(By.css('a')).triggerEventHandler('^click', null);
|
||||
testComponent.query(By.css('a')).triggerEventHandler('click', null);
|
||||
expect(router.spy('navigateInstruction')).toHaveBeenCalledWith(dummyInstruction);
|
||||
async.done();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user