@ -1,6 +1,6 @@
|
||||
import {isPresent, isBlank, Type, isArray, isNumber} from 'angular2/src/facade/lang';
|
||||
|
||||
import {RenderProtoViewRef} from 'angular2/src/core/render/api';
|
||||
import {RenderProtoViewRef, RenderComponentTemplate} from 'angular2/src/core/render/api';
|
||||
|
||||
import {Optional, Injectable, Provider, resolveForwardRef, Inject} from 'angular2/src/core/di';
|
||||
|
||||
@ -13,12 +13,12 @@ import {ProtoElementInjector, DirectiveProvider} from './element_injector';
|
||||
import {DirectiveResolver} from './directive_resolver';
|
||||
import {ViewResolver} from './view_resolver';
|
||||
import {PipeResolver} from './pipe_resolver';
|
||||
import {ViewMetadata} from '../metadata/view';
|
||||
import {ViewMetadata, ViewEncapsulation} from '../metadata/view';
|
||||
import {AMBIENT_PIPES} from 'angular2/src/core/ambient';
|
||||
|
||||
import {
|
||||
visitAllCommands,
|
||||
CompiledTemplate,
|
||||
CompiledComponentTemplate,
|
||||
CompiledHostTemplate,
|
||||
TemplateCmd,
|
||||
CommandVisitor,
|
||||
@ -36,7 +36,9 @@ import {APP_ID} from 'angular2/src/core/application_tokens';
|
||||
|
||||
@Injectable()
|
||||
export class ProtoViewFactory {
|
||||
private _cache: Map<number, AppProtoView> = new Map<number, AppProtoView>();
|
||||
private _cache: Map<string, AppProtoView> = new Map<string, AppProtoView>();
|
||||
private _nextTemplateId: number = 0;
|
||||
|
||||
constructor(private _renderer: Renderer,
|
||||
@Optional() @Inject(AMBIENT_PIPES) private _ambientPipes: Array<Type | any[]>,
|
||||
private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver,
|
||||
@ -45,13 +47,16 @@ export class ProtoViewFactory {
|
||||
clearCache() { this._cache.clear(); }
|
||||
|
||||
createHost(compiledHostTemplate: CompiledHostTemplate): AppProtoView {
|
||||
var compiledTemplate = compiledHostTemplate.getTemplate();
|
||||
var compiledTemplate = compiledHostTemplate.template;
|
||||
var result = this._cache.get(compiledTemplate.id);
|
||||
if (isBlank(result)) {
|
||||
var templateData = compiledTemplate.getData(this._appId);
|
||||
var emptyMap: {[key: string]: PipeProvider} = {};
|
||||
result = new AppProtoView(templateData.commands, ViewType.HOST, true,
|
||||
templateData.changeDetectorFactory, null, new ProtoPipes(emptyMap));
|
||||
var shortId = `${this._appId}-${this._nextTemplateId++}`;
|
||||
this._renderer.registerComponentTemplate(new RenderComponentTemplate(
|
||||
compiledTemplate.id, shortId, ViewEncapsulation.None, compiledTemplate.commands, []));
|
||||
result =
|
||||
new AppProtoView(compiledTemplate.id, compiledTemplate.commands, ViewType.HOST, true,
|
||||
compiledTemplate.changeDetectorFactory, null, new ProtoPipes(emptyMap));
|
||||
this._cache.set(compiledTemplate.id, result);
|
||||
}
|
||||
return result;
|
||||
@ -62,18 +67,19 @@ export class ProtoViewFactory {
|
||||
if (isBlank(nestedProtoView)) {
|
||||
var component = cmd.directives[0];
|
||||
var view = this._viewResolver.resolve(component);
|
||||
var compiledTemplateData = cmd.template.getData(this._appId);
|
||||
|
||||
this._renderer.registerComponentTemplate(cmd.templateId, compiledTemplateData.commands,
|
||||
compiledTemplateData.styles, cmd.nativeShadow);
|
||||
var compiledTemplate = cmd.templateGetter();
|
||||
var styles = _flattenStyleArr(compiledTemplate.styles, []);
|
||||
var shortId = `${this._appId}-${this._nextTemplateId++}`;
|
||||
this._renderer.registerComponentTemplate(new RenderComponentTemplate(
|
||||
compiledTemplate.id, shortId, cmd.encapsulation, compiledTemplate.commands, styles));
|
||||
var boundPipes = this._flattenPipes(view).map(pipe => this._bindPipe(pipe));
|
||||
|
||||
nestedProtoView = new AppProtoView(compiledTemplateData.commands, ViewType.COMPONENT, true,
|
||||
compiledTemplateData.changeDetectorFactory, null,
|
||||
ProtoPipes.fromProviders(boundPipes));
|
||||
nestedProtoView = new AppProtoView(
|
||||
compiledTemplate.id, compiledTemplate.commands, ViewType.COMPONENT, true,
|
||||
compiledTemplate.changeDetectorFactory, null, ProtoPipes.fromProviders(boundPipes));
|
||||
// Note: The cache is updated before recursing
|
||||
// to be able to resolve cycles
|
||||
this._cache.set(cmd.template.id, nestedProtoView);
|
||||
this._cache.set(compiledTemplate.id, nestedProtoView);
|
||||
this._initializeProtoView(nestedProtoView, null);
|
||||
}
|
||||
return nestedProtoView;
|
||||
@ -81,7 +87,7 @@ export class ProtoViewFactory {
|
||||
|
||||
private _createEmbeddedTemplate(cmd: EmbeddedTemplateCmd, parent: AppProtoView): AppProtoView {
|
||||
var nestedProtoView = new AppProtoView(
|
||||
cmd.children, ViewType.EMBEDDED, cmd.isMerged, cmd.changeDetectorFactory,
|
||||
parent.templateId, cmd.children, ViewType.EMBEDDED, cmd.isMerged, cmd.changeDetectorFactory,
|
||||
arrayToMap(cmd.variableNameAndValues, true), new ProtoPipes(parent.pipes.config));
|
||||
if (cmd.isMerged) {
|
||||
this.initializeProtoViewIfNeeded(nestedProtoView);
|
||||
@ -91,7 +97,7 @@ export class ProtoViewFactory {
|
||||
|
||||
initializeProtoViewIfNeeded(protoView: AppProtoView) {
|
||||
if (!protoView.isInitialized()) {
|
||||
var render = this._renderer.createProtoView(protoView.templateCmds);
|
||||
var render = this._renderer.createProtoView(protoView.templateId, protoView.templateCmds);
|
||||
this._initializeProtoView(protoView, render);
|
||||
}
|
||||
}
|
||||
@ -321,3 +327,15 @@ function _flattenArray(tree: any[], out: Array<Type | Provider | any[]>): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _flattenStyleArr(arr: Array<string | any[]>, out: string[]): string[] {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var entry = arr[i];
|
||||
if (isArray(entry)) {
|
||||
_flattenStyleArr(<any[]>entry, out);
|
||||
} else {
|
||||
out.push(<string>entry);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {Type, CONST_EXPR, CONST, isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {unimplemented} from 'angular2/src/facade/exceptions';
|
||||
import {
|
||||
RenderTemplateCmd,
|
||||
RenderCommandVisitor,
|
||||
@ -8,12 +9,10 @@ import {
|
||||
RenderBeginComponentCmd,
|
||||
RenderEmbeddedTemplateCmd
|
||||
} from 'angular2/src/core/render/render';
|
||||
|
||||
var _nextTemplateId: number = 0;
|
||||
|
||||
export function nextTemplateId(): number {
|
||||
return _nextTemplateId++;
|
||||
}
|
||||
import {ViewEncapsulation} from 'angular2/src/core/metadata';
|
||||
// Export ViewEncapsulation so that compiled templates only need to depend
|
||||
// on template_commands.
|
||||
export {ViewEncapsulation} from 'angular2/src/core/metadata';
|
||||
|
||||
/**
|
||||
* A compiled host template.
|
||||
@ -23,34 +22,16 @@ export function nextTemplateId(): number {
|
||||
*/
|
||||
@CONST()
|
||||
export class CompiledHostTemplate {
|
||||
// Note: _templateGetter is a function so that CompiledHostTemplate can be
|
||||
// a const!
|
||||
constructor(private _templateGetter: Function) {}
|
||||
|
||||
getTemplate(): CompiledTemplate { return this._templateGetter(); }
|
||||
constructor(public template: CompiledComponentTemplate) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* A compiled template.
|
||||
*/
|
||||
export class CompiledTemplate {
|
||||
// Note: paramGetter is a function so that we can have cycles between templates!
|
||||
// paramGetter returns a tuple with:
|
||||
// - ChangeDetector factory function
|
||||
// - TemplateCmd[]
|
||||
// - styles
|
||||
constructor(public id: number,
|
||||
private _dataGetter: /*()=>Array<Function, TemplateCmd[], string[]>*/ Function) {}
|
||||
|
||||
getData(appId: string): CompiledTemplateData {
|
||||
var data = this._dataGetter(appId, this.id);
|
||||
return new CompiledTemplateData(data[0], data[1], data[2]);
|
||||
}
|
||||
}
|
||||
|
||||
export class CompiledTemplateData {
|
||||
constructor(public changeDetectorFactory: Function, public commands: TemplateCmd[],
|
||||
public styles: string[]) {}
|
||||
@CONST()
|
||||
export class CompiledComponentTemplate {
|
||||
constructor(public id: string, public changeDetectorFactory: Function,
|
||||
public commands: TemplateCmd[], public styles: string[]) {}
|
||||
}
|
||||
|
||||
const EMPTY_ARR = CONST_EXPR([]);
|
||||
@ -59,6 +40,7 @@ export interface TemplateCmd extends RenderTemplateCmd {
|
||||
visit(visitor: RenderCommandVisitor, context: any): any;
|
||||
}
|
||||
|
||||
@CONST()
|
||||
export class TextCmd implements TemplateCmd, RenderTextCmd {
|
||||
constructor(public value: string, public isBound: boolean, public ngContentIndex: number) {}
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
@ -66,10 +48,7 @@ export class TextCmd implements TemplateCmd, RenderTextCmd {
|
||||
}
|
||||
}
|
||||
|
||||
export function text(value: string, isBound: boolean, ngContentIndex: number): TextCmd {
|
||||
return new TextCmd(value, isBound, ngContentIndex);
|
||||
}
|
||||
|
||||
@CONST()
|
||||
export class NgContentCmd implements TemplateCmd, RenderNgContentCmd {
|
||||
isBound: boolean = false;
|
||||
constructor(public index: number, public ngContentIndex: number) {}
|
||||
@ -78,17 +57,14 @@ export class NgContentCmd implements TemplateCmd, RenderNgContentCmd {
|
||||
}
|
||||
}
|
||||
|
||||
export function ngContent(index: number, ngContentIndex: number): NgContentCmd {
|
||||
return new NgContentCmd(index, ngContentIndex);
|
||||
}
|
||||
|
||||
export interface IBeginElementCmd extends TemplateCmd, RenderBeginElementCmd {
|
||||
variableNameAndValues: Array<string | number>;
|
||||
eventTargetAndNames: string[];
|
||||
directives: Type[];
|
||||
visit(visitor: RenderCommandVisitor, context: any): any;
|
||||
export abstract class IBeginElementCmd extends RenderBeginElementCmd implements TemplateCmd {
|
||||
get variableNameAndValues(): Array<string | number> { return unimplemented(); }
|
||||
get eventTargetAndNames(): string[] { return unimplemented(); }
|
||||
get directives(): Type[] { return unimplemented(); }
|
||||
abstract visit(visitor: RenderCommandVisitor, context: any): any;
|
||||
}
|
||||
|
||||
@CONST()
|
||||
export class BeginElementCmd implements TemplateCmd, IBeginElementCmd, RenderBeginElementCmd {
|
||||
constructor(public name: string, public attrNameAndValues: string[],
|
||||
public eventTargetAndNames: string[],
|
||||
@ -99,57 +75,40 @@ export class BeginElementCmd implements TemplateCmd, IBeginElementCmd, RenderBeg
|
||||
}
|
||||
}
|
||||
|
||||
export function beginElement(name: string, attrNameAndValues: string[],
|
||||
eventTargetAndNames: string[],
|
||||
variableNameAndValues: Array<string | number>, directives: Type[],
|
||||
isBound: boolean, ngContentIndex: number): BeginElementCmd {
|
||||
return new BeginElementCmd(name, attrNameAndValues, eventTargetAndNames, variableNameAndValues,
|
||||
directives, isBound, ngContentIndex);
|
||||
}
|
||||
|
||||
@CONST()
|
||||
export class EndElementCmd implements TemplateCmd {
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
return visitor.visitEndElement(context);
|
||||
}
|
||||
}
|
||||
|
||||
export function endElement(): TemplateCmd {
|
||||
return new EndElementCmd();
|
||||
}
|
||||
|
||||
@CONST()
|
||||
export class BeginComponentCmd implements TemplateCmd, IBeginElementCmd, RenderBeginComponentCmd {
|
||||
isBound: boolean = true;
|
||||
templateId: number;
|
||||
constructor(public name: string, public attrNameAndValues: string[],
|
||||
public eventTargetAndNames: string[],
|
||||
public variableNameAndValues: Array<string | number>, public directives: Type[],
|
||||
public nativeShadow: boolean, public ngContentIndex: number,
|
||||
public template: CompiledTemplate) {
|
||||
this.templateId = template.id;
|
||||
}
|
||||
public encapsulation: ViewEncapsulation, public ngContentIndex: number,
|
||||
// Note: the template needs to be stored as a function
|
||||
// so that we can resolve cycles
|
||||
public templateGetter: Function /*() => CompiledComponentTemplate*/) {}
|
||||
|
||||
get templateId(): string { return this.templateGetter().id; }
|
||||
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
return visitor.visitBeginComponent(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export function beginComponent(
|
||||
name: string, attrNameAnsValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: Array<string | number>, directives: Type[], nativeShadow: boolean,
|
||||
ngContentIndex: number, template: CompiledTemplate): BeginComponentCmd {
|
||||
return new BeginComponentCmd(name, attrNameAnsValues, eventTargetAndNames, variableNameAndValues,
|
||||
directives, nativeShadow, ngContentIndex, template);
|
||||
}
|
||||
|
||||
@CONST()
|
||||
export class EndComponentCmd implements TemplateCmd {
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
return visitor.visitEndComponent(context);
|
||||
}
|
||||
}
|
||||
|
||||
export function endComponent(): TemplateCmd {
|
||||
return new EndComponentCmd();
|
||||
}
|
||||
|
||||
@CONST()
|
||||
export class EmbeddedTemplateCmd implements TemplateCmd, IBeginElementCmd,
|
||||
RenderEmbeddedTemplateCmd {
|
||||
isBound: boolean = true;
|
||||
@ -163,13 +122,6 @@ export class EmbeddedTemplateCmd implements TemplateCmd, IBeginElementCmd,
|
||||
}
|
||||
}
|
||||
|
||||
export function embeddedTemplate(attrNameAndValues: string[], variableNameAndValues: string[],
|
||||
directives: Type[], isMerged: boolean, ngContentIndex: number,
|
||||
changeDetectorFactory: Function,
|
||||
children: TemplateCmd[]): EmbeddedTemplateCmd {
|
||||
return new EmbeddedTemplateCmd(attrNameAndValues, variableNameAndValues, directives, isMerged,
|
||||
ngContentIndex, changeDetectorFactory, children);
|
||||
}
|
||||
|
||||
export interface CommandVisitor extends RenderCommandVisitor {
|
||||
visitText(cmd: TextCmd, context: any): any;
|
||||
|
@ -318,8 +318,8 @@ export class AppProtoView {
|
||||
textBindingCount = null;
|
||||
render: renderApi.RenderProtoViewRef = null;
|
||||
|
||||
constructor(public templateCmds: TemplateCmd[], public type: ViewType, public isMergable: boolean,
|
||||
public changeDetectorFactory: Function,
|
||||
constructor(public templateId: string, public templateCmds: TemplateCmd[], public type: ViewType,
|
||||
public isMergable: boolean, public changeDetectorFactory: Function,
|
||||
public templateVariableBindings: Map<string, string>, public pipes: ProtoPipes) {
|
||||
this.ref = new ProtoViewRef_(this);
|
||||
}
|
||||
|
Reference in New Issue
Block a user