refactor(compiler): make all commands const

Closes #5135
This commit is contained in:
Tobias Bosch
2015-11-02 08:39:14 -08:00
parent fb8b8157ff
commit e667ad3e6b
35 changed files with 1002 additions and 868 deletions

View File

@ -63,7 +63,7 @@ export class ChangeDetectionCompiler {
var index = 0;
var sourceParts = changeDetectorDefinitions.map(definition => {
var codegen: any;
var sourcePart;
var sourcePart: string;
// TODO(tbosch): move the 2 code generators to the same place, one with .dart and one with .ts
// suffix
// and have the same API for calling them!
@ -74,7 +74,7 @@ export class ChangeDetectionCompiler {
'dynamic' :
`${moduleRef(componentType.moduleUrl)}${componentType.name}`;
codegen.generate(typeRef, className, definition);
factories.push(`(dispatcher) => new ${className}(dispatcher)`);
factories.push(`${className}.newChangeDetector`);
sourcePart = codegen.toString();
} else {
codegen = new ChangeDetectorJITGenerator(

View File

@ -1,15 +1,15 @@
import {isPresent, isBlank, Type, isString, StringWrapper} from 'angular2/src/facade/lang';
import {isPresent, isBlank, Type, isString, StringWrapper, IS_DART} from 'angular2/src/facade/lang';
import {SetWrapper, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {
TemplateCmd,
text,
ngContent,
beginElement,
endElement,
beginComponent,
endComponent,
embeddedTemplate,
CompiledTemplate
TextCmd,
NgContentCmd,
BeginElementCmd,
EndElementCmd,
BeginComponentCmd,
EndComponentCmd,
EmbeddedTemplateCmd,
CompiledComponentTemplate
} from 'angular2/src/core/linker/template_commands';
import {
TemplateAst,
@ -32,12 +32,11 @@ import {SourceExpressions, SourceExpression, moduleRef} from './source_module';
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
import {
shimHostAttribute,
shimContentAttribute,
shimContentAttributeExpr,
shimHostAttributeExpr
} from './style_compiler';
import {escapeSingleQuoteString, MODULE_SUFFIX} from './util';
escapeSingleQuoteString,
codeGenConstConstructorCall,
codeGenValueFn,
MODULE_SUFFIX
} from './util';
import {Injectable} from 'angular2/src/core/di';
export var TEMPLATE_COMMANDS_MODULE_REF =
@ -49,28 +48,24 @@ const STYLE_ATTR = 'style';
@Injectable()
export class CommandCompiler {
compileComponentRuntime(component: CompileDirectiveMetadata, appId: string, templateId: number,
template: TemplateAst[], changeDetectorFactories: Function[],
compileComponentRuntime(component: CompileDirectiveMetadata, template: TemplateAst[],
changeDetectorFactories: Function[],
componentTemplateFactory: Function): TemplateCmd[] {
var visitor = new CommandBuilderVisitor(
new RuntimeCommandFactory(component, appId, templateId, componentTemplateFactory,
changeDetectorFactories),
0);
new RuntimeCommandFactory(component, componentTemplateFactory, changeDetectorFactories), 0);
templateVisitAll(visitor, template);
return visitor.result;
}
compileComponentCodeGen(component: CompileDirectiveMetadata, appIdExpr: string,
templateIdExpr: string, template: TemplateAst[],
compileComponentCodeGen(component: CompileDirectiveMetadata, template: TemplateAst[],
changeDetectorFactoryExpressions: string[],
componentTemplateFactory: Function): SourceExpression {
var visitor = new CommandBuilderVisitor(
new CodegenCommandFactory(component, appIdExpr, templateIdExpr, componentTemplateFactory,
changeDetectorFactoryExpressions),
0);
var visitor =
new CommandBuilderVisitor(new CodegenCommandFactory(component, componentTemplateFactory,
changeDetectorFactoryExpressions),
0);
templateVisitAll(visitor, template);
var source = `[${visitor.result.join(',')}]`;
return new SourceExpression([], source);
return new SourceExpression([], codeGenArray(visitor.result));
}
}
@ -83,7 +78,7 @@ interface CommandFactory<R> {
createEndElement(): R;
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
nativeShadow: boolean, ngContentIndex: number): R;
encapsulation: ViewEncapsulation, ngContentIndex: number): R;
createEndComponent(): R;
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
@ -91,112 +86,89 @@ interface CommandFactory<R> {
}
class RuntimeCommandFactory implements CommandFactory<TemplateCmd> {
constructor(private component: CompileDirectiveMetadata, private appId: string,
private templateId: number, private componentTemplateFactory: Function,
constructor(private component: CompileDirectiveMetadata,
private componentTemplateFactory: Function,
private changeDetectorFactories: Function[]) {}
private _mapDirectives(directives: CompileDirectiveMetadata[]): Type[] {
return directives.map(directive => directive.type.runtime);
}
private _addStyleShimAttributes(attrNameAndValues: string[],
localComponent: CompileDirectiveMetadata,
localTemplateId: number): string[] {
var additionalStyles = [];
if (isPresent(localComponent) &&
localComponent.template.encapsulation === ViewEncapsulation.Emulated) {
additionalStyles.push(shimHostAttribute(this.appId, localTemplateId));
additionalStyles.push('');
}
if (this.component.template.encapsulation === ViewEncapsulation.Emulated) {
additionalStyles.push(shimContentAttribute(this.appId, this.templateId));
additionalStyles.push('');
}
return additionalStyles.concat(attrNameAndValues);
}
createText(value: string, isBound: boolean, ngContentIndex: number): TemplateCmd {
return text(value, isBound, ngContentIndex);
return new TextCmd(value, isBound, ngContentIndex);
}
createNgContent(index: number, ngContentIndex: number): TemplateCmd {
return ngContent(index, ngContentIndex);
return new NgContentCmd(index, ngContentIndex);
}
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
isBound: boolean, ngContentIndex: number): TemplateCmd {
return beginElement(name, this._addStyleShimAttributes(attrNameAndValues, null, null),
eventTargetAndNames, variableNameAndValues, this._mapDirectives(directives),
isBound, ngContentIndex);
return new BeginElementCmd(name, attrNameAndValues, eventTargetAndNames, variableNameAndValues,
this._mapDirectives(directives), isBound, ngContentIndex);
}
createEndElement(): TemplateCmd { return endElement(); }
createEndElement(): TemplateCmd { return new EndElementCmd(); }
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
nativeShadow: boolean, ngContentIndex: number): TemplateCmd {
var nestedTemplate = this.componentTemplateFactory(directives[0]);
return beginComponent(
name, this._addStyleShimAttributes(attrNameAndValues, directives[0], nestedTemplate.id),
eventTargetAndNames, variableNameAndValues, this._mapDirectives(directives), nativeShadow,
ngContentIndex, nestedTemplate);
encapsulation: ViewEncapsulation, ngContentIndex: number): TemplateCmd {
var nestedTemplateAccessor = this.componentTemplateFactory(directives[0]);
return new BeginComponentCmd(name, attrNameAndValues, eventTargetAndNames,
variableNameAndValues, this._mapDirectives(directives),
encapsulation, ngContentIndex, nestedTemplateAccessor);
}
createEndComponent(): TemplateCmd { return endComponent(); }
createEndComponent(): TemplateCmd { return new EndComponentCmd(); }
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
isMerged: boolean, ngContentIndex: number,
children: TemplateCmd[]): TemplateCmd {
return embeddedTemplate(attrNameAndValues, variableNameAndValues,
this._mapDirectives(directives), isMerged, ngContentIndex,
this.changeDetectorFactories[embeddedTemplateIndex], children);
return new EmbeddedTemplateCmd(attrNameAndValues, variableNameAndValues,
this._mapDirectives(directives), isMerged, ngContentIndex,
this.changeDetectorFactories[embeddedTemplateIndex], children);
}
}
class CodegenCommandFactory implements CommandFactory<string> {
constructor(private component: CompileDirectiveMetadata, private appIdExpr: string,
private templateIdExpr: string, private componentTemplateFactory: Function,
class CodegenCommandFactory implements CommandFactory<Expression> {
constructor(private component: CompileDirectiveMetadata,
private componentTemplateFactory: Function,
private changeDetectorFactoryExpressions: string[]) {}
private _addStyleShimAttributes(attrNameAndValues: string[],
localComponent: CompileDirectiveMetadata,
localTemplateIdExpr: string): any[] {
var additionalStlyes = [];
if (isPresent(localComponent) &&
localComponent.template.encapsulation === ViewEncapsulation.Emulated) {
additionalStlyes.push(
new Expression(shimHostAttributeExpr(this.appIdExpr, localTemplateIdExpr)));
additionalStlyes.push('');
}
if (this.component.template.encapsulation === ViewEncapsulation.Emulated) {
additionalStlyes.push(
new Expression(shimContentAttributeExpr(this.appIdExpr, this.templateIdExpr)));
additionalStlyes.push('');
}
return additionalStlyes.concat(attrNameAndValues);
createText(value: string, isBound: boolean, ngContentIndex: number): Expression {
return new Expression(
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'TextCmd')}(${escapeSingleQuoteString(value)}, ${isBound}, ${ngContentIndex})`);
}
createText(value: string, isBound: boolean, ngContentIndex: number): string {
return `${TEMPLATE_COMMANDS_MODULE_REF}text(${escapeSingleQuoteString(value)}, ${isBound}, ${ngContentIndex})`;
}
createNgContent(index: number, ngContentIndex: number): string {
return `${TEMPLATE_COMMANDS_MODULE_REF}ngContent(${index}, ${ngContentIndex})`;
createNgContent(index: number, ngContentIndex: number): Expression {
return new Expression(
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'NgContentCmd')}(${index}, ${ngContentIndex})`);
}
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
isBound: boolean, ngContentIndex: number): string {
var attrsExpression = codeGenArray(this._addStyleShimAttributes(attrNameAndValues, null, null));
return `${TEMPLATE_COMMANDS_MODULE_REF}beginElement(${escapeSingleQuoteString(name)}, ${attrsExpression}, ${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${isBound}, ${ngContentIndex})`;
isBound: boolean, ngContentIndex: number): Expression {
var attrsExpression = codeGenArray(attrNameAndValues);
return new Expression(
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'BeginElementCmd')}(${escapeSingleQuoteString(name)}, ${attrsExpression}, ` +
`${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${isBound}, ${ngContentIndex})`);
}
createEndElement(): Expression {
return new Expression(
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'EndElementCmd')}()`);
}
createEndElement(): string { return `${TEMPLATE_COMMANDS_MODULE_REF}endElement()`; }
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
nativeShadow: boolean, ngContentIndex: number): string {
var nestedCompExpr = this.componentTemplateFactory(directives[0]);
var attrsExpression = codeGenArray(
this._addStyleShimAttributes(attrNameAndValues, directives[0], `${nestedCompExpr}.id`));
return `${TEMPLATE_COMMANDS_MODULE_REF}beginComponent(${escapeSingleQuoteString(name)}, ${attrsExpression}, ${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${nativeShadow}, ${ngContentIndex}, ${nestedCompExpr})`;
encapsulation: ViewEncapsulation, ngContentIndex: number): Expression {
var attrsExpression = codeGenArray(attrNameAndValues);
return new Expression(
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'BeginComponentCmd')}(${escapeSingleQuoteString(name)}, ${attrsExpression}, ` +
`${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${codeGenViewEncapsulation(encapsulation)}, ${ngContentIndex}, ${this.componentTemplateFactory(directives[0])})`);
}
createEndComponent(): Expression {
return new Expression(
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'EndComponentCmd')}()`);
}
createEndComponent(): string { return `${TEMPLATE_COMMANDS_MODULE_REF}endComponent()`; }
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
isMerged: boolean, ngContentIndex: number, children: string[]): string {
return `${TEMPLATE_COMMANDS_MODULE_REF}embeddedTemplate(${codeGenArray(attrNameAndValues)}, ${codeGenArray(variableNameAndValues)}, ` +
`${codeGenDirectivesArray(directives)}, ${isMerged}, ${ngContentIndex}, ${this.changeDetectorFactoryExpressions[embeddedTemplateIndex]}, [${children.join(',')}])`;
isMerged: boolean, ngContentIndex: number,
children: Expression[]): Expression {
return new Expression(
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'EmbeddedTemplateCmd')}(${codeGenArray(attrNameAndValues)}, ${codeGenArray(variableNameAndValues)}, ` +
`${codeGenDirectivesArray(directives)}, ${isMerged}, ${ngContentIndex}, ${this.changeDetectorFactoryExpressions[embeddedTemplateIndex]}, ${codeGenArray(children)})`);
}
}
@ -270,7 +242,7 @@ class CommandBuilderVisitor<R> implements TemplateAstVisitor {
if (isPresent(component)) {
this.result.push(this.commandFactory.createBeginComponent(
ast.name, attrNameAndValues, eventTargetAndNames, variableNameAndValues, directives,
component.template.encapsulation === ViewEncapsulation.Native, ast.ngContentIndex));
component.template.encapsulation, ast.ngContentIndex));
templateVisitAll(this, ast.children);
this.result.push(this.commandFactory.createEndComponent());
} else {
@ -383,11 +355,21 @@ function escapeValue(value: any): string {
}
function codeGenArray(data: any[]): string {
return `[${data.map(escapeValue).join(',')}]`;
var base = `[${data.map(escapeValue).join(',')}]`;
return IS_DART ? `const ${base}` : base;
}
function codeGenDirectivesArray(directives: CompileDirectiveMetadata[]): string {
var expressions = directives.map(
directiveType => `${moduleRef(directiveType.type.moduleUrl)}${directiveType.type.name}`);
return `[${expressions.join(',')}]`;
var base = `[${expressions.join(',')}]`;
return IS_DART ? `const ${base}` : base;
}
function codeGenViewEncapsulation(value: ViewEncapsulation): string {
if (IS_DART) {
return `${TEMPLATE_COMMANDS_MODULE_REF}${value}`;
} else {
return `${value}`;
}
}

View File

@ -9,21 +9,12 @@ import {UrlResolver} from 'angular2/src/compiler/url_resolver';
import {extractStyleUrls} from './style_url_resolver';
import {
escapeSingleQuoteString,
codeGenConcatArray,
codeGenMapArray,
codeGenReplaceAll,
codeGenExportVariable,
codeGenToString,
MODULE_SUFFIX
} from './util';
import {Injectable} from 'angular2/src/core/di';
const COMPONENT_VARIABLE = '%COMP%';
var COMPONENT_REGEX = /%COMP%/g;
const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
const HOST_ATTR_EXPR = `'_nghost-'+${COMPONENT_VARIABLE}`;
const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
const CONTENT_ATTR_EXPR = `'_ngcontent-'+${COMPONENT_VARIABLE}`;
import {COMPONENT_VARIABLE, HOST_ATTR, CONTENT_ATTR} from 'angular2/src/core/render/view_factory';
@Injectable()
export class StyleCompiler {
@ -32,28 +23,16 @@ export class StyleCompiler {
constructor(private _xhr: XHR, private _urlResolver: UrlResolver) {}
compileComponentRuntime(appId: string, templateId: number,
template: CompileTemplateMetadata): Promise<string[]> {
compileComponentRuntime(template: CompileTemplateMetadata): Promise<Array<string | any[]>> {
var styles = template.styles;
var styleAbsUrls = template.styleUrls;
return this._loadStyles(styles, styleAbsUrls,
template.encapsulation === ViewEncapsulation.Emulated)
.then(styles => styles.map(style => StringWrapper.replaceAll(
style, COMPONENT_REGEX, componentId(appId, templateId))));
template.encapsulation === ViewEncapsulation.Emulated);
}
compileComponentCodeGen(appIdExpression: string, templateIdExpression: string,
template: CompileTemplateMetadata): SourceExpression {
compileComponentCodeGen(template: CompileTemplateMetadata): SourceExpression {
var shim = template.encapsulation === ViewEncapsulation.Emulated;
var suffix;
if (shim) {
suffix = codeGenMapArray(
['style'],
`style${codeGenReplaceAll(COMPONENT_VARIABLE, componentIdExpression(appIdExpression, templateIdExpression))}`);
} else {
suffix = '';
}
return this._styleCodeGen(template.styles, template.styleUrls, shim, suffix);
return this._styleCodeGen(template.styles, template.styleUrls, shim);
}
compileStylesheetCodeGen(stylesheetUrl: string, cssText: string): SourceModule[] {
@ -61,17 +40,16 @@ export class StyleCompiler {
return [
this._styleModule(
stylesheetUrl, false,
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, false, '')),
this._styleModule(
stylesheetUrl, true,
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, true, ''))
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, false)),
this._styleModule(stylesheetUrl, true, this._styleCodeGen([styleWithImports.style],
styleWithImports.styleUrls, true))
];
}
clearCache() { this._styleCache.clear(); }
private _loadStyles(plainStyles: string[], absUrls: string[],
encapsulate: boolean): Promise<string[]> {
encapsulate: boolean): Promise<Array<string | any[]>> {
var promises = absUrls.map((absUrl) => {
var cacheKey = `${absUrl}${encapsulate ? '.shim' : ''}`;
var result = this._styleCache.get(cacheKey);
@ -86,22 +64,23 @@ export class StyleCompiler {
return result;
});
return PromiseWrapper.all(promises).then((nestedStyles: string[][]) => {
var result = plainStyles.map(plainStyle => this._shimIfNeeded(plainStyle, encapsulate));
nestedStyles.forEach(styles => styles.forEach(style => result.push(style)));
var result: Array<string | any[]> =
plainStyles.map(plainStyle => this._shimIfNeeded(plainStyle, encapsulate));
nestedStyles.forEach(styles => result.push(styles));
return result;
});
}
private _styleCodeGen(plainStyles: string[], absUrls: string[], shim: boolean,
suffix: string): SourceExpression {
var expressionSource = `(`;
expressionSource +=
`[${plainStyles.map( plainStyle => escapeSingleQuoteString(this._shimIfNeeded(plainStyle, shim)) ).join(',')}]`;
private _styleCodeGen(plainStyles: string[], absUrls: string[], shim: boolean): SourceExpression {
var arrayPrefix = IS_DART ? `const` : '';
var styleExpressions = plainStyles.map(
plainStyle => escapeSingleQuoteString(this._shimIfNeeded(plainStyle, shim)));
for (var i = 0; i < absUrls.length; i++) {
var moduleUrl = this._createModuleUrl(absUrls[i], shim);
expressionSource += codeGenConcatArray(`${moduleRef(moduleUrl)}STYLES`);
styleExpressions.push(`${moduleRef(moduleUrl)}STYLES`);
}
expressionSource += `)${suffix}`;
var expressionSource = `${arrayPrefix} [${styleExpressions.join(',')}]`;
return new SourceExpression([], expressionSource);
}
@ -122,29 +101,3 @@ export class StyleCompiler {
return shim ? `${stylesheetUrl}.shim${MODULE_SUFFIX}` : `${stylesheetUrl}${MODULE_SUFFIX}`;
}
}
export function shimContentAttribute(appId: string, templateId: number): string {
return StringWrapper.replaceAll(CONTENT_ATTR, COMPONENT_REGEX, componentId(appId, templateId));
}
export function shimContentAttributeExpr(appIdExpr: string, templateIdExpr: string): string {
return StringWrapper.replaceAll(CONTENT_ATTR_EXPR, COMPONENT_REGEX,
componentIdExpression(appIdExpr, templateIdExpr));
}
export function shimHostAttribute(appId: string, templateId: number): string {
return StringWrapper.replaceAll(HOST_ATTR, COMPONENT_REGEX, componentId(appId, templateId));
}
export function shimHostAttributeExpr(appIdExpr: string, templateIdExpr: string): string {
return StringWrapper.replaceAll(HOST_ATTR_EXPR, COMPONENT_REGEX,
componentIdExpression(appIdExpr, templateIdExpr));
}
function componentId(appId: string, templateId: number): string {
return `${appId}-${templateId}`;
}
function componentIdExpression(appIdExpression: string, templateIdExpression: string): string {
return `${appIdExpression}+'-'+${codeGenToString(templateIdExpression)}`;
}

View File

@ -3,10 +3,10 @@ import {BaseException} from 'angular2/src/facade/exceptions';
import {ListWrapper, SetWrapper} from 'angular2/src/facade/collection';
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
import {
CompiledTemplate,
CompiledComponentTemplate,
TemplateCmd,
nextTemplateId,
CompiledHostTemplate
CompiledHostTemplate,
BeginComponentCmd
} from 'angular2/src/core/linker/template_commands';
import {
createHostComponentMeta,
@ -23,7 +23,6 @@ import {CommandCompiler} from './command_compiler';
import {TemplateParser} from './template_parser';
import {TemplateNormalizer} from './template_normalizer';
import {RuntimeMetadataResolver} from './runtime_metadata';
import {APP_ID} from 'angular2/src/core/application_tokens';
import {TEMPLATE_COMMANDS_MODULE_REF} from './command_compiler';
import {
@ -32,22 +31,19 @@ import {
codeGenValueFn,
MODULE_SUFFIX
} from './util';
import {Inject} from 'angular2/src/core/di';
@Injectable()
export class TemplateCompiler {
private _hostCacheKeys = new Map<Type, any>();
private _compiledTemplateCache = new Map<any, CompiledTemplate>();
private _compiledTemplateDone = new Map<any, Promise<CompiledTemplate>>();
private _appId: string;
private _compiledTemplateCache = new Map<any, CompiledComponentTemplate>();
private _compiledTemplateDone = new Map<any, Promise<CompiledComponentTemplate>>();
private _nextTemplateId: number = 0;
constructor(private _runtimeMetadataResolver: RuntimeMetadataResolver,
private _templateNormalizer: TemplateNormalizer,
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
private _commandCompiler: CommandCompiler,
private _cdCompiler: ChangeDetectionCompiler, @Inject(APP_ID) appId: string) {
this._appId = appId;
}
private _cdCompiler: ChangeDetectionCompiler) {}
normalizeDirectiveMetadata(directive: CompileDirectiveMetadata):
Promise<CompileDirectiveMetadata> {
@ -87,7 +83,7 @@ export class TemplateCompiler {
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], new Set());
}
return this._compiledTemplateDone.get(hostCacheKey)
.then(compiledTemplate => new CompiledHostTemplate(() => compiledTemplate));
.then(compiledTemplate => new CompiledHostTemplate(compiledTemplate));
}
clearCache() {
@ -97,57 +93,55 @@ export class TemplateCompiler {
this._compiledTemplateDone.clear();
}
private _compileComponentRuntime(cacheKey: any, compMeta: CompileDirectiveMetadata,
viewDirectives: CompileDirectiveMetadata[],
compilingComponentCacheKeys: Set<any>): CompiledTemplate {
private _compileComponentRuntime(
cacheKey: any, compMeta: CompileDirectiveMetadata, viewDirectives: CompileDirectiveMetadata[],
compilingComponentCacheKeys: Set<any>): CompiledComponentTemplate {
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
var done = this._compiledTemplateDone.get(cacheKey);
if (isBlank(compiledTemplate)) {
var styles;
var styles = [];
var changeDetectorFactory;
var commands;
var templateId = nextTemplateId();
compiledTemplate =
new CompiledTemplate(templateId, (_a, _b) => [changeDetectorFactory, commands, styles]);
var commands = [];
var templateId = `${stringify(compMeta.type.runtime)}Template${this._nextTemplateId++}`;
compiledTemplate = new CompiledComponentTemplate(
templateId, (dispatcher) => changeDetectorFactory(dispatcher), commands, styles);
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
compilingComponentCacheKeys.add(cacheKey);
done =
PromiseWrapper.all([
<any>this._styleCompiler.compileComponentRuntime(this._appId, templateId,
compMeta.template)
].concat(viewDirectives.map(dirMeta =>
this.normalizeDirectiveMetadata(dirMeta))))
.then((stylesAndNormalizedViewDirMetas: any[]) => {
var childPromises = [];
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
var parsedTemplate = this._templateParser.parse(
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);
done = PromiseWrapper
.all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat(
viewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
.then((stylesAndNormalizedViewDirMetas: any[]) => {
var childPromises = [];
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
var parsedTemplate = this._templateParser.parse(
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);
var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
compMeta.type, compMeta.changeDetection, parsedTemplate);
changeDetectorFactory = changeDetectorFactories[0];
styles = stylesAndNormalizedViewDirMetas[0];
commands = this._compileCommandsRuntime(compMeta, templateId, parsedTemplate,
changeDetectorFactories,
compilingComponentCacheKeys, childPromises);
return PromiseWrapper.all(childPromises);
})
.then((_) => {
SetWrapper.delete(compilingComponentCacheKeys, cacheKey);
return compiledTemplate;
});
var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
compMeta.type, compMeta.changeDetection, parsedTemplate);
changeDetectorFactory = changeDetectorFactories[0];
var tmpStyles: string[] = stylesAndNormalizedViewDirMetas[0];
tmpStyles.forEach(style => styles.push(style));
var tmpCommands: TemplateCmd[] = this._compileCommandsRuntime(
compMeta, parsedTemplate, changeDetectorFactories,
compilingComponentCacheKeys, childPromises);
tmpCommands.forEach(cmd => commands.push(cmd));
return PromiseWrapper.all(childPromises);
})
.then((_) => {
SetWrapper.delete(compilingComponentCacheKeys, cacheKey);
return compiledTemplate;
});
this._compiledTemplateDone.set(cacheKey, done);
}
return compiledTemplate;
}
private _compileCommandsRuntime(compMeta: CompileDirectiveMetadata, templateId: number,
parsedTemplate: TemplateAst[],
private _compileCommandsRuntime(compMeta: CompileDirectiveMetadata, parsedTemplate: TemplateAst[],
changeDetectorFactories: Function[],
compilingComponentCacheKeys: Set<Type>,
childPromises: Promise<any>[]): TemplateCmd[] {
return this._commandCompiler.compileComponentRuntime(
compMeta, this._appId, templateId, parsedTemplate, changeDetectorFactories,
var cmds: TemplateCmd[] = this._commandCompiler.compileComponentRuntime(
compMeta, parsedTemplate, changeDetectorFactories,
(childComponentDir: CompileDirectiveMetadata) => {
var childCacheKey = childComponentDir.type.runtime;
var childViewDirectives: CompileDirectiveMetadata[] =
@ -160,8 +154,14 @@ export class TemplateCompiler {
// Only wait for a child if it is not a cycle
childPromises.push(this._compiledTemplateDone.get(childCacheKey));
}
return childTemplate;
return () => childTemplate;
});
cmds.forEach(cmd => {
if (cmd instanceof BeginComponentCmd) {
cmd.templateGetter();
}
});
return cmds;
}
compileTemplatesCodeGen(components: NormalizedComponentWithViewDirectives[]): SourceModule {
@ -171,40 +171,35 @@ export class TemplateCompiler {
var declarations = [];
var templateArguments = [];
var componentMetas: CompileDirectiveMetadata[] = [];
var templateIdVariable = 'templateId';
var appIdVariable = 'appId';
components.forEach(componentWithDirs => {
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
assertComponent(compMeta);
componentMetas.push(compMeta);
this._processTemplateCodeGen(compMeta, appIdVariable, templateIdVariable,
this._processTemplateCodeGen(compMeta,
<CompileDirectiveMetadata[]>componentWithDirs.directives,
declarations, templateArguments);
if (compMeta.dynamicLoadable) {
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
componentMetas.push(hostMeta);
this._processTemplateCodeGen(hostMeta, appIdVariable, templateIdVariable, [compMeta],
declarations, templateArguments);
this._processTemplateCodeGen(hostMeta, [compMeta], declarations, templateArguments);
}
});
ListWrapper.forEachWithIndex(componentMetas, (compMeta: CompileDirectiveMetadata,
index: number) => {
var templateDataFn = codeGenValueFn([appIdVariable, templateIdVariable],
`[${(<any[]>templateArguments[index]).join(',')}]`);
var templateId = `${compMeta.type.moduleUrl}|${compMeta.type.name}`;
var constructionKeyword = IS_DART ? 'const' : 'new';
var compiledTemplateExpr =
`new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${TEMPLATE_COMMANDS_MODULE_REF}nextTemplateId(),${templateDataFn})`;
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledComponentTemplate('${templateId}',${(<any[]>templateArguments[index]).join(',')})`;
var variableValueExpr;
if (compMeta.type.isHost) {
var factoryName = `_hostTemplateFactory${index}`;
declarations.push(`${codeGenValueFn([], compiledTemplateExpr, factoryName)};`);
var constructionKeyword = IS_DART ? 'const' : 'new';
variableValueExpr =
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${factoryName})`;
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${compiledTemplateExpr})`;
} else {
variableValueExpr = compiledTemplateExpr;
}
declarations.push(
`${codeGenExportVariable(templateVariableName(compMeta.type), compMeta.type.isHost)}${variableValueExpr};`);
var varName = templateVariableName(compMeta.type);
declarations.push(`${codeGenExportVariable(varName)}${variableValueExpr};`);
declarations.push(`${codeGenValueFn([], varName, templateGetterName(compMeta.type))};`);
});
var moduleUrl = components[0].component.type.moduleUrl;
return new SourceModule(`${templateModuleUrl(moduleUrl)}`, declarations.join('\n'));
@ -214,17 +209,16 @@ export class TemplateCompiler {
return this._styleCompiler.compileStylesheetCodeGen(stylesheetUrl, cssText);
}
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata, appIdExpr: string,
templateIdExpr: string, directives: CompileDirectiveMetadata[],
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata,
directives: CompileDirectiveMetadata[],
targetDeclarations: string[], targetTemplateArguments: any[][]) {
var styleExpr =
this._styleCompiler.compileComponentCodeGen(appIdExpr, templateIdExpr, compMeta.template);
var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta.template);
var parsedTemplate =
this._templateParser.parse(compMeta.template.template, directives, compMeta.type.name);
var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen(
compMeta.type, compMeta.changeDetection, parsedTemplate);
var commandsExpr = this._commandCompiler.compileComponentCodeGen(
compMeta, appIdExpr, templateIdExpr, parsedTemplate, changeDetectorsExprs.expressions,
compMeta, parsedTemplate, changeDetectorsExprs.expressions,
codeGenComponentTemplateFactory);
addAll(styleExpr.declarations, targetDeclarations);
@ -251,6 +245,10 @@ function templateVariableName(type: CompileTypeMetadata): string {
return `${type.name}Template`;
}
function templateGetterName(type: CompileTypeMetadata): string {
return `${templateVariableName(type)}Getter`;
}
function templateModuleUrl(moduleUrl: string): string {
var urlWithoutSuffix = moduleUrl.substring(0, moduleUrl.length - MODULE_SUFFIX.length);
return `${urlWithoutSuffix}.template${MODULE_SUFFIX}`;
@ -263,5 +261,5 @@ function addAll(source: any[], target: any[]) {
}
function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string {
return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateVariableName(nestedCompType.type)}`;
return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateGetterName(nestedCompType.type)}`;
}

View File

@ -43,31 +43,19 @@ function escapeString(input: string, re: RegExp): string {
});
}
export function codeGenExportVariable(name: string, isConst: boolean = false): string {
export function codeGenExportVariable(name: string): string {
if (IS_DART) {
return isConst ? `const ${name} = ` : `final ${name} = `;
return `const ${name} = `;
} else {
return `var ${name} = exports['${name}'] = `;
}
}
export function codeGenConcatArray(expression: string): string {
return `${IS_DART ? '..addAll' : '.concat'}(${expression})`;
}
export function codeGenMapArray(argNames: string[], callback: string): string {
export function codeGenConstConstructorCall(name: string): string {
if (IS_DART) {
return `.map( (${argNames.join(',')}) => ${callback} ).toList()`;
return `const ${name}`;
} else {
return `.map(function(${argNames.join(',')}) { return ${callback}; })`;
}
}
export function codeGenReplaceAll(pattern: string, expression: string): string {
if (IS_DART) {
return `.replaceAll('${pattern}', ${expression})`;
} else {
return `.replace(/${pattern}/g, ${expression})`;
return `new ${name}`;
}
}

View File

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

View File

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

View File

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

View File

@ -1,4 +1,6 @@
import {unimplemented} from 'angular2/src/facade/exceptions';
import {Map} from 'angular2/src/facade/collection';
import {ViewEncapsulation} from 'angular2/src/core/metadata';
/**
* Represents an Angular ProtoView in the Rendering Context.
@ -69,37 +71,40 @@ export class RenderFragmentRef {}
// TODO(i): refactor into an interface
export class RenderViewRef {}
export interface RenderTemplateCmd { visit(visitor: RenderCommandVisitor, context: any): any; }
export interface RenderBeginCmd extends RenderTemplateCmd {
ngContentIndex: number;
isBound: boolean;
export abstract class RenderTemplateCmd {
abstract visit(visitor: RenderCommandVisitor, context: any): any;
}
export interface RenderTextCmd extends RenderBeginCmd { value: string; }
export abstract class RenderBeginCmd extends RenderTemplateCmd {
get ngContentIndex(): number { return unimplemented(); };
get isBound(): boolean { return unimplemented(); };
}
export interface RenderNgContentCmd {
export abstract class RenderTextCmd extends RenderBeginCmd {
get value(): string { return unimplemented(); };
}
export abstract class RenderNgContentCmd extends RenderTemplateCmd {
// The index of this NgContent element
index: number;
get index(): number { return unimplemented(); };
// The index of the NgContent element into which this
// NgContent element should be projected (if any)
ngContentIndex: number;
get ngContentIndex(): number { return unimplemented(); };
}
export interface RenderBeginElementCmd extends RenderBeginCmd {
name: string;
attrNameAndValues: string[];
eventTargetAndNames: string[];
export abstract class RenderBeginElementCmd extends RenderBeginCmd {
get name(): string { return unimplemented(); };
get attrNameAndValues(): string[] { return unimplemented(); };
get eventTargetAndNames(): string[] { return unimplemented(); };
}
export interface RenderBeginComponentCmd extends RenderBeginElementCmd {
nativeShadow: boolean;
templateId: number;
export abstract class RenderBeginComponentCmd extends RenderBeginElementCmd {
get templateId(): string { return unimplemented(); };
}
export interface RenderEmbeddedTemplateCmd extends RenderBeginElementCmd {
isMerged: boolean;
children: RenderTemplateCmd[];
export abstract class RenderEmbeddedTemplateCmd extends RenderBeginElementCmd {
get isMerged(): boolean { return unimplemented(); };
get children(): RenderTemplateCmd[] { return unimplemented(); };
}
export interface RenderCommandVisitor {
@ -156,6 +161,10 @@ export interface RenderElementRef {
boundElementIndex: number;
}
export class RenderComponentTemplate {
constructor(public id: string, public shortId: string, public encapsulation: ViewEncapsulation,
public commands: RenderTemplateCmd[], public styles: string[]) {}
}
/**
* Injectable service that provides a low-level interface for modifying the UI.
@ -177,13 +186,13 @@ export abstract class Renderer {
* Once a template is registered it can be referenced via {@link RenderBeginComponentCmd} when
* {@link #createProtoView creating Render ProtoView}.
*/
abstract registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[],
styles: string[], nativeShadow: boolean);
abstract registerComponentTemplate(template: RenderComponentTemplate);
/**
* Creates a {@link RenderProtoViewRef} from an array of {@link RenderTemplateCmd}`s.
*/
abstract createProtoView(cmds: RenderTemplateCmd[]): RenderProtoViewRef;
abstract createProtoView(componentTemplateId: string,
cmds: RenderTemplateCmd[]): RenderProtoViewRef;
/**
* Creates a Root Host View based on the provided `hostProtoViewRef`.

View File

@ -1,6 +1,13 @@
import {Inject, Injectable, OpaqueToken} from 'angular2/src/core/di';
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
import {isPresent, isBlank, RegExpWrapper, CONST_EXPR, stringify} from 'angular2/src/facade/lang';
import {
isPresent,
isBlank,
RegExpWrapper,
CONST_EXPR,
stringify,
StringWrapper
} from 'angular2/src/facade/lang';
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
import {DOM} from 'angular2/src/core/dom/dom_adapter';
@ -18,13 +25,15 @@ import {
RenderFragmentRef,
RenderViewWithFragments,
RenderTemplateCmd,
RenderEventDispatcher
RenderEventDispatcher,
RenderComponentTemplate
} from '../api';
import {DOCUMENT} from './dom_tokens';
import {createRenderView, NodeFactory} from '../view_factory';
import {createRenderView, NodeFactory, encapsulateStyles} from '../view_factory';
import {DefaultRenderView, DefaultRenderFragmentRef, DefaultProtoViewRef} from '../view';
import {camelCaseToDashCase} from './util';
import {ViewEncapsulation} from 'angular2/src/core/metadata';
// TODO(tbosch): solve SVG properly once https://github.com/angular/angular/issues/4417 is done
const XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink';
@ -113,14 +122,12 @@ const SVG_ELEMENT_NAMES = CONST_EXPR({
const SVG_ATTR_NAMESPACES = CONST_EXPR({'href': XLINK_NAMESPACE, 'xlink:href': XLINK_NAMESPACE});
export abstract class DomRenderer extends Renderer implements NodeFactory<Node> {
abstract registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[],
styles: string[], nativeShadow: boolean);
abstract registerComponentTemplate(template: RenderComponentTemplate);
abstract resolveComponentTemplate(templateId: number): RenderTemplateCmd[];
abstract resolveComponentTemplate(templateId: string): RenderComponentTemplate;
createProtoView(cmds: RenderTemplateCmd[]): RenderProtoViewRef {
return new DefaultProtoViewRef(cmds);
}
abstract createProtoView(componentTemplateId: string,
cmds: RenderTemplateCmd[]): RenderProtoViewRef;
abstract createRootHostView(hostProtoViewRef: RenderProtoViewRef, fragmentCount: number,
hostElementSelector: string): RenderViewWithFragments;
@ -189,7 +196,7 @@ export abstract class DomRenderer extends Renderer implements NodeFactory<Node>
}
abstract createElement(name: string, attrNameAndValues: string[]): Node;
abstract mergeElement(existing: Node, attrNameAndValues: string[]);
abstract createShadowRoot(host: Node, templateId: number): Node;
abstract createShadowRoot(host: Node, templateId: string): Node;
createText(value: string): Node { return DOM.createTextNode(isPresent(value) ? value : ''); }
appendChild(parent: Node, child: Node) { DOM.appendChild(parent, child); }
abstract on(element: Node, eventName: string, callback: Function);
@ -252,8 +259,8 @@ export abstract class DomRenderer extends Renderer implements NodeFactory<Node>
@Injectable()
export class DomRenderer_ extends DomRenderer {
private _componentCmds: Map<number, RenderTemplateCmd[]> = new Map<number, RenderTemplateCmd[]>();
private _nativeShadowStyles: Map<number, string[]> = new Map<number, string[]>();
private _componentTpls: Map<string, RenderComponentTemplate> =
new Map<string, RenderComponentTemplate>();
private _document;
constructor(private _eventManager: EventManager,
@ -263,18 +270,20 @@ export class DomRenderer_ extends DomRenderer {
this._document = document;
}
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[],
nativeShadow: boolean) {
this._componentCmds.set(templateId, commands);
if (nativeShadow) {
this._nativeShadowStyles.set(templateId, styles);
} else {
this._domSharedStylesHost.addStyles(styles);
registerComponentTemplate(template: RenderComponentTemplate) {
this._componentTpls.set(template.id, template);
if (template.encapsulation !== ViewEncapsulation.Native) {
var encapsulatedStyles = encapsulateStyles(template);
this._domSharedStylesHost.addStyles(encapsulatedStyles);
}
}
resolveComponentTemplate(templateId: number): RenderTemplateCmd[] {
return this._componentCmds.get(templateId);
createProtoView(componentTemplateId: string, cmds: RenderTemplateCmd[]): RenderProtoViewRef {
return new DefaultProtoViewRef(this._componentTpls.get(componentTemplateId), cmds);
}
resolveComponentTemplate(templateId: string): RenderComponentTemplate {
return this._componentTpls.get(templateId);
}
/** @internal */
@ -299,7 +308,8 @@ export class DomRenderer_ extends DomRenderer {
private _createView(protoViewRef: RenderProtoViewRef,
inplaceElement: HTMLElement): RenderViewWithFragments {
var view = createRenderView((<DefaultProtoViewRef>protoViewRef).cmds, inplaceElement, this);
var dpvr = <DefaultProtoViewRef>protoViewRef;
var view = createRenderView(dpvr.template, dpvr.cmds, inplaceElement, this);
var sdRoots = view.nativeShadowRoots;
for (var i = 0; i < sdRoots.length; i++) {
this._domSharedStylesHost.addHost(sdRoots[i]);
@ -375,11 +385,11 @@ export class DomRenderer_ extends DomRenderer {
createRootContentInsertionPoint(): Node {
return DOM.createComment('root-content-insertion-point');
}
createShadowRoot(host: Node, templateId: number): Node {
createShadowRoot(host: Node, templateId: string): Node {
var sr = DOM.createShadowRoot(host);
var styles = this._nativeShadowStyles.get(templateId);
for (var i = 0; i < styles.length; i++) {
DOM.appendChild(sr, DOM.createStyleElement(styles[i]));
var tpl = this._componentTpls.get(templateId);
for (var i = 0; i < tpl.styles.length; i++) {
DOM.appendChild(sr, DOM.createStyleElement(tpl.styles[i]));
}
return sr;
}

View File

@ -3,6 +3,7 @@ import {ListWrapper, MapWrapper, Map, StringMapWrapper} from 'angular2/src/facad
import {isPresent, isBlank, stringify} from 'angular2/src/facade/lang';
import {
RenderComponentTemplate,
RenderViewRef,
RenderEventDispatcher,
RenderTemplateCmd,
@ -11,7 +12,9 @@ import {
} from './api';
export class DefaultProtoViewRef extends RenderProtoViewRef {
constructor(public cmds: RenderTemplateCmd[]) { super(); }
constructor(public template: RenderComponentTemplate, public cmds: RenderTemplateCmd[]) {
super();
}
}
export class DefaultRenderFragmentRef<N> extends RenderFragmentRef {

View File

@ -1,4 +1,4 @@
import {isBlank, isPresent} from 'angular2/src/facade/lang';
import {isBlank, isPresent, StringWrapper} from 'angular2/src/facade/lang';
import {
RenderEventDispatcher,
RenderTemplateCmd,
@ -7,17 +7,34 @@ import {
RenderBeginComponentCmd,
RenderNgContentCmd,
RenderTextCmd,
RenderEmbeddedTemplateCmd
RenderEmbeddedTemplateCmd,
RenderComponentTemplate
} from './api';
import {DefaultRenderView, DefaultRenderFragmentRef} from './view';
import {ViewEncapsulation} from 'angular2/src/core/metadata';
import {ListWrapper} from 'angular2/src/facade/collection';
export function createRenderView(fragmentCmds: RenderTemplateCmd[], inplaceElement: any,
export function encapsulateStyles(componentTemplate: RenderComponentTemplate): string[] {
var processedStyles = componentTemplate.styles;
if (componentTemplate.encapsulation === ViewEncapsulation.Emulated) {
processedStyles = ListWrapper.createFixedSize(componentTemplate.styles.length);
for (var i = 0; i < componentTemplate.styles.length; i++) {
processedStyles[i] = StringWrapper.replaceAll(componentTemplate.styles[i], COMPONENT_REGEX,
componentTemplate.shortId);
}
}
return processedStyles;
}
export function createRenderView(componentTemplate: RenderComponentTemplate,
cmds: RenderTemplateCmd[], inplaceElement: any,
nodeFactory: NodeFactory<any>): DefaultRenderView<any> {
var view: DefaultRenderView<any>;
var eventDispatcher = (boundElementIndex: number, eventName: string, event: any) =>
view.dispatchRenderEvent(boundElementIndex, eventName, event);
var context = new BuildContext(eventDispatcher, nodeFactory, inplaceElement);
context.build(fragmentCmds);
context.build(componentTemplate, cmds);
var fragments: DefaultRenderFragmentRef<any>[] = [];
for (var i = 0; i < context.fragments.length; i++) {
fragments.push(new DefaultRenderFragmentRef(context.fragments[i]));
@ -29,12 +46,12 @@ export function createRenderView(fragmentCmds: RenderTemplateCmd[], inplaceEleme
}
export interface NodeFactory<N> {
resolveComponentTemplate(templateId: number): RenderTemplateCmd[];
resolveComponentTemplate(templateId: string): RenderComponentTemplate;
createTemplateAnchor(attrNameAndValues: string[]): N;
createElement(name: string, attrNameAndValues: string[]): N;
createRootContentInsertionPoint(): N;
mergeElement(existing: N, attrNameAndValues: string[]);
createShadowRoot(host: N, templateId: number): N;
createShadowRoot(host: N, templateId: string): N;
createText(value: string): N;
appendChild(parent: N, child: N);
on(element: N, eventName: string, callback: Function);
@ -57,8 +74,8 @@ class BuildContext<N> {
componentCount: number = 0;
isHost: boolean;
build(fragmentCmds: RenderTemplateCmd[]) {
this.enqueueFragmentBuilder(null, fragmentCmds);
build(template: RenderComponentTemplate, cmds: RenderTemplateCmd[]) {
this.enqueueRootBuilder(template, cmds);
this._build(this._builders[0]);
}
@ -73,14 +90,22 @@ class BuildContext<N> {
enqueueComponentBuilder(component: Component<N>) {
this.componentCount++;
this._builders.push(new RenderViewBuilder<N>(
component, null, this.factory.resolveComponentTemplate(component.cmd.templateId)));
this._builders.push(
new RenderViewBuilder<N>(component, null, component.template, component.template.commands));
}
enqueueFragmentBuilder(parentComponent: Component<N>, commands: RenderTemplateCmd[]) {
enqueueFragmentBuilder(parentComponent: Component<N>, parentTemplate: RenderComponentTemplate,
commands: RenderTemplateCmd[]) {
var rootNodes = [];
this.fragments.push(rootNodes);
this._builders.push(new RenderViewBuilder<N>(parentComponent, rootNodes, commands));
this._builders.push(
new RenderViewBuilder<N>(parentComponent, rootNodes, parentTemplate, commands));
}
enqueueRootBuilder(template: RenderComponentTemplate, cmds: RenderTemplateCmd[]) {
var rootNodes = [];
this.fragments.push(rootNodes);
this._builders.push(new RenderViewBuilder<N>(null, rootNodes, template, cmds));
}
consumeInplaceElement(): N {
@ -116,14 +141,15 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
parentStack: Array<N | Component<N>>;
constructor(public parentComponent: Component<N>, public fragmentRootNodes: N[],
public commands: RenderTemplateCmd[]) {
public template: RenderComponentTemplate, public cmds: RenderTemplateCmd[]) {
var rootNodesParent = isPresent(fragmentRootNodes) ? null : parentComponent.shadowRoot;
this.parentStack = [rootNodesParent];
}
build(context: BuildContext<N>) {
for (var i = 0; i < this.commands.length; i++) {
this.commands[i].visit(this, context);
var cmds = this.cmds;
for (var i = 0; i < cmds.length; i++) {
cmds[i].visit(this, context);
}
}
@ -158,7 +184,7 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
return null;
}
visitBeginElement(cmd: RenderBeginElementCmd, context: BuildContext<N>): any {
this.parentStack.push(this._beginElement(cmd, context));
this.parentStack.push(this._beginElement(cmd, context, null));
return null;
}
visitEndElement(context: BuildContext<N>): any {
@ -166,14 +192,17 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
return null;
}
visitBeginComponent(cmd: RenderBeginComponentCmd, context: BuildContext<N>): any {
var el = this._beginElement(cmd, context);
var templateId = cmd.templateId;
var tpl = context.factory.resolveComponentTemplate(templateId);
var el = this._beginElement(cmd, context, tpl);
var root = el;
if (cmd.nativeShadow) {
root = context.factory.createShadowRoot(el, cmd.templateId);
if (tpl.encapsulation === ViewEncapsulation.Native) {
root = context.factory.createShadowRoot(el, templateId);
context.nativeShadowRoots.push(root);
}
var isRoot = context.componentCount === 0 && context.isHost;
var component = new Component(el, root, cmd, isRoot);
var component = new Component(el, root, isRoot, tpl);
context.enqueueComponentBuilder(component);
this.parentStack.push(component);
return null;
@ -187,18 +216,34 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
this._addChild(el, cmd.ngContentIndex, context);
context.boundElements.push(el);
if (cmd.isMerged) {
context.enqueueFragmentBuilder(this.parentComponent, cmd.children);
context.enqueueFragmentBuilder(this.parentComponent, this.template, cmd.children);
}
return null;
}
private _beginElement(cmd: RenderBeginElementCmd, context: BuildContext<N>): N {
private _beginElement(cmd: RenderBeginElementCmd, context: BuildContext<N>,
componentTemplate: RenderComponentTemplate): N {
var el: N = context.consumeInplaceElement();
var attrNameAndValues = cmd.attrNameAndValues;
if (this.template.encapsulation === ViewEncapsulation.Emulated) {
// Note: Need to clone attrNameAndValues to make it writable!
if (isPresent(componentTemplate)) {
attrNameAndValues = attrNameAndValues.concat([
_shimContentAttribute(this.template.shortId),
'',
_shimHostAttribute(componentTemplate.shortId),
''
]);
} else {
attrNameAndValues =
attrNameAndValues.concat([_shimContentAttribute(this.template.shortId), '']);
}
}
if (isPresent(el)) {
context.factory.mergeElement(el, cmd.attrNameAndValues);
context.factory.mergeElement(el, attrNameAndValues);
this.fragmentRootNodes.push(el);
} else {
el = context.factory.createElement(cmd.name, cmd.attrNameAndValues);
el = context.factory.createElement(cmd.name, attrNameAndValues);
this._addChild(el, cmd.ngContentIndex, context);
}
if (cmd.isBound) {
@ -232,11 +277,11 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
class Component<N> {
private contentNodesByNgContentIndex: N[][] = [];
constructor(public hostElement: N, public shadowRoot: N, public cmd: RenderBeginComponentCmd,
public isRoot: boolean) {}
constructor(public hostElement: N, public shadowRoot: N, public isRoot: boolean,
public template: RenderComponentTemplate) {}
addContentNode(ngContentIndex: number, node: N, context: BuildContext<N>) {
if (isBlank(ngContentIndex)) {
if (this.cmd.nativeShadow) {
if (this.template.encapsulation === ViewEncapsulation.Native) {
context.factory.appendChild(this.hostElement, node);
}
} else {
@ -252,3 +297,16 @@ class Component<N> {
[];
}
}
var COMPONENT_REGEX = /%COMP%/g;
export const COMPONENT_VARIABLE = '%COMP%';
export const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
export const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
function _shimContentAttribute(componentShortId: string): string {
return StringWrapper.replaceAll(CONTENT_ATTR, COMPONENT_REGEX, componentShortId);
}
function _shimHostAttribute(componentShortId: string): string {
return StringWrapper.replaceAll(HOST_ATTR, COMPONENT_REGEX, componentShortId);
}

View File

@ -53,7 +53,7 @@ export class WebWorkerEndElementCmd implements RenderTemplateCmd {
export class WebWorkerBeginComponentCmd implements RenderBeginComponentCmd {
constructor(public isBound: boolean, public ngContentIndex: number, public name: string,
public attrNameAndValues: string[], public eventTargetAndNames: string[],
public nativeShadow: boolean, public templateId: number) {}
public templateId: string) {}
visit(visitor: RenderCommandVisitor, context: any): any {
return visitor.visitBeginComponent(this, context);
}

View File

@ -13,7 +13,8 @@ import {
RenderNgContentCmd,
RenderBeginElementCmd,
RenderBeginComponentCmd,
RenderEmbeddedTemplateCmd
RenderEmbeddedTemplateCmd,
RenderComponentTemplate
} from "angular2/src/core/render/api";
import {
WebWorkerElementRef,
@ -31,6 +32,7 @@ import {RenderProtoViewRefStore} from 'angular2/src/web_workers/shared/render_pr
import {
RenderViewWithFragmentsStore
} from 'angular2/src/web_workers/shared/render_view_with_fragments_store';
import {ViewEncapsulation, VIEW_ENCAPSULATION_VALUES} from 'angular2/src/core/metadata/view';
// PRIMITIVE is any type that does not need to be serialized (string, number, boolean)
// We set it to String so that it is considered a Type.
@ -41,7 +43,7 @@ export class Serializer {
constructor(private _protoViewStore: RenderProtoViewRefStore,
private _renderViewStore: RenderViewWithFragmentsStore) {}
serialize(obj: any, type: Type): Object {
serialize(obj: any, type: any): Object {
if (!isPresent(obj)) {
return null;
}
@ -61,12 +63,16 @@ export class Serializer {
return this._serializeWorkerElementRef(obj);
} else if (type == WebWorkerTemplateCmd) {
return serializeTemplateCmd(obj);
} else if (type === RenderComponentTemplate) {
return this._serializeRenderTemplate(obj);
} else if (type === ViewEncapsulation) {
return serializeEnum(obj);
} else {
throw new BaseException("No serializer for " + type.toString());
}
}
deserialize(map: any, type: Type, data?: any): any {
deserialize(map: any, type: any, data?: any): any {
if (!isPresent(map)) {
return null;
}
@ -89,6 +95,10 @@ export class Serializer {
return this._deserializeWorkerElementRef(map);
} else if (type == WebWorkerTemplateCmd) {
return deserializeTemplateCmd(map);
} else if (type === RenderComponentTemplate) {
return this._deserializeRenderTemplate(map);
} else if (type === ViewEncapsulation) {
return VIEW_ENCAPSULATION_VALUES[map];
} else {
throw new BaseException("No deserializer for " + type.toString());
}
@ -137,8 +147,27 @@ export class Serializer {
return new WebWorkerElementRef(this.deserialize(map['renderView'], RenderViewRef),
map['boundElementIndex']);
}
private _serializeRenderTemplate(obj: RenderComponentTemplate): Object {
return {
'id': obj.id,
'shortId': obj.shortId,
'encapsulation': this.serialize(obj.encapsulation, ViewEncapsulation),
'commands': this.serialize(obj.commands, WebWorkerTemplateCmd),
'styles': this.serialize(obj.styles, PRIMITIVE)
};
}
private _deserializeRenderTemplate(map: {[key: string]: any}): RenderComponentTemplate {
return new RenderComponentTemplate(map['id'], map['shortId'],
this.deserialize(map['encapsulation'], ViewEncapsulation),
this.deserialize(map['commands'], WebWorkerTemplateCmd),
this.deserialize(map['styles'], PRIMITIVE));
}
}
function serializeTemplateCmd(cmd: RenderTemplateCmd): Object {
return cmd.visit(RENDER_TEMPLATE_CMD_SERIALIZER, null);
}
@ -178,7 +207,6 @@ class RenderTemplateCmdSerializer implements RenderCommandVisitor {
'name': cmd.name,
'attrNameAndValues': cmd.attrNameAndValues,
'eventTargetAndNames': cmd.eventTargetAndNames,
'nativeShadow': cmd.nativeShadow,
'templateId': cmd.templateId
};
}
@ -210,7 +238,7 @@ var RENDER_TEMPLATE_CMD_DESERIALIZERS = [
(data: {[key: string]: any}) => new WebWorkerEndElementCmd(),
(data: {[key: string]: any}) => new WebWorkerBeginComponentCmd(
data['isBound'], data['ngContentIndex'], data['name'], data['attrNameAndValues'],
data['eventTargetAndNames'], data['nativeShadow'], data['templateId']),
data['eventTargetAndNames'], data['templateId']),
(data: {[key: string]: any}) => new WebWorkerEndComponentCmd(),
(data: {[key: string]: any}) => new WebWorkerEmbeddedTemplateCmd(
data['isBound'], data['ngContentIndex'], data['name'], data['attrNameAndValues'],

View File

@ -6,7 +6,8 @@ import {
RenderFragmentRef,
RenderProtoViewRef,
Renderer,
RenderTemplateCmd
RenderTemplateCmd,
RenderComponentTemplate
} from 'angular2/src/core/render/api';
import {WebWorkerElementRef, WebWorkerTemplateCmd} from 'angular2/src/web_workers/shared/api';
import {EVENT_CHANNEL, RENDERER_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
@ -31,10 +32,9 @@ export class MessageBasedRenderer {
var broker = this._brokerFactory.createMessageBroker(RENDERER_CHANNEL);
this._bus.initChannel(EVENT_CHANNEL);
broker.registerMethod("registerComponentTemplate",
[PRIMITIVE, WebWorkerTemplateCmd, PRIMITIVE, PRIMITIVE],
broker.registerMethod("registerComponentTemplate", [RenderComponentTemplate],
bind(this._renderer.registerComponentTemplate, this._renderer));
broker.registerMethod("createProtoView", [WebWorkerTemplateCmd, PRIMITIVE],
broker.registerMethod("createProtoView", [PRIMITIVE, WebWorkerTemplateCmd, PRIMITIVE],
bind(this._createProtoView, this));
broker.registerMethod("createRootHostView",
[RenderProtoViewRef, PRIMITIVE, PRIMITIVE, PRIMITIVE],
@ -73,8 +73,9 @@ export class MessageBasedRenderer {
this._renderViewWithFragmentsStore.remove(viewRef);
}
private _createProtoView(cmds: RenderTemplateCmd[], refIndex: number) {
var protoViewRef = this._renderer.createProtoView(cmds);
private _createProtoView(componentTemplateId: string, cmds: RenderTemplateCmd[],
refIndex: number) {
var protoViewRef = this._renderer.createProtoView(componentTemplateId, cmds);
this._renderProtoViewRefStore.store(protoViewRef, refIndex);
}

View File

@ -6,7 +6,8 @@ import {
RenderEventDispatcher,
RenderViewWithFragments,
RenderFragmentRef,
RenderTemplateCmd
RenderTemplateCmd,
RenderComponentTemplate
} from 'angular2/src/core/render/api';
import {
ClientMessageBroker,
@ -35,23 +36,20 @@ export class WebWorkerRenderer implements Renderer {
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_CHANNEL);
}
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[],
nativeShadow: boolean) {
var fnArgs = [
new FnArg(templateId, null),
new FnArg(commands, WebWorkerTemplateCmd),
new FnArg(styles, null),
new FnArg(nativeShadow, null)
];
registerComponentTemplate(template: RenderComponentTemplate) {
var fnArgs = [new FnArg(template, RenderComponentTemplate)];
var args = new UiArguments("registerComponentTemplate", fnArgs);
this._messageBroker.runOnService(args, null);
}
createProtoView(cmds: RenderTemplateCmd[]): RenderProtoViewRef {
createProtoView(componentTemplateId: string, cmds: RenderTemplateCmd[]): RenderProtoViewRef {
var renderProtoViewRef = this._renderProtoViewRefStore.allocate();
var fnArgs: FnArg[] =
[new FnArg(cmds, WebWorkerTemplateCmd), new FnArg(renderProtoViewRef, RenderProtoViewRef)];
var fnArgs: FnArg[] = [
new FnArg(componentTemplateId, null),
new FnArg(cmds, WebWorkerTemplateCmd),
new FnArg(renderProtoViewRef, RenderProtoViewRef)
];
var args: UiArguments = new UiArguments("createProtoView", fnArgs);
this._messageBroker.runOnService(args, null);
return renderProtoViewRef;