feat(compiler): support on- and []

This commit is contained in:
Tobias Bosch
2014-11-19 14:54:07 -08:00
parent c6846f1163
commit fc5b7edca4
9 changed files with 97 additions and 12 deletions

View File

@ -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<int>')
@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

View File

@ -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) {

View File

@ -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)) {

View File

@ -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);

View File

@ -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 <template> elements!');
}
current.addVariableBinding(bindParts[3], attrValue);
} else if (isPresent(bindParts[4])) {
current.addVariableBinding(bindParts[4], attrValue);
} else if (isPresent(bindParts[3])) {
// match: on-prop
current.addEventBinding(bindParts[4], this._parser.parseAction(attrValue));
} else if (isPresent(bindParts[5])) {
// match: [prop]
current.addPropertyBinding(bindParts[4], this._parser.parseBinding(attrValue));
current.addPropertyBinding(bindParts[5], this._parser.parseBinding(attrValue));
} else if (isPresent(bindParts[6])) {
// match: (prop)
current.addEventBinding(bindParts[6], this._parser.parseBinding(attrValue));
}
} else {
var expression = interpolationToExpression(attrValue);

View File

@ -141,6 +141,9 @@ export class ProtoView {
*/
bindTextNode(indexInParent:int, expression:AST) {
var elBinder = this.elementBinders[this.elementBinders.length-1];
if (isBlank(elBinder.textNodeIndices)) {
elBinder.textNodeIndices = ListWrapper.create();
}
ListWrapper.push(elBinder.textNodeIndices, indexInParent);
this.protoWatchGroup.watch(expression, this.textNodesWithBindingCount++);
}
@ -162,6 +165,17 @@ export class ProtoView {
);
}
/**
* Adds an event binding for the last created ElementBinder via bindElement
*/
bindEvent(eventName:string, expression:AST) {
var elBinder = this.elementBinders[this.elementBinders.length-1];
if (isBlank(elBinder.events)) {
elBinder.events = MapWrapper.create();
}
MapWrapper.set(elBinder.events, eventName, expression);
}
/**
* Adds a directive property binding for the last created ElementBinder via bindElement
*/
@ -228,9 +242,11 @@ export class ProtoView {
}
static _collectTextNodes(allTextNodes, element, indices) {
var childNodes = DOM.templateAwareRoot(element).childNodes;
for (var i = 0; i < indices.length; ++i) {
ListWrapper.push(allTextNodes, childNodes[indices[i]]);
if (isPresent(indices)) {
var childNodes = DOM.templateAwareRoot(element).childNodes;
for (var i = 0; i < indices.length; ++i) {
ListWrapper.push(allTextNodes, childNodes[indices[i]]);
}
}
}