From fc5b7edca488dce9ceec9ff845930cce69a9d676 Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Wed, 19 Nov 2014 14:54:07 -0800 Subject: [PATCH] feat(compiler): support `on-` and `[]` --- modules/core/src/compiler/element_binder.js | 8 +++++-- .../src/compiler/pipeline/compile_element.js | 8 +++++++ .../pipeline/element_binder_builder.js | 10 +++++++++ .../pipeline/element_binding_marker.js | 2 ++ .../pipeline/property_binding_parser.js | 18 ++++++++++----- modules/core/src/compiler/view.js | 22 ++++++++++++++++--- .../pipeline/element_binder_builder_spec.js | 20 ++++++++++++++++- .../pipeline/element_binding_marker_spec.js | 11 +++++++++- .../pipeline/property_binding_parser_spec.js | 10 +++++++++ 9 files changed, 97 insertions(+), 12 deletions(-) diff --git a/modules/core/src/compiler/element_binder.js b/modules/core/src/compiler/element_binder.js index b97ccb732b..6d1a704c2e 100644 --- a/modules/core/src/compiler/element_binder.js +++ b/modules/core/src/compiler/element_binder.js @@ -1,5 +1,6 @@ import {ProtoElementInjector} from './element_injector'; import {FIELD} from 'facade/lang'; +import {MapWrapper} from 'facade/collection'; import {AnnotatedType} from './annotated_type'; // Comment out as dartanalyzer does not look into @FIELD // import {List} from 'facade/collection'; @@ -11,12 +12,15 @@ export class ElementBinder { @FIELD('final templateDirective:AnnotatedType') @FIELD('final textNodeIndices:List') @FIELD('hasElementPropertyBindings:bool') - constructor(protoElementInjector: ProtoElementInjector, componentDirective:AnnotatedType, templateDirective:AnnotatedType) { + constructor( + protoElementInjector: ProtoElementInjector, componentDirective:AnnotatedType, templateDirective:AnnotatedType) { this.protoElementInjector = protoElementInjector; this.componentDirective = componentDirective; this.templateDirective = templateDirective; + // updated later when events are bound + this.events = null; // updated later when text nodes are bound - this.textNodeIndices = []; + this.textNodeIndices = null; // updated later when element properties are bound this.hasElementPropertyBindings = false; // updated later, so we are able to resolve cycles diff --git a/modules/core/src/compiler/pipeline/compile_element.js b/modules/core/src/compiler/pipeline/compile_element.js index 30fa4d971f..83245972ba 100644 --- a/modules/core/src/compiler/pipeline/compile_element.js +++ b/modules/core/src/compiler/pipeline/compile_element.js @@ -20,6 +20,7 @@ export class CompileElement { this._classList = null; this.textNodeBindings = null; this.propertyBindings = null; + this.eventBindings = null; this.variableBindings = null; this.decoratorDirectives = null; this.templateDirective = null; @@ -84,6 +85,13 @@ export class CompileElement { MapWrapper.set(this.variableBindings, contextName, templateName); } + addEventBinding(eventName:string, expression:ASTWithSource) { + if (isBlank(this.eventBindings)) { + this.eventBindings = MapWrapper.create(); + } + MapWrapper.set(this.eventBindings, eventName, expression); + } + addDirective(directive:AnnotatedType) { var annotation = directive.annotation; if (annotation instanceof Decorator) { diff --git a/modules/core/src/compiler/pipeline/element_binder_builder.js b/modules/core/src/compiler/pipeline/element_binder_builder.js index 10d8b1786c..21233f4adf 100644 --- a/modules/core/src/compiler/pipeline/element_binder_builder.js +++ b/modules/core/src/compiler/pipeline/element_binder_builder.js @@ -33,6 +33,7 @@ import {CompileControl} from './compile_control'; * - CompileElement#inheritedProtoElementInjector * - CompileElement#textNodeBindings * - CompileElement#propertyBindings + * - CompileElement#eventBindings * - CompileElement#decoratorDirectives * - CompileElement#componentDirective * - CompileElement#templateDirective @@ -60,6 +61,9 @@ export class ElementBinderBuilder extends CompileStep { if (isPresent(current.propertyBindings)) { this._bindElementProperties(protoView, current); } + if (isPresent(current.eventBindings)) { + this._bindEvents(protoView, current); + } this._bindDirectiveProperties(this._collectDirectives(current), current); } else if (isPresent(parent)) { elementBinder = parent.inheritedElementBinder; @@ -79,6 +83,12 @@ export class ElementBinderBuilder extends CompileStep { }); } + _bindEvents(protoView, compileElement) { + MapWrapper.forEach(compileElement.eventBindings, (expression, eventName) => { + protoView.bindEvent(eventName, expression.ast); + }); + } + _collectDirectives(compileElement) { var directives; if (isPresent(compileElement.decoratorDirectives)) { diff --git a/modules/core/src/compiler/pipeline/element_binding_marker.js b/modules/core/src/compiler/pipeline/element_binding_marker.js index 5adf802bd8..441fd67f6a 100644 --- a/modules/core/src/compiler/pipeline/element_binding_marker.js +++ b/modules/core/src/compiler/pipeline/element_binding_marker.js @@ -19,6 +19,7 @@ const NG_BINDING_CLASS = 'ng-binding'; * - CompileElement#textNodeBindings * - CompileElement#propertyBindings * - CompileElement#variableBindings + * - CompileElement#eventBindings * - CompileElement#decoratorDirectives * - CompileElement#componentDirective * - CompileElement#templateDirective @@ -29,6 +30,7 @@ export class ElementBindingMarker extends CompileStep { (isPresent(current.textNodeBindings) && MapWrapper.size(current.textNodeBindings)>0) || (isPresent(current.propertyBindings) && MapWrapper.size(current.propertyBindings)>0) || (isPresent(current.variableBindings) && MapWrapper.size(current.variableBindings)>0) || + (isPresent(current.eventBindings) && MapWrapper.size(current.eventBindings)>0) || (isPresent(current.decoratorDirectives) && current.decoratorDirectives.length > 0) || isPresent(current.templateDirective) || isPresent(current.componentDirective); diff --git a/modules/core/src/compiler/pipeline/property_binding_parser.js b/modules/core/src/compiler/pipeline/property_binding_parser.js index 79cc94dc86..47961dc860 100644 --- a/modules/core/src/compiler/pipeline/property_binding_parser.js +++ b/modules/core/src/compiler/pipeline/property_binding_parser.js @@ -12,13 +12,15 @@ import {CompileControl} from './compile_control'; import {interpolationToExpression} from './text_interpolation_parser'; // TODO(tbosch): Cannot make this const/final right now because of the transpiler... -var BIND_NAME_REGEXP = RegExpWrapper.create('^(?:(?:(bind)|(let))-(.+))|\\[([^\\]]+)\\]'); +var BIND_NAME_REGEXP = RegExpWrapper.create('^(?:(?:(bind)|(let)|(on))-(.+))|\\[([^\\]]+)\\]|\\(([^\\]]+)\\)'); /** * Parses the property bindings on a single element. * * Fills: * - CompileElement#propertyBindings + * - CompileElement#eventBindings + * - CompileElement#variableBindings */ export class PropertyBindingParser extends CompileStep { constructor(parser:Parser) { @@ -32,7 +34,7 @@ export class PropertyBindingParser extends CompileStep { if (isPresent(bindParts)) { if (isPresent(bindParts[1])) { // match: bind-prop - current.addPropertyBinding(bindParts[3], this._parser.parseBinding(attrValue)); + current.addPropertyBinding(bindParts[4], this._parser.parseBinding(attrValue)); } else if (isPresent(bindParts[2])) { // match: let-prop // Note: We assume that the ViewSplitter already did its work, i.e. template directive should @@ -40,10 +42,16 @@ export class PropertyBindingParser extends CompileStep { if (!(current.element instanceof TemplateElement)) { throw new BaseException('let-* is only allowed on