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:
parent
9934b3ec7f
commit
60ce884671
|
@ -130,33 +130,6 @@ Example:
|
|||
|
||||
Example:
|
||||
|
||||
`<div on-click="doX()">`
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Event binding (bubbling)</th>
|
||||
<td>
|
||||
`<div (^event)="statement">`
|
||||
|
||||
Example:
|
||||
|
||||
`<div (^mouseover)="hlite()">`
|
||||
</td>
|
||||
<td>
|
||||
`<div on-bubble-event="statement">`
|
||||
|
||||
Example:
|
||||
|
||||
`<div on-bubble-mouseover="hlite()">`
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Declare reference</th>
|
||||
<td>
|
||||
`<div #symbol>`
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
```
|
||||
<video #player>
|
||||
|
@ -420,7 +393,7 @@ of the templates occurs. One such example is `ng-for`.
|
|||
|
||||
Where:
|
||||
* `[ng-for]` triggers the for directive.
|
||||
* `#person` exports the implicit `ng-for` item.
|
||||
* `#person` exports the implicit `ng-for` item.
|
||||
* `[ng-for-of]="people"` binds an iterable object to the `ng-for` controller.
|
||||
* `#i=index` exports item index as `i`.
|
||||
|
||||
|
@ -515,18 +488,16 @@ Where:
|
|||
* `statement` is a valid statement (as defined in section below).
|
||||
If the execution of the statement returns `false`, then `preventDefault`is applied on the DOM event.
|
||||
|
||||
By default, angular only listens to the element on the event, and ignores events which bubble. To listen to bubbled
|
||||
events (as in the case of clicking on any child) use the bubble option (`(event)` or `on-bubble-event`) as shown
|
||||
below.
|
||||
Angular listens to bubbled DOM events (as in the case of clicking on any child), as shown below:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Short form</th>
|
||||
<td>`<some-element (^some-event)="statement">`</td>
|
||||
<td>`<some-element (some-event)="statement">`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Canonical form</th>
|
||||
<td>`<some-element on-bubble-some-event="statement">`</td>
|
||||
<td>`<some-element on-some-event="statement">`</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -12,14 +12,13 @@ import {dashCaseToCamelCase} from '../util';
|
|||
// Group 1 = "bind-"
|
||||
// Group 2 = "var-" or "#"
|
||||
// Group 3 = "on-"
|
||||
// Group 4 = "onbubble-"
|
||||
// Group 5 = "bindon-"
|
||||
// Group 6 = the identifier after "bind-", "var-/#", or "on-"
|
||||
// Group 7 = idenitifer inside [()]
|
||||
// Group 8 = idenitifer inside []
|
||||
// Group 9 = identifier inside ()
|
||||
// Group 4 = "bindon-"
|
||||
// Group 5 = the identifier after "bind-", "var-/#", or "on-"
|
||||
// Group 6 = idenitifer inside [()]
|
||||
// Group 7 = idenitifer inside []
|
||||
// Group 8 = identifier inside ()
|
||||
var BIND_NAME_REGEXP =
|
||||
/^(?:(?:(?:(bind-)|(var-|#)|(on-)|(onbubble-)|(bindon-))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/g;
|
||||
/^(?:(?:(?:(bind-)|(var-|#)|(on-)|(bindon-))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/g;
|
||||
/**
|
||||
* Parses the property bindings on a single element.
|
||||
*/
|
||||
|
@ -39,33 +38,30 @@ export class PropertyBindingParser implements CompileStep {
|
|||
var bindParts = RegExpWrapper.firstMatch(BIND_NAME_REGEXP, attrName);
|
||||
if (isPresent(bindParts)) {
|
||||
if (isPresent(bindParts[1])) { // match: bind-prop
|
||||
this._bindProperty(bindParts[6], attrValue, current, newAttrs);
|
||||
this._bindProperty(bindParts[5], attrValue, current, newAttrs);
|
||||
|
||||
} else if (isPresent(
|
||||
bindParts[2])) { // match: var-name / var-name="iden" / #name / #name="iden"
|
||||
var identifier = bindParts[6];
|
||||
var identifier = bindParts[5];
|
||||
var value = attrValue == '' ? '\$implicit' : attrValue;
|
||||
this._bindVariable(identifier, value, current, newAttrs);
|
||||
|
||||
} else if (isPresent(bindParts[3])) { // match: on-event
|
||||
this._bindEvent(bindParts[6], attrValue, current, newAttrs);
|
||||
this._bindEvent(bindParts[5], attrValue, current, newAttrs);
|
||||
|
||||
} else if (isPresent(bindParts[4])) { // match: onbubble-event
|
||||
this._bindEvent('^' + bindParts[6], attrValue, current, newAttrs);
|
||||
} else if (isPresent(bindParts[4])) { // match: bindon-prop
|
||||
this._bindProperty(bindParts[5], attrValue, current, newAttrs);
|
||||
this._bindAssignmentEvent(bindParts[5], attrValue, current, newAttrs);
|
||||
|
||||
} else if (isPresent(bindParts[5])) { // match: bindon-prop
|
||||
} else if (isPresent(bindParts[6])) { // match: [(expr)]
|
||||
this._bindProperty(bindParts[6], attrValue, current, newAttrs);
|
||||
this._bindAssignmentEvent(bindParts[6], attrValue, current, newAttrs);
|
||||
|
||||
} else if (isPresent(bindParts[7])) { // match: [(expr)]
|
||||
} else if (isPresent(bindParts[7])) { // match: [expr]
|
||||
this._bindProperty(bindParts[7], attrValue, current, newAttrs);
|
||||
this._bindAssignmentEvent(bindParts[7], attrValue, current, newAttrs);
|
||||
|
||||
} else if (isPresent(bindParts[8])) { // match: [expr]
|
||||
this._bindProperty(bindParts[8], attrValue, current, newAttrs);
|
||||
|
||||
} else if (isPresent(bindParts[9])) { // match: (event)
|
||||
this._bindEvent(bindParts[9], attrValue, current, newAttrs);
|
||||
} else if (isPresent(bindParts[8])) { // match: (event)
|
||||
this._bindEvent(bindParts[8], attrValue, current, newAttrs);
|
||||
}
|
||||
} else {
|
||||
var expr = this._parser.parseInterpolation(attrValue, current.elementDescription);
|
||||
|
|
|
@ -2,8 +2,6 @@ import {isBlank, BaseException, isPresent, StringWrapper} from 'angular2/src/cor
|
|||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||
|
||||
const BUBBLE_SYMBOL = '^';
|
||||
|
||||
export class EventManager {
|
||||
constructor(public _plugins: EventManagerPlugin[], public _zone: NgZone) {
|
||||
for (var i = 0; i < _plugins.length; i++) {
|
||||
|
@ -12,17 +10,13 @@ export class EventManager {
|
|||
}
|
||||
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function) {
|
||||
var withoutBubbleSymbol = this._removeBubbleSymbol(eventName);
|
||||
var plugin = this._findPluginFor(withoutBubbleSymbol);
|
||||
plugin.addEventListener(element, withoutBubbleSymbol, handler,
|
||||
withoutBubbleSymbol != eventName);
|
||||
var plugin = this._findPluginFor(eventName);
|
||||
plugin.addEventListener(element, eventName, handler);
|
||||
}
|
||||
|
||||
addGlobalEventListener(target: string, eventName: string, handler: Function): Function {
|
||||
var withoutBubbleSymbol = this._removeBubbleSymbol(eventName);
|
||||
var plugin = this._findPluginFor(withoutBubbleSymbol);
|
||||
return plugin.addGlobalEventListener(target, withoutBubbleSymbol, handler,
|
||||
withoutBubbleSymbol != eventName);
|
||||
var plugin = this._findPluginFor(eventName);
|
||||
return plugin.addGlobalEventListener(target, eventName, handler);
|
||||
}
|
||||
|
||||
getZone(): NgZone { return this._zone; }
|
||||
|
@ -37,28 +31,19 @@ export class EventManager {
|
|||
}
|
||||
throw new BaseException(`No event manager plugin found for event ${eventName}`);
|
||||
}
|
||||
|
||||
_removeBubbleSymbol(eventName: string): string {
|
||||
return eventName[0] == BUBBLE_SYMBOL ? StringWrapper.substring(eventName, 1) : eventName;
|
||||
}
|
||||
}
|
||||
|
||||
export class EventManagerPlugin {
|
||||
manager: EventManager;
|
||||
|
||||
// We are assuming here that all plugins support bubbled and non-bubbled events.
|
||||
// That is equivalent to having supporting $event.target
|
||||
// The bubbling flag (currently ^) is stripped before calling the supports and
|
||||
// addEventListener methods.
|
||||
supports(eventName: string): boolean { return false; }
|
||||
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function,
|
||||
shouldSupportBubble: boolean) {
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function) {
|
||||
throw "not implemented";
|
||||
}
|
||||
|
||||
addGlobalEventListener(element: string, eventName: string, handler: Function,
|
||||
shouldSupportBubble: boolean): Function {
|
||||
addGlobalEventListener(element: string, eventName: string, handler: Function): Function {
|
||||
throw "not implemented";
|
||||
}
|
||||
}
|
||||
|
@ -70,39 +55,17 @@ export class DomEventsPlugin extends EventManagerPlugin {
|
|||
// events.
|
||||
supports(eventName: string): boolean { return true; }
|
||||
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function,
|
||||
shouldSupportBubble: boolean) {
|
||||
var outsideHandler =
|
||||
this._getOutsideHandler(shouldSupportBubble, element, handler, this.manager._zone);
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function) {
|
||||
var zone = this.manager._zone;
|
||||
var outsideHandler = (event) => zone.run(() => handler(event));
|
||||
this.manager._zone.runOutsideAngular(() => { DOM.on(element, eventName, outsideHandler); });
|
||||
}
|
||||
|
||||
addGlobalEventListener(target: string, eventName: string, handler: Function,
|
||||
shouldSupportBubble: boolean): Function {
|
||||
addGlobalEventListener(target: string, eventName: string, handler: Function): Function {
|
||||
var element = DOM.getGlobalEventTarget(target);
|
||||
var outsideHandler =
|
||||
this._getOutsideHandler(shouldSupportBubble, element, handler, this.manager._zone);
|
||||
var zone = this.manager._zone;
|
||||
var outsideHandler = (event) => zone.run(() => handler(event));
|
||||
return this.manager._zone.runOutsideAngular(
|
||||
() => { return DOM.onAndCancel(element, eventName, outsideHandler); });
|
||||
}
|
||||
|
||||
_getOutsideHandler(shouldSupportBubble: boolean, element: HTMLElement, handler: Function,
|
||||
zone: NgZone) {
|
||||
return shouldSupportBubble ? DomEventsPlugin.bubbleCallback(element, handler, zone) :
|
||||
DomEventsPlugin.sameElementCallback(element, handler, zone);
|
||||
}
|
||||
|
||||
static sameElementCallback(element: HTMLElement, handler: Function, zone: NgZone):
|
||||
(event: Event) => void {
|
||||
return (event) => {
|
||||
if (event.target === element) {
|
||||
zone.run(() => handler(event));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static bubbleCallback(element: HTMLElement, handler: Function, zone: NgZone):
|
||||
(event: Event) => void {
|
||||
return (event) => zone.run(() => handler(event));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,7 @@ class HammerGesturesPlugin extends HammerGesturesPluginCommon {
|
|||
return true;
|
||||
}
|
||||
|
||||
addEventListener(Element element, String eventName, Function handler,
|
||||
bool shouldSupportBubble) {
|
||||
if (shouldSupportBubble) throw new BaseException(
|
||||
'Hammer.js plugin does not support bubbling gestures.');
|
||||
addEventListener(Element element, String eventName, Function handler) {
|
||||
var zone = this.manager.getZone();
|
||||
eventName = eventName.toLowerCase();
|
||||
|
||||
|
|
|
@ -16,10 +16,7 @@ export class HammerGesturesPlugin extends HammerGesturesPluginCommon {
|
|||
return true;
|
||||
}
|
||||
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function,
|
||||
shouldSupportBubble: boolean) {
|
||||
if (shouldSupportBubble)
|
||||
throw new BaseException('Hammer.js plugin does not support bubbling gestures.');
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function) {
|
||||
var zone = this.manager.getZone();
|
||||
eventName = eventName.toLowerCase();
|
||||
|
||||
|
|
|
@ -26,13 +26,11 @@ export class KeyEventsPlugin extends EventManagerPlugin {
|
|||
return isPresent(KeyEventsPlugin.parseEventName(eventName));
|
||||
}
|
||||
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: (Event: any) => any,
|
||||
shouldSupportBubble: boolean) {
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: (Event: any) => any) {
|
||||
var parsedEvent = KeyEventsPlugin.parseEventName(eventName);
|
||||
|
||||
var outsideHandler = KeyEventsPlugin.eventCallback(element, shouldSupportBubble,
|
||||
StringMapWrapper.get(parsedEvent, 'fullKey'),
|
||||
handler, this.manager.getZone());
|
||||
var outsideHandler = KeyEventsPlugin.eventCallback(
|
||||
element, StringMapWrapper.get(parsedEvent, 'fullKey'), handler, this.manager.getZone());
|
||||
|
||||
this.manager.getZone().runOutsideAngular(() => {
|
||||
DOM.on(element, StringMapWrapper.get(parsedEvent, 'domEventName'), outsideHandler);
|
||||
|
@ -91,11 +89,10 @@ export class KeyEventsPlugin extends EventManagerPlugin {
|
|||
return fullKey;
|
||||
}
|
||||
|
||||
static eventCallback(element: HTMLElement, shouldSupportBubble: boolean, fullKey: any,
|
||||
handler: (Event) => any, zone: NgZone): (event: Event) => void {
|
||||
static eventCallback(element: HTMLElement, fullKey: any, handler: (Event) => any, zone: NgZone):
|
||||
(event: Event) => void {
|
||||
return (event) => {
|
||||
var correctElement = shouldSupportBubble || event.target === element;
|
||||
if (correctElement && StringWrapper.equals(KeyEventsPlugin.getEventFullKey(event), fullKey)) {
|
||||
if (StringWrapper.equals(KeyEventsPlugin.getEventFullKey(event), fullKey)) {
|
||||
zone.run(() => handler(event));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ import {Instruction, stringifyInstruction} from './instruction';
|
|||
selector: '[router-link]',
|
||||
properties: ['routeParams: routerLink'],
|
||||
host: {
|
||||
'(^click)': 'onClick()',
|
||||
'(click)': 'onClick()',
|
||||
'[attr.href]': 'visibleHref',
|
||||
'[class.router-link-active]': 'isRouteActive'
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ import {isPresent} from 'angular2/src/core/facade/lang';
|
|||
@Component({
|
||||
selector: '[md-button]:not(a), [md-fab]:not(a), [md-raised-button]:not(a)',
|
||||
host: {
|
||||
'(^mousedown)': 'onMousedown()',
|
||||
'(mousedown)': 'onMousedown()',
|
||||
'(focus)': 'onFocus()',
|
||||
'(blur)': 'onBlur()',
|
||||
'[class.md-button-focus]': 'isKeyboardFocused',
|
||||
|
@ -50,8 +50,8 @@ export class MdButton {
|
|||
properties: ['disabled'],
|
||||
lifecycle: [LifecycleEvent.OnChanges],
|
||||
host: {
|
||||
'(^click)': 'onClick($event)',
|
||||
'(^mousedown)': 'onMousedown()',
|
||||
'(click)': 'onClick($event)',
|
||||
'(mousedown)': 'onMousedown()',
|
||||
'(focus)': 'onFocus()',
|
||||
'(blur)': 'onBlur()',
|
||||
'[tabIndex]': 'tabIndex',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<style>@import "package:angular2_material/src/components/checkbox/checkbox.css";</style>
|
||||
|
||||
<div (^click)="toggle($event)">
|
||||
<div (click)="toggle($event)">
|
||||
<div class="md-checkbox-container">
|
||||
<div class="md-checkbox-icon"></div>
|
||||
</div>
|
||||
|
|
|
@ -206,7 +206,7 @@ export class MdDialogConfig {
|
|||
host: {
|
||||
'class': 'md-dialog',
|
||||
'tabindex': '0',
|
||||
'(body:^keydown)': 'documentKeypress($event)',
|
||||
'(body:keydown)': 'documentKeypress($event)',
|
||||
},
|
||||
})
|
||||
@View({
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<label role="radio" class="md-radio-root"
|
||||
[class.md-radio-checked]="checked"
|
||||
(^click)="select($event)">
|
||||
(click)="select($event)">
|
||||
<!-- The actual `radio` part of the control. -->
|
||||
<div class="md-radio-container">
|
||||
<div class="md-radio-off"></div>
|
||||
|
|
|
@ -41,7 +41,7 @@ var _uniqueIdCounter: number = 0;
|
|||
'[attr.aria-disabled]': 'disabled',
|
||||
'[attr.aria-activedescendant]': 'activedescendant',
|
||||
// TODO(jelbourn): Remove ^ when event retargeting is fixed.
|
||||
'(^keydown)': 'onKeydown($event)',
|
||||
'(keydown)': 'onKeydown($event)',
|
||||
'[tabindex]': 'tabindex',
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<style>@import "package:angular2_material/src/components/switcher/switch.css";</style>
|
||||
|
||||
<div (^click)="toggle($event)">
|
||||
<div (click)="toggle($event)">
|
||||
<div class="md-switch-container">
|
||||
<div class="md-switch-bar"></div>
|
||||
<div class="md-switch-thumb-container">
|
||||
|
|
|
@ -9,10 +9,12 @@ describe('md-dialog', function() {
|
|||
it('should open a dialog', function() {
|
||||
var openButton = element(by.id('open'));
|
||||
openButton.click();
|
||||
browser.sleep(500);
|
||||
expect(element(by.css('.md-dialog')).isPresent()).toEqual(true);
|
||||
|
||||
var dialog = element(by.css('.md-dialog'));
|
||||
browser.sleep(500);
|
||||
|
||||
expect(dialog.isPresent()).toEqual(true);
|
||||
|
||||
dialog.sendKeys(protractor.Key.ESCAPE);
|
||||
|
||||
expect(element(by.css('.md-dialog')).isPresent()).toEqual(false);
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
</p>
|
||||
|
||||
<section>
|
||||
<form (^submit)="submit('form submit')">
|
||||
<form (submit)="submit('form submit')">
|
||||
<button md-button>SUBMIT</button>
|
||||
<button>Native button</button>
|
||||
</form>
|
||||
|
@ -45,32 +45,32 @@
|
|||
<section>
|
||||
<span class="label">Regular button</span>
|
||||
|
||||
<button md-button (^click)="click('button')">BUTTON</button>
|
||||
<button md-button (click)="click('button')">BUTTON</button>
|
||||
|
||||
<button md-button class="md-primary" (^click)="click('primary')">PRIMARY</button>
|
||||
<button md-button disabled="disabled" (^click)="click('disabled')">DISABLED</button>
|
||||
<button md-button class="md-accent" (^click)="click('accent')">ACCENT</button>
|
||||
<button md-button class="md-warn" (^click)="click('warn')">WARN</button>
|
||||
<button md-button class="custom" (^click)="click('custom')">CUSTOM</button>
|
||||
<button md-button class="md-primary" (click)="click('primary')">PRIMARY</button>
|
||||
<button md-button disabled="disabled" (click)="click('disabled')">DISABLED</button>
|
||||
<button md-button class="md-accent" (click)="click('accent')">ACCENT</button>
|
||||
<button md-button class="md-warn" (click)="click('warn')">WARN</button>
|
||||
<button md-button class="custom" (click)="click('custom')">CUSTOM</button>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<span class="label">Raised button</span>
|
||||
<button md-raised-button (^click)="click('raised')">BUTTON</button>
|
||||
<button md-raised-button class="md-primary" (^click)="click('raised primary')">PRIMARY</button>
|
||||
<button md-raised-button disabled="disabled" (^click)="click('raised disabled')">DISABLED</button>
|
||||
<button md-raised-button class="md-accent" (^click)="click('raised accent')">ACCENT</button>
|
||||
<button md-raised-button class="md-warn" (^click)="click('raised warn')">WARN</button>
|
||||
<button md-raised-button class="custom" (^click)="click('custom raised')">CUSTOM</button>
|
||||
<button md-raised-button (click)="click('raised')">BUTTON</button>
|
||||
<button md-raised-button class="md-primary" (click)="click('raised primary')">PRIMARY</button>
|
||||
<button md-raised-button disabled="disabled" (click)="click('raised disabled')">DISABLED</button>
|
||||
<button md-raised-button class="md-accent" (click)="click('raised accent')">ACCENT</button>
|
||||
<button md-raised-button class="md-warn" (click)="click('raised warn')">WARN</button>
|
||||
<button md-raised-button class="custom" (click)="click('custom raised')">CUSTOM</button>
|
||||
</section>
|
||||
<section>
|
||||
<span class="label">Fab button</span>
|
||||
<button md-fab (^click)="click('fab')">BTN</button>
|
||||
<button md-fab class="md-primary" (^click)="click('fab primary')">PRMY</button>
|
||||
<button md-fab disabled="disabled" (^click)="click('fab disabled')">DIS</button>
|
||||
<button md-fab class="md-accent" (^click)="click('fab accent')">ACC</button>
|
||||
<button md-fab class="md-warn" (^click)="click('fab warn')">WRN</button>
|
||||
<button md-fab class="custom" (^click)="click('custom fab')">CSTM</button>
|
||||
<button md-fab (click)="click('fab')">BTN</button>
|
||||
<button md-fab class="md-primary" (click)="click('fab primary')">PRMY</button>
|
||||
<button md-fab disabled="disabled" (click)="click('fab disabled')">DIS</button>
|
||||
<button md-fab class="md-accent" (click)="click('fab accent')">ACC</button>
|
||||
<button md-fab class="md-warn" (click)="click('fab warn')">WRN</button>
|
||||
<button md-fab class="custom" (click)="click('custom fab')">CSTM</button>
|
||||
</section>
|
||||
<section>
|
||||
<span class="label">Anchor / hyperlink</span>
|
||||
|
@ -81,8 +81,8 @@
|
|||
|
||||
<section dir="rtl">
|
||||
<span class="label" dir="ltr">Right-to-left</span>
|
||||
<button md-button (^click)="click('Hebrew button')">לחצן</button>
|
||||
<button md-raised-button (^click)="click('Hebrew raised button')">העלה</button>
|
||||
<button md-button (click)="click('Hebrew button')">לחצן</button>
|
||||
<button md-raised-button (click)="click('Hebrew raised button')">העלה</button>
|
||||
<a md-button href="http://translate.google.com">עוגן</a>
|
||||
</section>
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<div md-theme="default">
|
||||
<h2>Checkbox demo</h2>
|
||||
|
||||
<md-checkbox (^click)="increment()">Normal checkbox</md-checkbox>
|
||||
<md-checkbox class="md-primary" (^click)="increment()">Primary checkbox</md-checkbox>
|
||||
<md-checkbox disabled (^click)="increment()">Disabled checkbox</md-checkbox>
|
||||
<md-checkbox (click)="increment()">Normal checkbox</md-checkbox>
|
||||
<md-checkbox class="md-primary" (click)="increment()">Primary checkbox</md-checkbox>
|
||||
<md-checkbox disabled (click)="increment()">Disabled checkbox</md-checkbox>
|
||||
|
||||
<p>Toggle count: {{toggleCount}}</p>
|
||||
</div>
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
<hr>
|
||||
<h3>Standalone</h3>
|
||||
|
||||
<md-radio-button name="element" (^click)="onIndividualClick()">Earth</md-radio-button>
|
||||
<md-radio-button name="element" (^click)="onIndividualClick()">Fire</md-radio-button>
|
||||
<md-radio-button name="element" (^click)="onIndividualClick()" disabled>Wind (disabled)</md-radio-button>
|
||||
<md-radio-button name="element" (^click)="onIndividualClick()">Heart</md-radio-button>
|
||||
<md-radio-button name="element" (click)="onIndividualClick()">Earth</md-radio-button>
|
||||
<md-radio-button name="element" (click)="onIndividualClick()">Fire</md-radio-button>
|
||||
<md-radio-button name="element" (click)="onIndividualClick()" disabled>Wind (disabled)</md-radio-button>
|
||||
<md-radio-button name="element" (click)="onIndividualClick()">Heart</md-radio-button>
|
||||
|
||||
<p>individual radio value change count: {{individualValueChanges}}</p>
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<div md-theme="default">
|
||||
<h2>NgSwitch demo</h2>
|
||||
|
||||
<md-switch (^click)="increment()">Normal switch</md-switch>
|
||||
<md-switch class="md-primary" (^click)="increment()">Primary switch</md-switch>
|
||||
<md-switch disabled (^click)="increment()">Disabled switch</md-switch>
|
||||
<md-switch (click)="increment()">Normal switch</md-switch>
|
||||
<md-switch class="md-primary" (click)="increment()">Primary switch</md-switch>
|
||||
<md-switch disabled (click)="increment()">Disabled switch</md-switch>
|
||||
|
||||
<p>Toggle count: {{toggleCount}}</p>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue