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:
@ -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'
|
||||
}
|
||||
|
Reference in New Issue
Block a user