refactor(render): user render compiler
This commit is contained in:
19
modules/angular2/src/render/api.js
vendored
19
modules/angular2/src/render/api.js
vendored
@ -19,8 +19,6 @@ export class ElementBinder {
|
||||
index:number;
|
||||
parentIndex:number;
|
||||
distanceToParent:number;
|
||||
parentWithDirectivesIndex:number;
|
||||
distanceToParentWithDirectives:number;
|
||||
directives:List<DirectiveBinder>;
|
||||
nestedProtoView:ProtoView;
|
||||
propertyBindings: Map<string, ASTWithSource>;
|
||||
@ -30,24 +28,25 @@ export class ElementBinder {
|
||||
// with a local name
|
||||
eventBindings: Map<string, ASTWithSource>;
|
||||
textBindings: List<ASTWithSource>;
|
||||
readAttributes: Map<string, string>;
|
||||
|
||||
constructor({
|
||||
index, parentIndex, distanceToParent, parentWithDirectivesIndex,
|
||||
distanceToParentWithDirectives, directives, nestedProtoView,
|
||||
index, parentIndex, distanceToParent,
|
||||
directives, nestedProtoView,
|
||||
propertyBindings, variableBindings,
|
||||
eventBindings, textBindings
|
||||
eventBindings, textBindings,
|
||||
readAttributes
|
||||
}) {
|
||||
this.index = index;
|
||||
this.parentIndex = parentIndex;
|
||||
this.distanceToParent = distanceToParent;
|
||||
this.parentWithDirectivesIndex = parentWithDirectivesIndex;
|
||||
this.distanceToParentWithDirectives = distanceToParentWithDirectives;
|
||||
this.directives = directives;
|
||||
this.nestedProtoView = nestedProtoView;
|
||||
this.propertyBindings = propertyBindings;
|
||||
this.variableBindings = variableBindings;
|
||||
this.eventBindings = eventBindings;
|
||||
this.textBindings = textBindings;
|
||||
this.readAttributes = readAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +72,7 @@ export class ProtoView {
|
||||
elementBinders:List<ElementBinder>;
|
||||
variableBindings: Map<string, string>;
|
||||
|
||||
constructor({render, elementBinders, variableBindings}) {
|
||||
constructor({render, elementBinders, variableBindings}={}) {
|
||||
this.render = render;
|
||||
this.elementBinders = elementBinders;
|
||||
this.variableBindings = variableBindings;
|
||||
@ -90,14 +89,16 @@ export class DirectiveMetadata {
|
||||
events:Map<string, string>;
|
||||
bind:Map<string, string>;
|
||||
setters:List<string>;
|
||||
readAttributes:List<string>;
|
||||
type:number;
|
||||
constructor({id, selector, compileChildren, events, bind, setters, type}) {
|
||||
constructor({id, selector, compileChildren, events, bind, setters, readAttributes, type}) {
|
||||
this.id = id;
|
||||
this.selector = selector;
|
||||
this.compileChildren = isPresent(compileChildren) ? compileChildren : true;
|
||||
this.events = events;
|
||||
this.bind = bind;
|
||||
this.setters = setters;
|
||||
this.readAttributes = readAttributes;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,14 @@ import {BaseException} from 'angular2/src/facade/lang';
|
||||
|
||||
import {Template, ProtoView} from '../../api';
|
||||
import {CompilePipeline} from './compile_pipeline';
|
||||
import {TemplateLoader} from './template_loader';
|
||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {CompileStepFactory} from './compile_step_factory';
|
||||
|
||||
/**
|
||||
* The compiler loads and translates the html templates of components into
|
||||
* nested ProtoViews. To decompose its functionality it uses
|
||||
* the CompilePipeline and the CompileSteps.
|
||||
*/
|
||||
export class Compiler {
|
||||
_templateLoader: TemplateLoader;
|
||||
_stepFactory: CompileStepFactory;
|
||||
|
@ -9,8 +9,6 @@ import {CompileStep} from './compile_step';
|
||||
import {CompileElement} from './compile_element';
|
||||
import {CompileControl} from './compile_control';
|
||||
|
||||
import {setterFactory} from 'angular2/src/render/dom/compiler/property_setter_factory';
|
||||
|
||||
import {DirectiveMetadata} from '../../api';
|
||||
import {dashCaseToCamelCase, camelCaseToDashCase} from '../util';
|
||||
|
||||
@ -72,7 +70,12 @@ export class DirectiveParser extends CompileStep {
|
||||
}
|
||||
if (isPresent(directive.setters)) {
|
||||
ListWrapper.forEach(directive.setters, (propertyName) => {
|
||||
directiveBinder.bindPropertySetter(propertyName, setterFactory(propertyName));
|
||||
elementBinder.bindPropertySetter(propertyName);
|
||||
});
|
||||
}
|
||||
if (isPresent(directive.readAttributes)) {
|
||||
ListWrapper.forEach(directive.readAttributes, (attrName) => {
|
||||
elementBinder.readAttribute(attrName);
|
||||
});
|
||||
}
|
||||
if (directive.type === DirectiveMetadata.VIEWPORT_TYPE) {
|
||||
|
@ -8,7 +8,6 @@ import {CompileElement} from './compile_element';
|
||||
import {CompileControl} from './compile_control';
|
||||
|
||||
import {dashCaseToCamelCase} from '../util';
|
||||
import {setterFactory} from 'angular2/src/render/dom/compiler/property_setter_factory';
|
||||
|
||||
// Group 1 = "bind-"
|
||||
// Group 2 = "var-" or "#"
|
||||
@ -92,7 +91,6 @@ export class PropertyBindingParser extends CompileStep {
|
||||
var binder = current.bindElement();
|
||||
var camelCaseName = dashCaseToCamelCase(name);
|
||||
binder.bindProperty(camelCaseName, ast);
|
||||
binder.bindPropertySetter(camelCaseName, setterFactory(camelCaseName));
|
||||
MapWrapper.set(newAttrs, name, ast.source);
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import {Injectable} from 'angular2/di';
|
||||
import {isBlank, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
|
||||
import {Map, MapWrapper, StringMapWrapper, StringMap} from 'angular2/src/facade/collection';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
@ -12,6 +13,7 @@ import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||
* Strategy to load component templates.
|
||||
* @publicModule angular2/angular2
|
||||
*/
|
||||
@Injectable()
|
||||
export class TemplateLoader {
|
||||
_xhr: XHR;
|
||||
_htmlCache: StringMap;
|
||||
|
@ -7,6 +7,8 @@ import {CompileStep} from './compile_step';
|
||||
import {CompileElement} from './compile_element';
|
||||
import {CompileControl} from './compile_control';
|
||||
|
||||
import {dashCaseToCamelCase} from '../util';
|
||||
|
||||
/**
|
||||
* Splits views at `<template>` elements or elements with `template` attribute:
|
||||
* For `<template>` elements:
|
||||
@ -105,10 +107,14 @@ export class ViewSplitter extends CompileStep {
|
||||
for (var i=0; i<bindings.length; i++) {
|
||||
var binding = bindings[i];
|
||||
if (binding.keyIsVar) {
|
||||
compileElement.bindElement().bindVariable(binding.key, binding.name);
|
||||
compileElement.bindElement().bindVariable(
|
||||
dashCaseToCamelCase(binding.key), binding.name
|
||||
);
|
||||
MapWrapper.set(compileElement.attrs(), binding.key, binding.name);
|
||||
} else if (isPresent(binding.expression)) {
|
||||
compileElement.bindElement().bindProperty(binding.key, binding.expression);
|
||||
compileElement.bindElement().bindProperty(
|
||||
dashCaseToCamelCase(binding.key), binding.expression
|
||||
);
|
||||
MapWrapper.set(compileElement.attrs(), binding.key, binding.expression.source);
|
||||
} else {
|
||||
DOM.setAttribute(compileElement.element, binding.key, '');
|
||||
|
@ -26,7 +26,7 @@ export class ShadowDomCompileStep extends CompileStep {
|
||||
if (current.ignoreBindings) {
|
||||
return;
|
||||
}
|
||||
var tagName = DOM.tagName(current.element);
|
||||
var tagName = DOM.tagName(current.element).toUpperCase();
|
||||
if (tagName == 'STYLE') {
|
||||
this._processStyleElement(current);
|
||||
} else if (tagName == 'CONTENT') {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {AST} from 'angular2/change_detection';
|
||||
import {SetterFn} from 'angular2/src/reflection/types';
|
||||
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import * as protoViewModule from './proto_view';
|
||||
@ -15,6 +16,7 @@ export class ElementBinder {
|
||||
componentId: string;
|
||||
parentIndex:number;
|
||||
distanceToParent:number;
|
||||
propertySetters: Map<string, SetterFn>;
|
||||
|
||||
constructor({
|
||||
textNodeIndices,
|
||||
@ -24,7 +26,8 @@ export class ElementBinder {
|
||||
eventLocals,
|
||||
eventNames,
|
||||
parentIndex,
|
||||
distanceToParent
|
||||
distanceToParent,
|
||||
propertySetters
|
||||
}) {
|
||||
this.textNodeIndices = textNodeIndices;
|
||||
this.contentTagSelector = contentTagSelector;
|
||||
@ -34,6 +37,7 @@ export class ElementBinder {
|
||||
this.eventNames = eventNames;
|
||||
this.parentIndex = parentIndex;
|
||||
this.distanceToParent = distanceToParent;
|
||||
this.propertySetters = propertySetters;
|
||||
}
|
||||
|
||||
mergeChildComponentProtoViews(protoViews:List<protoViewModule.ProtoView>, target:List<protoViewModule.ProtoView>):ElementBinder {
|
||||
@ -45,15 +49,14 @@ export class ElementBinder {
|
||||
}
|
||||
return new ElementBinder({
|
||||
parentIndex: this.parentIndex,
|
||||
// Don't clone as we assume immutability!
|
||||
textNodeIndices: this.textNodeIndices,
|
||||
contentTagSelector: this.contentTagSelector,
|
||||
nestedProtoView: nestedProtoView,
|
||||
componentId: this.componentId,
|
||||
// Don't clone as we assume immutability!
|
||||
eventLocals: this.eventLocals,
|
||||
eventNames: this.eventNames,
|
||||
distanceToParent: this.distanceToParent
|
||||
distanceToParent: this.distanceToParent,
|
||||
propertySetters: this.propertySetters
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {SetterFn} from 'angular2/src/reflection/types';
|
||||
|
||||
import {List, Map, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
@ -16,20 +15,17 @@ export class ProtoView {
|
||||
isTemplateElement:boolean;
|
||||
isRootView:boolean;
|
||||
rootBindingOffset:int;
|
||||
propertySetters: Map<string, SetterFn>;
|
||||
|
||||
constructor({
|
||||
elementBinders,
|
||||
element,
|
||||
isRootView,
|
||||
propertySetters
|
||||
isRootView
|
||||
}) {
|
||||
this.element = element;
|
||||
this.elementBinders = elementBinders;
|
||||
this.isTemplateElement = DOM.isTemplateElement(this.element);
|
||||
this.isRootView = isRootView;
|
||||
this.rootBindingOffset = (isPresent(this.element) && DOM.hasClass(this.element, NG_BINDING_CLASS)) ? 1 : 0;
|
||||
this.propertySetters = propertySetters;
|
||||
}
|
||||
|
||||
mergeChildComponentProtoViews(protoViews:List<ProtoView>, target:List<ProtoView>):ProtoView {
|
||||
@ -45,9 +41,7 @@ export class ProtoView {
|
||||
var result = new ProtoView({
|
||||
elementBinders: elementBinders,
|
||||
element: this.element,
|
||||
isRootView: this.isRootView,
|
||||
// Don't clone as we assume immutability!
|
||||
propertySetters: this.propertySetters
|
||||
isRootView: this.isRootView
|
||||
});
|
||||
ListWrapper.insert(target, 0, result);
|
||||
return result
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {isPresent, BaseException} from 'angular2/src/facade/lang';
|
||||
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper, MapWrapper, Set, SetWrapper} from 'angular2/src/facade/collection';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
@ -9,6 +9,7 @@ import {SetterFn} from 'angular2/src/reflection/types';
|
||||
|
||||
import {ProtoView} from './proto_view';
|
||||
import {ElementBinder} from './element_binder';
|
||||
import {setterFactory} from './property_setter_factory';
|
||||
|
||||
import * as api from '../../api';
|
||||
import * as directDomRenderer from '../direct_dom_renderer';
|
||||
@ -20,14 +21,12 @@ export class ProtoViewBuilder {
|
||||
variableBindings: Map<string, string>;
|
||||
elements:List<ElementBinderBuilder>;
|
||||
isRootView:boolean;
|
||||
propertySetters:Set<string>;
|
||||
|
||||
constructor(rootElement) {
|
||||
this.rootElement = rootElement;
|
||||
this.elements = [];
|
||||
this.isRootView = false;
|
||||
this.variableBindings = MapWrapper.create();
|
||||
this.propertySetters = new Set();
|
||||
}
|
||||
|
||||
bindElement(element, description = null):ElementBinderBuilder {
|
||||
@ -55,13 +54,10 @@ export class ProtoViewBuilder {
|
||||
var renderElementBinders = [];
|
||||
|
||||
var apiElementBinders = [];
|
||||
var propertySetters = MapWrapper.create();
|
||||
ListWrapper.forEach(this.elements, (ebb) => {
|
||||
var propertySetters = MapWrapper.create();
|
||||
var eventLocalsAstSplitter = new EventLocalsAstSplitter();
|
||||
var apiDirectiveBinders = ListWrapper.map(ebb.directives, (db) => {
|
||||
MapWrapper.forEach(db.propertySetters, (setter, propertyName) => {
|
||||
MapWrapper.set(propertySetters, propertyName, setter);
|
||||
});
|
||||
return new api.DirectiveBinder({
|
||||
directiveIndex: db.directiveIndex,
|
||||
propertyBindings: db.propertyBindings,
|
||||
@ -74,15 +70,14 @@ export class ProtoViewBuilder {
|
||||
var nestedProtoView =
|
||||
isPresent(ebb.nestedProtoView) ? ebb.nestedProtoView.build() : null;
|
||||
var parentIndex = isPresent(ebb.parent) ? ebb.parent.index : -1;
|
||||
var parentWithDirectivesIndex = isPresent(ebb.parentWithDirectives) ? ebb.parentWithDirectives.index : -1;
|
||||
ListWrapper.push(apiElementBinders, new api.ElementBinder({
|
||||
index: ebb.index, parentIndex:parentIndex, distanceToParent:ebb.distanceToParent,
|
||||
parentWithDirectivesIndex: parentWithDirectivesIndex, distanceToParentWithDirectives: ebb.distanceToParentWithDirectives,
|
||||
directives: apiDirectiveBinders,
|
||||
nestedProtoView: nestedProtoView,
|
||||
propertyBindings: ebb.propertyBindings, variableBindings: ebb.variableBindings,
|
||||
eventBindings: eventLocalsAstSplitter.splitEventAstIntoLocals(ebb.eventBindings),
|
||||
textBindings: ebb.textBindings
|
||||
textBindings: ebb.textBindings,
|
||||
readAttributes: ebb.readAttributes
|
||||
}));
|
||||
ListWrapper.push(renderElementBinders, new ElementBinder({
|
||||
textNodeIndices: ebb.textBindingIndices,
|
||||
@ -92,15 +87,15 @@ export class ProtoViewBuilder {
|
||||
nestedProtoView: isPresent(nestedProtoView) ? nestedProtoView.render.delegate : null,
|
||||
componentId: ebb.componentId,
|
||||
eventLocals: eventLocalsAstSplitter.buildEventLocals(),
|
||||
eventNames: eventLocalsAstSplitter.buildEventNames()
|
||||
eventNames: eventLocalsAstSplitter.buildEventNames(),
|
||||
propertySetters: propertySetters
|
||||
}));
|
||||
});
|
||||
return new api.ProtoView({
|
||||
render: new directDomRenderer.DirectDomProtoViewRef(new ProtoView({
|
||||
element: this.rootElement,
|
||||
elementBinders: renderElementBinders,
|
||||
isRootView: this.isRootView,
|
||||
propertySetters: propertySetters
|
||||
isRootView: this.isRootView
|
||||
})),
|
||||
elementBinders: apiElementBinders,
|
||||
variableBindings: this.variableBindings
|
||||
@ -113,8 +108,6 @@ export class ElementBinderBuilder {
|
||||
index:number;
|
||||
parent:ElementBinderBuilder;
|
||||
distanceToParent:number;
|
||||
parentWithDirectives:ElementBinderBuilder;
|
||||
distanceToParentWithDirectives:number;
|
||||
directives:List<DirectiveBuilder>;
|
||||
nestedProtoView:ProtoViewBuilder;
|
||||
propertyBindings: Map<string, ASTWithSource>;
|
||||
@ -124,6 +117,7 @@ export class ElementBinderBuilder {
|
||||
textBindings: List<ASTWithSource>;
|
||||
contentTagSelector:string;
|
||||
propertySetters: Map<string, SetterFn>;
|
||||
readAttributes: Map<string, string>;
|
||||
componentId: string;
|
||||
|
||||
constructor(index, element, description) {
|
||||
@ -131,8 +125,6 @@ export class ElementBinderBuilder {
|
||||
this.index = index;
|
||||
this.parent = null;
|
||||
this.distanceToParent = 0;
|
||||
this.parentWithDirectives = null;
|
||||
this.distanceToParentWithDirectives = 0;
|
||||
this.directives = [];
|
||||
this.nestedProtoView = null;
|
||||
this.propertyBindings = MapWrapper.create();
|
||||
@ -143,25 +135,23 @@ export class ElementBinderBuilder {
|
||||
this.contentTagSelector = null;
|
||||
this.propertySetters = MapWrapper.create();
|
||||
this.componentId = null;
|
||||
this.readAttributes = MapWrapper.create();
|
||||
}
|
||||
|
||||
setParent(parent:ElementBinderBuilder, distanceToParent):ElementBinderBuilder {
|
||||
this.parent = parent;
|
||||
if (isPresent(parent)) {
|
||||
this.distanceToParent = distanceToParent;
|
||||
if (parent.directives.length > 0) {
|
||||
this.parentWithDirectives = parent;
|
||||
this.distanceToParentWithDirectives = distanceToParent;
|
||||
} else {
|
||||
this.parentWithDirectives = parent.parentWithDirectives;
|
||||
if (isPresent(this.parentWithDirectives)) {
|
||||
this.distanceToParentWithDirectives = distanceToParent + parent.distanceToParentWithDirectives;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
readAttribute(attrName:string) {
|
||||
if (isBlank(MapWrapper.get(this.readAttributes, attrName))) {
|
||||
MapWrapper.set(this.readAttributes, attrName, DOM.getAttribute(this.element, attrName));
|
||||
}
|
||||
}
|
||||
|
||||
bindDirective(directiveIndex:number):DirectiveBuilder {
|
||||
var directive = new DirectiveBuilder(directiveIndex);
|
||||
ListWrapper.push(this.directives, directive);
|
||||
@ -178,6 +168,11 @@ export class ElementBinderBuilder {
|
||||
|
||||
bindProperty(name, expression) {
|
||||
MapWrapper.set(this.propertyBindings, name, expression);
|
||||
this.bindPropertySetter(name);
|
||||
}
|
||||
|
||||
bindPropertySetter(name) {
|
||||
MapWrapper.set(this.propertySetters, name, setterFactory(name));
|
||||
}
|
||||
|
||||
bindVariable(name, value) {
|
||||
@ -209,10 +204,6 @@ export class ElementBinderBuilder {
|
||||
this.contentTagSelector = value;
|
||||
}
|
||||
|
||||
bindPropertySetter(propertyName, setter) {
|
||||
MapWrapper.set(this.propertySetters, propertyName, setter);
|
||||
}
|
||||
|
||||
setComponentId(componentId:string) {
|
||||
this.componentId = componentId;
|
||||
}
|
||||
@ -222,13 +213,11 @@ export class DirectiveBuilder {
|
||||
directiveIndex:number;
|
||||
propertyBindings: Map<string, ASTWithSource>;
|
||||
eventBindings: Map<string, ASTWithSource>;
|
||||
propertySetters: Map<string, SetterFn>;
|
||||
|
||||
constructor(directiveIndex) {
|
||||
this.directiveIndex = directiveIndex;
|
||||
this.propertyBindings = MapWrapper.create();
|
||||
this.eventBindings = MapWrapper.create();
|
||||
this.propertySetters = MapWrapper.create();
|
||||
}
|
||||
|
||||
bindProperty(name, expression) {
|
||||
@ -238,10 +227,6 @@ export class DirectiveBuilder {
|
||||
bindEvent(name, expression) {
|
||||
MapWrapper.set(this.eventBindings, name, expression);
|
||||
}
|
||||
|
||||
bindPropertySetter(propertyName, setter) {
|
||||
MapWrapper.set(this.propertySetters, propertyName, setter);
|
||||
}
|
||||
}
|
||||
|
||||
export class EventLocalsAstSplitter extends AstTransformer {
|
||||
@ -257,15 +242,19 @@ export class EventLocalsAstSplitter extends AstTransformer {
|
||||
}
|
||||
|
||||
splitEventAstIntoLocals(eventBindings:Map<string, ASTWithSource>):Map<string, ASTWithSource> {
|
||||
if (isPresent(eventBindings)) {
|
||||
var result = MapWrapper.create();
|
||||
MapWrapper.forEach(eventBindings, (astWithSource, eventName) => {
|
||||
MapWrapper.set(result, eventName, astWithSource.ast.visit(this));
|
||||
ListWrapper.push(this.eventNames, eventName);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
// TODO(tbosch): reenable this when we are using
|
||||
// the render views
|
||||
return eventBindings;
|
||||
// if (isPresent(eventBindings)) {
|
||||
// var result = MapWrapper.create();
|
||||
// MapWrapper.forEach(eventBindings, (astWithSource, eventName) => {
|
||||
// var adjustedAst = astWithSource.ast.visit(this);
|
||||
// MapWrapper.set(result, eventName, new ASTWithSource(adjustedAst, astWithSource.source, ''));
|
||||
// ListWrapper.push(this.eventNames, eventName);
|
||||
// });
|
||||
// return result;
|
||||
// }
|
||||
// return null;
|
||||
}
|
||||
|
||||
visitAccessMember(ast:AccessMember) {
|
||||
|
2
modules/angular2/src/render/dom/view/view.js
vendored
2
modules/angular2/src/render/dom/view/view.js
vendored
@ -52,7 +52,7 @@ export class View {
|
||||
}
|
||||
|
||||
setElementProperty(elementIndex:number, propertyName:string, value:any) {
|
||||
var setter = MapWrapper.get(this.proto.propertySetters, propertyName);
|
||||
var setter = MapWrapper.get(this.proto.elementBinders[elementIndex].propertySetters, propertyName);
|
||||
setter(this.boundElements[elementIndex], value);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user