refactor(proto_view_factory): expose data for generating change detectors

Also consolidates metadata handling in `ElementInjector`

BREAKING CHANGE:
- renames `DirectiveMetadataReader` into `DirectiveResolver`
  and removes `src/core/compiler/directive_metadata`.

Fixes #1712
Fixes #1713
This commit is contained in:
Tobias Bosch
2015-05-11 17:59:39 -07:00
parent 5114411749
commit ecb068019b
33 changed files with 685 additions and 436 deletions

View File

@ -93,7 +93,7 @@ export class ProtoViewDto {
static get COMPONENT_VIEW_TYPE() { return 1; }
// A view that is embedded into another View via a <template> element
// inside of a component view
static get EMBEDDED_VIEW_TYPE() { return 1; }
static get EMBEDDED_VIEW_TYPE() { return 2; }
render: RenderProtoViewRef;
elementBinders:List<ElementBinder>;
@ -114,6 +114,7 @@ export class DirectiveMetadata {
id:any;
selector:string;
compileChildren:boolean;
events:List<string>;
hostListeners:Map<string, string>;
hostProperties:Map<string, string>;
hostAttributes:Map<string, string>;
@ -121,10 +122,19 @@ export class DirectiveMetadata {
properties:Map<string, string>;
readAttributes:List<string>;
type:number;
constructor({id, selector, compileChildren, hostListeners, hostProperties, hostAttributes, hostActions, properties, readAttributes, type}) {
callOnDestroy:boolean;
callOnChange:boolean;
callOnAllChangesDone:boolean;
changeDetection: string;
constructor({id, selector, compileChildren, events, hostListeners, hostProperties,
hostAttributes, hostActions, properties, readAttributes, type,
callOnDestroy, callOnChange, callOnAllChangesDone,
changeDetection
}) {
this.id = id;
this.selector = selector;
this.compileChildren = isPresent(compileChildren) ? compileChildren : true;
this.events = events;
this.hostListeners = hostListeners;
this.hostProperties = hostProperties;
this.hostAttributes = hostAttributes;
@ -132,6 +142,10 @@ export class DirectiveMetadata {
this.properties = properties;
this.readAttributes = readAttributes;
this.type = type;
this.callOnDestroy = callOnDestroy;
this.callOnChange = callOnChange;
this.callOnAllChangesDone = callOnAllChangesDone;
this.changeDetection = changeDetection;
}
}

View File

@ -1,10 +1,11 @@
import {isPresent} from 'angular2/src/facade/lang';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {List, ListWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {CompileElement} from './compile_element';
import {CompileControl} from './compile_control';
import {CompileStep} from './compile_step';
import {ProtoViewBuilder} from '../view/proto_view_builder';
import {ProtoViewDto} from '../../api';
/**
* CompilePipeline for executing CompileSteps recursively for
@ -16,10 +17,13 @@ export class CompilePipeline {
this._control = new CompileControl(steps);
}
process(rootElement, compilationCtxtDescription:string = ''):List {
process(rootElement, protoViewType:number = null, compilationCtxtDescription:string = ''):List {
if (isBlank(protoViewType)) {
protoViewType = ProtoViewDto.COMPONENT_VIEW_TYPE;
}
var results = ListWrapper.create();
var rootCompileElement = new CompileElement(rootElement, compilationCtxtDescription);
rootCompileElement.inheritedProtoView = new ProtoViewBuilder(rootElement);
rootCompileElement.inheritedProtoView = new ProtoViewBuilder(rootElement, protoViewType);
rootCompileElement.isViewRoot = true;
this._process(results, null, rootCompileElement,
compilationCtxtDescription

View File

@ -29,7 +29,7 @@ export class DomCompiler extends RenderCompiler {
compile(template: ViewDefinition):Promise<ProtoViewDto> {
var tplPromise = this._templateLoader.load(template);
return PromiseWrapper.then(tplPromise,
(el) => this._compileTemplate(template, el),
(el) => this._compileTemplate(template, el, ProtoViewDto.COMPONENT_VIEW_TYPE),
(_) => { throw new BaseException(`Failed to load the template "${template.componentId}"`); }
);
}
@ -42,13 +42,13 @@ export class DomCompiler extends RenderCompiler {
directives: [directiveMetadata]
});
var element = DOM.createElement(directiveMetadata.selector);
return this._compileTemplate(hostViewDef, element);
return this._compileTemplate(hostViewDef, element, ProtoViewDto.HOST_VIEW_TYPE);
}
_compileTemplate(viewDef: ViewDefinition, tplElement):Promise<ProtoViewDto> {
_compileTemplate(viewDef: ViewDefinition, tplElement, protoViewType:number):Promise<ProtoViewDto> {
var subTaskPromises = [];
var pipeline = new CompilePipeline(this._stepFactory.createSteps(viewDef, subTaskPromises));
var compileElements = pipeline.process(tplElement, viewDef.componentId);
var compileElements = pipeline.process(tplElement, protoViewType, viewDef.componentId);
var protoView = compileElements[0].inheritedProtoView.build();

View File

@ -57,9 +57,24 @@ export class DirectiveParser extends CompileStep {
});
var componentDirective;
var foundDirectiveIndices = [];
var elementBinder = null;
this._selectorMatcher.match(cssSelector, (selector, directiveIndex) => {
var elementBinder = current.bindElement();
elementBinder = current.bindElement();
var directive = this._directives[directiveIndex];
if (directive.type === DirectiveMetadata.COMPONENT_TYPE) {
// components need to go first, so it is easier to locate them in the result.
ListWrapper.insert(foundDirectiveIndices, 0, directiveIndex);
if (isPresent(componentDirective)) {
throw new BaseException(`Only one component directive is allowed per element - check ${current.elementDescription}`);
}
componentDirective = directive;
elementBinder.setComponentId(directive.id);
} else {
ListWrapper.push(foundDirectiveIndices, directiveIndex);
}
});
ListWrapper.forEach(foundDirectiveIndices, (directiveIndex) => {
var directive = this._directives[directiveIndex];
var directiveBinderBuilder = elementBinder.bindDirective(directiveIndex);
current.compileChildren = current.compileChildren && directive.compileChildren;
@ -95,13 +110,6 @@ export class DirectiveParser extends CompileStep {
elementBinder.readAttribute(attrName);
});
}
if (directive.type === DirectiveMetadata.COMPONENT_TYPE) {
if (isPresent(componentDirective)) {
throw new BaseException(`Only one component directive is allowed per element - check ${current.elementDescription}`);
}
componentDirective = directive;
elementBinder.setComponentId(directive.id);
}
});
}

View File

@ -18,11 +18,13 @@ export class ProtoViewBuilder {
rootElement;
variableBindings: Map<string, string>;
elements:List<ElementBinderBuilder>;
type:number;
constructor(rootElement) {
constructor(rootElement, type:number) {
this.rootElement = rootElement;
this.elements = [];
this.variableBindings = MapWrapper.create();
this.type = type;
}
bindElement(element, description = null):ElementBinderBuilder {
@ -104,6 +106,7 @@ export class ProtoViewBuilder {
element: this.rootElement,
elementBinders: renderElementBinders
})),
type: this.type,
elementBinders: apiElementBinders,
variableBindings: this.variableBindings
});
@ -169,7 +172,7 @@ export class ElementBinderBuilder {
if (isPresent(this.nestedProtoView)) {
throw new BaseException('Only one nested view per element is allowed');
}
this.nestedProtoView = new ProtoViewBuilder(rootElement);
this.nestedProtoView = new ProtoViewBuilder(rootElement, api.ProtoViewDto.EMBEDDED_VIEW_TYPE);
return this.nestedProtoView;
}