fix(compiler): fix directive registration order

fix #328
This commit is contained in:
Victor Berchet
2015-01-09 18:48:28 +01:00
parent fd34a56347
commit b4338b623c
8 changed files with 71 additions and 52 deletions
@@ -1,4 +1,4 @@
import {Type, FIELD} from 'facade/lang';
import {Type} from 'facade/lang';
import {Directive} from '../annotations/annotations'
import {List} from 'facade/collection'
import {ShadowDomStrategy} from './shadow_dom';
@@ -1,6 +1,6 @@
import {List, Map, ListWrapper, MapWrapper} from 'facade/collection';
import {Element, DOM} from 'facade/dom';
import {int, isBlank, isPresent} from 'facade/lang';
import {int, isBlank, isPresent, Type} from 'facade/lang';
import {DirectiveMetadata} from '../directive_metadata';
import {Decorator} from '../../annotations/annotations';
import {Component} from '../../annotations/annotations';
@@ -27,6 +27,7 @@ export class CompileElement {
decoratorDirectives:List<DirectiveMetadata>;
templateDirective:DirectiveMetadata;
componentDirective:DirectiveMetadata;
_allDirectives:List<DirectiveMetadata>;
isViewRoot:boolean;
hasBindings:boolean;
inheritedProtoView:ProtoView;
@@ -45,6 +46,7 @@ export class CompileElement {
this.decoratorDirectives = null;
this.templateDirective = null;
this.componentDirective = null;
this._allDirectives = null;
this.isViewRoot = false;
this.hasBindings = false;
// inherited down to children if they don't have
@@ -116,6 +118,7 @@ export class CompileElement {
addDirective(directive:DirectiveMetadata) {
var annotation = directive.annotation;
this._allDirectives = null;
if (annotation instanceof Decorator) {
if (isBlank(this.decoratorDirectives)) {
this.decoratorDirectives = ListWrapper.create();
@@ -130,4 +133,23 @@ export class CompileElement {
this.componentDirective = directive;
}
}
getAllDirectives(): List<DirectiveMetadata> {
if (this._allDirectives === null) {
// Collect all the directives
// When present the component directive must be first
var directives = ListWrapper.create();
if (isPresent(this.componentDirective)) {
ListWrapper.push(directives, this.componentDirective);
}
if (isPresent(this.templateDirective)) {
ListWrapper.push(directives, this.templateDirective);
}
if (isPresent(this.decoratorDirectives)) {
directives = ListWrapper.concat(directives, this.decoratorDirectives);
}
this._allDirectives = directives;
}
return this._allDirectives;
}
}
@@ -58,7 +58,7 @@ export class ElementBinderBuilder extends CompileStep {
if (isPresent(current.eventBindings)) {
this._bindEvents(protoView, current);
}
this._bindDirectiveProperties(this._collectDirectives(current), current);
this._bindDirectiveProperties(current.getAllDirectives(), current);
} else if (isPresent(parent)) {
elementBinder = parent.inheritedElementBinder;
}
@@ -85,37 +85,21 @@ export class ElementBinderBuilder extends CompileStep {
});
}
_collectDirectives(compileElement) {
var directives;
if (isPresent(compileElement.decoratorDirectives)) {
directives = ListWrapper.clone(compileElement.decoratorDirectives);
} else {
directives = [];
}
if (isPresent(compileElement.templateDirective)) {
ListWrapper.push(directives, compileElement.templateDirective);
}
if (isPresent(compileElement.componentDirective)) {
ListWrapper.push(directives, compileElement.componentDirective);
}
return directives;
}
_bindDirectiveProperties(typesWithAnnotations, compileElement) {
_bindDirectiveProperties(directives: List<DirectiveMetadata>,
compileElement: CompileElement) {
var protoView = compileElement.inheritedProtoView;
var directiveIndex = 0;
ListWrapper.forEach(typesWithAnnotations, (typeWithAnnotation) => {
var annotation = typeWithAnnotation.annotation;
if (isBlank(annotation.bind)) {
return;
}
StringMapWrapper.forEach(annotation.bind, (dirProp, elProp) => {
for (var directiveIndex = 0; directiveIndex < directives.length; directiveIndex++) {
var directive = ListWrapper.get(directives, directiveIndex);
var annotation = directive.annotation;
if (isBlank(annotation.bind)) continue;
StringMapWrapper.forEach(annotation.bind, function (dirProp, elProp) {
var expression = isPresent(compileElement.propertyBindings) ?
MapWrapper.get(compileElement.propertyBindings, elProp) :
null;
if (isBlank(expression)) {
throw new BaseException('No element binding found for property '+elProp
+' which is required by directive '+stringify(typeWithAnnotation.type));
+' which is required by directive '+stringify(directive.type));
}
var len = dirProp.length;
var dirBindingName = dirProp;
@@ -129,7 +113,6 @@ export class ElementBinderBuilder extends CompileStep {
isContentWatch
);
});
directiveIndex++;
});
}
}
}
@@ -32,8 +32,7 @@ export class ProtoElementInjectorBuilder extends CompileStep {
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
var distanceToParentInjector = this._getDistanceToParentInjector(parent, current);
var parentProtoElementInjector = this._getParentProtoElementInjector(parent, current);
var injectorBindings = this._collectDirectiveBindings(current);
var injectorBindings = ListWrapper.map(current.getAllDirectives(), this._createBinding);
// TODO: add lightDomServices as well,
// but after the directives as we rely on that order
// in the element_binder_builder.
@@ -65,22 +64,6 @@ export class ProtoElementInjectorBuilder extends CompileStep {
return null;
}
_collectDirectiveBindings(pipelineElement) {
var directiveTypes = [];
if (isPresent(pipelineElement.componentDirective)) {
ListWrapper.push(directiveTypes, this._createBinding(pipelineElement.componentDirective));
}
if (isPresent(pipelineElement.templateDirective)) {
ListWrapper.push(directiveTypes, this._createBinding(pipelineElement.templateDirective));
}
if (isPresent(pipelineElement.decoratorDirectives)) {
for (var i=0; i<pipelineElement.decoratorDirectives.length; i++) {
ListWrapper.push(directiveTypes, this._createBinding(pipelineElement.decoratorDirectives[i]));
}
}
return directiveTypes;
}
_createBinding(d:DirectiveMetadata): DirectiveBinding {
return DirectiveBinding.createFromType(d.type, d.annotation);
}