parent
fb8b8157ff
commit
e667ad3e6b
|
@ -23,7 +23,7 @@ dependencies:
|
||||||
source_span: '^1.0.0'
|
source_span: '^1.0.0'
|
||||||
stack_trace: '^1.1.1'
|
stack_trace: '^1.1.1'
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
guinness: '^0.1.17'
|
guinness: '^0.1.18'
|
||||||
transformers:
|
transformers:
|
||||||
- angular2
|
- angular2
|
||||||
- $dart2js:
|
- $dart2js:
|
||||||
|
|
|
@ -63,7 +63,7 @@ export class ChangeDetectionCompiler {
|
||||||
var index = 0;
|
var index = 0;
|
||||||
var sourceParts = changeDetectorDefinitions.map(definition => {
|
var sourceParts = changeDetectorDefinitions.map(definition => {
|
||||||
var codegen: any;
|
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
|
// TODO(tbosch): move the 2 code generators to the same place, one with .dart and one with .ts
|
||||||
// suffix
|
// suffix
|
||||||
// and have the same API for calling them!
|
// and have the same API for calling them!
|
||||||
|
@ -74,7 +74,7 @@ export class ChangeDetectionCompiler {
|
||||||
'dynamic' :
|
'dynamic' :
|
||||||
`${moduleRef(componentType.moduleUrl)}${componentType.name}`;
|
`${moduleRef(componentType.moduleUrl)}${componentType.name}`;
|
||||||
codegen.generate(typeRef, className, definition);
|
codegen.generate(typeRef, className, definition);
|
||||||
factories.push(`(dispatcher) => new ${className}(dispatcher)`);
|
factories.push(`${className}.newChangeDetector`);
|
||||||
sourcePart = codegen.toString();
|
sourcePart = codegen.toString();
|
||||||
} else {
|
} else {
|
||||||
codegen = new ChangeDetectorJITGenerator(
|
codegen = new ChangeDetectorJITGenerator(
|
||||||
|
|
|
@ -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 {SetWrapper, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||||
import {
|
import {
|
||||||
TemplateCmd,
|
TemplateCmd,
|
||||||
text,
|
TextCmd,
|
||||||
ngContent,
|
NgContentCmd,
|
||||||
beginElement,
|
BeginElementCmd,
|
||||||
endElement,
|
EndElementCmd,
|
||||||
beginComponent,
|
BeginComponentCmd,
|
||||||
endComponent,
|
EndComponentCmd,
|
||||||
embeddedTemplate,
|
EmbeddedTemplateCmd,
|
||||||
CompiledTemplate
|
CompiledComponentTemplate
|
||||||
} from 'angular2/src/core/linker/template_commands';
|
} from 'angular2/src/core/linker/template_commands';
|
||||||
import {
|
import {
|
||||||
TemplateAst,
|
TemplateAst,
|
||||||
|
@ -32,12 +32,11 @@ import {SourceExpressions, SourceExpression, moduleRef} from './source_module';
|
||||||
|
|
||||||
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
|
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
|
||||||
import {
|
import {
|
||||||
shimHostAttribute,
|
escapeSingleQuoteString,
|
||||||
shimContentAttribute,
|
codeGenConstConstructorCall,
|
||||||
shimContentAttributeExpr,
|
codeGenValueFn,
|
||||||
shimHostAttributeExpr
|
MODULE_SUFFIX
|
||||||
} from './style_compiler';
|
} from './util';
|
||||||
import {escapeSingleQuoteString, MODULE_SUFFIX} from './util';
|
|
||||||
import {Injectable} from 'angular2/src/core/di';
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
|
|
||||||
export var TEMPLATE_COMMANDS_MODULE_REF =
|
export var TEMPLATE_COMMANDS_MODULE_REF =
|
||||||
|
@ -49,28 +48,24 @@ const STYLE_ATTR = 'style';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CommandCompiler {
|
export class CommandCompiler {
|
||||||
compileComponentRuntime(component: CompileDirectiveMetadata, appId: string, templateId: number,
|
compileComponentRuntime(component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||||
template: TemplateAst[], changeDetectorFactories: Function[],
|
changeDetectorFactories: Function[],
|
||||||
componentTemplateFactory: Function): TemplateCmd[] {
|
componentTemplateFactory: Function): TemplateCmd[] {
|
||||||
var visitor = new CommandBuilderVisitor(
|
var visitor = new CommandBuilderVisitor(
|
||||||
new RuntimeCommandFactory(component, appId, templateId, componentTemplateFactory,
|
new RuntimeCommandFactory(component, componentTemplateFactory, changeDetectorFactories), 0);
|
||||||
changeDetectorFactories),
|
|
||||||
0);
|
|
||||||
templateVisitAll(visitor, template);
|
templateVisitAll(visitor, template);
|
||||||
return visitor.result;
|
return visitor.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
compileComponentCodeGen(component: CompileDirectiveMetadata, appIdExpr: string,
|
compileComponentCodeGen(component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||||
templateIdExpr: string, template: TemplateAst[],
|
|
||||||
changeDetectorFactoryExpressions: string[],
|
changeDetectorFactoryExpressions: string[],
|
||||||
componentTemplateFactory: Function): SourceExpression {
|
componentTemplateFactory: Function): SourceExpression {
|
||||||
var visitor = new CommandBuilderVisitor(
|
var visitor =
|
||||||
new CodegenCommandFactory(component, appIdExpr, templateIdExpr, componentTemplateFactory,
|
new CommandBuilderVisitor(new CodegenCommandFactory(component, componentTemplateFactory,
|
||||||
changeDetectorFactoryExpressions),
|
changeDetectorFactoryExpressions),
|
||||||
0);
|
0);
|
||||||
templateVisitAll(visitor, template);
|
templateVisitAll(visitor, template);
|
||||||
var source = `[${visitor.result.join(',')}]`;
|
return new SourceExpression([], codeGenArray(visitor.result));
|
||||||
return new SourceExpression([], source);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +78,7 @@ interface CommandFactory<R> {
|
||||||
createEndElement(): R;
|
createEndElement(): R;
|
||||||
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||||
nativeShadow: boolean, ngContentIndex: number): R;
|
encapsulation: ViewEncapsulation, ngContentIndex: number): R;
|
||||||
createEndComponent(): R;
|
createEndComponent(): R;
|
||||||
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
|
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
|
||||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||||
|
@ -91,112 +86,89 @@ interface CommandFactory<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class RuntimeCommandFactory implements CommandFactory<TemplateCmd> {
|
class RuntimeCommandFactory implements CommandFactory<TemplateCmd> {
|
||||||
constructor(private component: CompileDirectiveMetadata, private appId: string,
|
constructor(private component: CompileDirectiveMetadata,
|
||||||
private templateId: number, private componentTemplateFactory: Function,
|
private componentTemplateFactory: Function,
|
||||||
private changeDetectorFactories: Function[]) {}
|
private changeDetectorFactories: Function[]) {}
|
||||||
private _mapDirectives(directives: CompileDirectiveMetadata[]): Type[] {
|
private _mapDirectives(directives: CompileDirectiveMetadata[]): Type[] {
|
||||||
return directives.map(directive => directive.type.runtime);
|
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 {
|
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 {
|
createNgContent(index: number, ngContentIndex: number): TemplateCmd {
|
||||||
return ngContent(index, ngContentIndex);
|
return new NgContentCmd(index, ngContentIndex);
|
||||||
}
|
}
|
||||||
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||||
isBound: boolean, ngContentIndex: number): TemplateCmd {
|
isBound: boolean, ngContentIndex: number): TemplateCmd {
|
||||||
return beginElement(name, this._addStyleShimAttributes(attrNameAndValues, null, null),
|
return new BeginElementCmd(name, attrNameAndValues, eventTargetAndNames, variableNameAndValues,
|
||||||
eventTargetAndNames, variableNameAndValues, this._mapDirectives(directives),
|
this._mapDirectives(directives), isBound, ngContentIndex);
|
||||||
isBound, ngContentIndex);
|
|
||||||
}
|
}
|
||||||
createEndElement(): TemplateCmd { return endElement(); }
|
createEndElement(): TemplateCmd { return new EndElementCmd(); }
|
||||||
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||||
nativeShadow: boolean, ngContentIndex: number): TemplateCmd {
|
encapsulation: ViewEncapsulation, ngContentIndex: number): TemplateCmd {
|
||||||
var nestedTemplate = this.componentTemplateFactory(directives[0]);
|
var nestedTemplateAccessor = this.componentTemplateFactory(directives[0]);
|
||||||
return beginComponent(
|
return new BeginComponentCmd(name, attrNameAndValues, eventTargetAndNames,
|
||||||
name, this._addStyleShimAttributes(attrNameAndValues, directives[0], nestedTemplate.id),
|
variableNameAndValues, this._mapDirectives(directives),
|
||||||
eventTargetAndNames, variableNameAndValues, this._mapDirectives(directives), nativeShadow,
|
encapsulation, ngContentIndex, nestedTemplateAccessor);
|
||||||
ngContentIndex, nestedTemplate);
|
|
||||||
}
|
}
|
||||||
createEndComponent(): TemplateCmd { return endComponent(); }
|
createEndComponent(): TemplateCmd { return new EndComponentCmd(); }
|
||||||
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
|
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
|
||||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||||
isMerged: boolean, ngContentIndex: number,
|
isMerged: boolean, ngContentIndex: number,
|
||||||
children: TemplateCmd[]): TemplateCmd {
|
children: TemplateCmd[]): TemplateCmd {
|
||||||
return embeddedTemplate(attrNameAndValues, variableNameAndValues,
|
return new EmbeddedTemplateCmd(attrNameAndValues, variableNameAndValues,
|
||||||
this._mapDirectives(directives), isMerged, ngContentIndex,
|
this._mapDirectives(directives), isMerged, ngContentIndex,
|
||||||
this.changeDetectorFactories[embeddedTemplateIndex], children);
|
this.changeDetectorFactories[embeddedTemplateIndex], children);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CodegenCommandFactory implements CommandFactory<string> {
|
class CodegenCommandFactory implements CommandFactory<Expression> {
|
||||||
constructor(private component: CompileDirectiveMetadata, private appIdExpr: string,
|
constructor(private component: CompileDirectiveMetadata,
|
||||||
private templateIdExpr: string, private componentTemplateFactory: Function,
|
private componentTemplateFactory: Function,
|
||||||
private changeDetectorFactoryExpressions: string[]) {}
|
private changeDetectorFactoryExpressions: string[]) {}
|
||||||
|
|
||||||
private _addStyleShimAttributes(attrNameAndValues: string[],
|
createText(value: string, isBound: boolean, ngContentIndex: number): Expression {
|
||||||
localComponent: CompileDirectiveMetadata,
|
return new Expression(
|
||||||
localTemplateIdExpr: string): any[] {
|
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'TextCmd')}(${escapeSingleQuoteString(value)}, ${isBound}, ${ngContentIndex})`);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
createNgContent(index: number, ngContentIndex: number): Expression {
|
||||||
createText(value: string, isBound: boolean, ngContentIndex: number): string {
|
return new Expression(
|
||||||
return `${TEMPLATE_COMMANDS_MODULE_REF}text(${escapeSingleQuoteString(value)}, ${isBound}, ${ngContentIndex})`;
|
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'NgContentCmd')}(${index}, ${ngContentIndex})`);
|
||||||
}
|
|
||||||
createNgContent(index: number, ngContentIndex: number): string {
|
|
||||||
return `${TEMPLATE_COMMANDS_MODULE_REF}ngContent(${index}, ${ngContentIndex})`;
|
|
||||||
}
|
}
|
||||||
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||||
isBound: boolean, ngContentIndex: number): string {
|
isBound: boolean, ngContentIndex: number): Expression {
|
||||||
var attrsExpression = codeGenArray(this._addStyleShimAttributes(attrNameAndValues, null, null));
|
var attrsExpression = codeGenArray(attrNameAndValues);
|
||||||
return `${TEMPLATE_COMMANDS_MODULE_REF}beginElement(${escapeSingleQuoteString(name)}, ${attrsExpression}, ${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${isBound}, ${ngContentIndex})`;
|
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[],
|
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||||
nativeShadow: boolean, ngContentIndex: number): string {
|
encapsulation: ViewEncapsulation, ngContentIndex: number): Expression {
|
||||||
var nestedCompExpr = this.componentTemplateFactory(directives[0]);
|
var attrsExpression = codeGenArray(attrNameAndValues);
|
||||||
var attrsExpression = codeGenArray(
|
return new Expression(
|
||||||
this._addStyleShimAttributes(attrNameAndValues, directives[0], `${nestedCompExpr}.id`));
|
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'BeginComponentCmd')}(${escapeSingleQuoteString(name)}, ${attrsExpression}, ` +
|
||||||
return `${TEMPLATE_COMMANDS_MODULE_REF}beginComponent(${escapeSingleQuoteString(name)}, ${attrsExpression}, ${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${nativeShadow}, ${ngContentIndex}, ${nestedCompExpr})`;
|
`${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[],
|
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
|
||||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||||
isMerged: boolean, ngContentIndex: number, children: string[]): string {
|
isMerged: boolean, ngContentIndex: number,
|
||||||
return `${TEMPLATE_COMMANDS_MODULE_REF}embeddedTemplate(${codeGenArray(attrNameAndValues)}, ${codeGenArray(variableNameAndValues)}, ` +
|
children: Expression[]): Expression {
|
||||||
`${codeGenDirectivesArray(directives)}, ${isMerged}, ${ngContentIndex}, ${this.changeDetectorFactoryExpressions[embeddedTemplateIndex]}, [${children.join(',')}])`;
|
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)) {
|
if (isPresent(component)) {
|
||||||
this.result.push(this.commandFactory.createBeginComponent(
|
this.result.push(this.commandFactory.createBeginComponent(
|
||||||
ast.name, attrNameAndValues, eventTargetAndNames, variableNameAndValues, directives,
|
ast.name, attrNameAndValues, eventTargetAndNames, variableNameAndValues, directives,
|
||||||
component.template.encapsulation === ViewEncapsulation.Native, ast.ngContentIndex));
|
component.template.encapsulation, ast.ngContentIndex));
|
||||||
templateVisitAll(this, ast.children);
|
templateVisitAll(this, ast.children);
|
||||||
this.result.push(this.commandFactory.createEndComponent());
|
this.result.push(this.commandFactory.createEndComponent());
|
||||||
} else {
|
} else {
|
||||||
|
@ -383,11 +355,21 @@ function escapeValue(value: any): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
function codeGenArray(data: 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 {
|
function codeGenDirectivesArray(directives: CompileDirectiveMetadata[]): string {
|
||||||
var expressions = directives.map(
|
var expressions = directives.map(
|
||||||
directiveType => `${moduleRef(directiveType.type.moduleUrl)}${directiveType.type.name}`);
|
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}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,21 +9,12 @@ import {UrlResolver} from 'angular2/src/compiler/url_resolver';
|
||||||
import {extractStyleUrls} from './style_url_resolver';
|
import {extractStyleUrls} from './style_url_resolver';
|
||||||
import {
|
import {
|
||||||
escapeSingleQuoteString,
|
escapeSingleQuoteString,
|
||||||
codeGenConcatArray,
|
|
||||||
codeGenMapArray,
|
|
||||||
codeGenReplaceAll,
|
|
||||||
codeGenExportVariable,
|
codeGenExportVariable,
|
||||||
codeGenToString,
|
codeGenToString,
|
||||||
MODULE_SUFFIX
|
MODULE_SUFFIX
|
||||||
} from './util';
|
} from './util';
|
||||||
import {Injectable} from 'angular2/src/core/di';
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
|
import {COMPONENT_VARIABLE, HOST_ATTR, CONTENT_ATTR} from 'angular2/src/core/render/view_factory';
|
||||||
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}`;
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class StyleCompiler {
|
export class StyleCompiler {
|
||||||
|
@ -32,28 +23,16 @@ export class StyleCompiler {
|
||||||
|
|
||||||
constructor(private _xhr: XHR, private _urlResolver: UrlResolver) {}
|
constructor(private _xhr: XHR, private _urlResolver: UrlResolver) {}
|
||||||
|
|
||||||
compileComponentRuntime(appId: string, templateId: number,
|
compileComponentRuntime(template: CompileTemplateMetadata): Promise<Array<string | any[]>> {
|
||||||
template: CompileTemplateMetadata): Promise<string[]> {
|
|
||||||
var styles = template.styles;
|
var styles = template.styles;
|
||||||
var styleAbsUrls = template.styleUrls;
|
var styleAbsUrls = template.styleUrls;
|
||||||
return this._loadStyles(styles, styleAbsUrls,
|
return this._loadStyles(styles, styleAbsUrls,
|
||||||
template.encapsulation === ViewEncapsulation.Emulated)
|
template.encapsulation === ViewEncapsulation.Emulated);
|
||||||
.then(styles => styles.map(style => StringWrapper.replaceAll(
|
|
||||||
style, COMPONENT_REGEX, componentId(appId, templateId))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compileComponentCodeGen(appIdExpression: string, templateIdExpression: string,
|
compileComponentCodeGen(template: CompileTemplateMetadata): SourceExpression {
|
||||||
template: CompileTemplateMetadata): SourceExpression {
|
|
||||||
var shim = template.encapsulation === ViewEncapsulation.Emulated;
|
var shim = template.encapsulation === ViewEncapsulation.Emulated;
|
||||||
var suffix;
|
return this._styleCodeGen(template.styles, template.styleUrls, shim);
|
||||||
if (shim) {
|
|
||||||
suffix = codeGenMapArray(
|
|
||||||
['style'],
|
|
||||||
`style${codeGenReplaceAll(COMPONENT_VARIABLE, componentIdExpression(appIdExpression, templateIdExpression))}`);
|
|
||||||
} else {
|
|
||||||
suffix = '';
|
|
||||||
}
|
|
||||||
return this._styleCodeGen(template.styles, template.styleUrls, shim, suffix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compileStylesheetCodeGen(stylesheetUrl: string, cssText: string): SourceModule[] {
|
compileStylesheetCodeGen(stylesheetUrl: string, cssText: string): SourceModule[] {
|
||||||
|
@ -61,17 +40,16 @@ export class StyleCompiler {
|
||||||
return [
|
return [
|
||||||
this._styleModule(
|
this._styleModule(
|
||||||
stylesheetUrl, false,
|
stylesheetUrl, false,
|
||||||
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, false, '')),
|
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, false)),
|
||||||
this._styleModule(
|
this._styleModule(stylesheetUrl, true, this._styleCodeGen([styleWithImports.style],
|
||||||
stylesheetUrl, true,
|
styleWithImports.styleUrls, true))
|
||||||
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, true, ''))
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCache() { this._styleCache.clear(); }
|
clearCache() { this._styleCache.clear(); }
|
||||||
|
|
||||||
private _loadStyles(plainStyles: string[], absUrls: string[],
|
private _loadStyles(plainStyles: string[], absUrls: string[],
|
||||||
encapsulate: boolean): Promise<string[]> {
|
encapsulate: boolean): Promise<Array<string | any[]>> {
|
||||||
var promises = absUrls.map((absUrl) => {
|
var promises = absUrls.map((absUrl) => {
|
||||||
var cacheKey = `${absUrl}${encapsulate ? '.shim' : ''}`;
|
var cacheKey = `${absUrl}${encapsulate ? '.shim' : ''}`;
|
||||||
var result = this._styleCache.get(cacheKey);
|
var result = this._styleCache.get(cacheKey);
|
||||||
|
@ -86,22 +64,23 @@ export class StyleCompiler {
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
return PromiseWrapper.all(promises).then((nestedStyles: string[][]) => {
|
return PromiseWrapper.all(promises).then((nestedStyles: string[][]) => {
|
||||||
var result = plainStyles.map(plainStyle => this._shimIfNeeded(plainStyle, encapsulate));
|
var result: Array<string | any[]> =
|
||||||
nestedStyles.forEach(styles => styles.forEach(style => result.push(style)));
|
plainStyles.map(plainStyle => this._shimIfNeeded(plainStyle, encapsulate));
|
||||||
|
nestedStyles.forEach(styles => result.push(styles));
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _styleCodeGen(plainStyles: string[], absUrls: string[], shim: boolean,
|
private _styleCodeGen(plainStyles: string[], absUrls: string[], shim: boolean): SourceExpression {
|
||||||
suffix: string): SourceExpression {
|
var arrayPrefix = IS_DART ? `const` : '';
|
||||||
var expressionSource = `(`;
|
var styleExpressions = plainStyles.map(
|
||||||
expressionSource +=
|
plainStyle => escapeSingleQuoteString(this._shimIfNeeded(plainStyle, shim)));
|
||||||
`[${plainStyles.map( plainStyle => escapeSingleQuoteString(this._shimIfNeeded(plainStyle, shim)) ).join(',')}]`;
|
|
||||||
for (var i = 0; i < absUrls.length; i++) {
|
for (var i = 0; i < absUrls.length; i++) {
|
||||||
var moduleUrl = this._createModuleUrl(absUrls[i], shim);
|
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);
|
return new SourceExpression([], expressionSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,29 +101,3 @@ export class StyleCompiler {
|
||||||
return shim ? `${stylesheetUrl}.shim${MODULE_SUFFIX}` : `${stylesheetUrl}${MODULE_SUFFIX}`;
|
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)}`;
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ import {BaseException} from 'angular2/src/facade/exceptions';
|
||||||
import {ListWrapper, SetWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper, SetWrapper} from 'angular2/src/facade/collection';
|
||||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
import {
|
import {
|
||||||
CompiledTemplate,
|
CompiledComponentTemplate,
|
||||||
TemplateCmd,
|
TemplateCmd,
|
||||||
nextTemplateId,
|
CompiledHostTemplate,
|
||||||
CompiledHostTemplate
|
BeginComponentCmd
|
||||||
} from 'angular2/src/core/linker/template_commands';
|
} from 'angular2/src/core/linker/template_commands';
|
||||||
import {
|
import {
|
||||||
createHostComponentMeta,
|
createHostComponentMeta,
|
||||||
|
@ -23,7 +23,6 @@ import {CommandCompiler} from './command_compiler';
|
||||||
import {TemplateParser} from './template_parser';
|
import {TemplateParser} from './template_parser';
|
||||||
import {TemplateNormalizer} from './template_normalizer';
|
import {TemplateNormalizer} from './template_normalizer';
|
||||||
import {RuntimeMetadataResolver} from './runtime_metadata';
|
import {RuntimeMetadataResolver} from './runtime_metadata';
|
||||||
import {APP_ID} from 'angular2/src/core/application_tokens';
|
|
||||||
|
|
||||||
import {TEMPLATE_COMMANDS_MODULE_REF} from './command_compiler';
|
import {TEMPLATE_COMMANDS_MODULE_REF} from './command_compiler';
|
||||||
import {
|
import {
|
||||||
|
@ -32,22 +31,19 @@ import {
|
||||||
codeGenValueFn,
|
codeGenValueFn,
|
||||||
MODULE_SUFFIX
|
MODULE_SUFFIX
|
||||||
} from './util';
|
} from './util';
|
||||||
import {Inject} from 'angular2/src/core/di';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TemplateCompiler {
|
export class TemplateCompiler {
|
||||||
private _hostCacheKeys = new Map<Type, any>();
|
private _hostCacheKeys = new Map<Type, any>();
|
||||||
private _compiledTemplateCache = new Map<any, CompiledTemplate>();
|
private _compiledTemplateCache = new Map<any, CompiledComponentTemplate>();
|
||||||
private _compiledTemplateDone = new Map<any, Promise<CompiledTemplate>>();
|
private _compiledTemplateDone = new Map<any, Promise<CompiledComponentTemplate>>();
|
||||||
private _appId: string;
|
private _nextTemplateId: number = 0;
|
||||||
|
|
||||||
constructor(private _runtimeMetadataResolver: RuntimeMetadataResolver,
|
constructor(private _runtimeMetadataResolver: RuntimeMetadataResolver,
|
||||||
private _templateNormalizer: TemplateNormalizer,
|
private _templateNormalizer: TemplateNormalizer,
|
||||||
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
|
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
|
||||||
private _commandCompiler: CommandCompiler,
|
private _commandCompiler: CommandCompiler,
|
||||||
private _cdCompiler: ChangeDetectionCompiler, @Inject(APP_ID) appId: string) {
|
private _cdCompiler: ChangeDetectionCompiler) {}
|
||||||
this._appId = appId;
|
|
||||||
}
|
|
||||||
|
|
||||||
normalizeDirectiveMetadata(directive: CompileDirectiveMetadata):
|
normalizeDirectiveMetadata(directive: CompileDirectiveMetadata):
|
||||||
Promise<CompileDirectiveMetadata> {
|
Promise<CompileDirectiveMetadata> {
|
||||||
|
@ -87,7 +83,7 @@ export class TemplateCompiler {
|
||||||
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], new Set());
|
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], new Set());
|
||||||
}
|
}
|
||||||
return this._compiledTemplateDone.get(hostCacheKey)
|
return this._compiledTemplateDone.get(hostCacheKey)
|
||||||
.then(compiledTemplate => new CompiledHostTemplate(() => compiledTemplate));
|
.then(compiledTemplate => new CompiledHostTemplate(compiledTemplate));
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCache() {
|
clearCache() {
|
||||||
|
@ -97,57 +93,55 @@ export class TemplateCompiler {
|
||||||
this._compiledTemplateDone.clear();
|
this._compiledTemplateDone.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _compileComponentRuntime(cacheKey: any, compMeta: CompileDirectiveMetadata,
|
private _compileComponentRuntime(
|
||||||
viewDirectives: CompileDirectiveMetadata[],
|
cacheKey: any, compMeta: CompileDirectiveMetadata, viewDirectives: CompileDirectiveMetadata[],
|
||||||
compilingComponentCacheKeys: Set<any>): CompiledTemplate {
|
compilingComponentCacheKeys: Set<any>): CompiledComponentTemplate {
|
||||||
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
|
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
|
||||||
var done = this._compiledTemplateDone.get(cacheKey);
|
var done = this._compiledTemplateDone.get(cacheKey);
|
||||||
if (isBlank(compiledTemplate)) {
|
if (isBlank(compiledTemplate)) {
|
||||||
var styles;
|
var styles = [];
|
||||||
var changeDetectorFactory;
|
var changeDetectorFactory;
|
||||||
var commands;
|
var commands = [];
|
||||||
var templateId = nextTemplateId();
|
var templateId = `${stringify(compMeta.type.runtime)}Template${this._nextTemplateId++}`;
|
||||||
compiledTemplate =
|
compiledTemplate = new CompiledComponentTemplate(
|
||||||
new CompiledTemplate(templateId, (_a, _b) => [changeDetectorFactory, commands, styles]);
|
templateId, (dispatcher) => changeDetectorFactory(dispatcher), commands, styles);
|
||||||
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
|
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
|
||||||
compilingComponentCacheKeys.add(cacheKey);
|
compilingComponentCacheKeys.add(cacheKey);
|
||||||
done =
|
done = PromiseWrapper
|
||||||
PromiseWrapper.all([
|
.all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat(
|
||||||
<any>this._styleCompiler.compileComponentRuntime(this._appId, templateId,
|
viewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
|
||||||
compMeta.template)
|
.then((stylesAndNormalizedViewDirMetas: any[]) => {
|
||||||
].concat(viewDirectives.map(dirMeta =>
|
var childPromises = [];
|
||||||
this.normalizeDirectiveMetadata(dirMeta))))
|
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
|
||||||
.then((stylesAndNormalizedViewDirMetas: any[]) => {
|
var parsedTemplate = this._templateParser.parse(
|
||||||
var childPromises = [];
|
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);
|
||||||
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
|
|
||||||
var parsedTemplate = this._templateParser.parse(
|
|
||||||
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);
|
|
||||||
|
|
||||||
var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
|
var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
|
||||||
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
||||||
changeDetectorFactory = changeDetectorFactories[0];
|
changeDetectorFactory = changeDetectorFactories[0];
|
||||||
styles = stylesAndNormalizedViewDirMetas[0];
|
var tmpStyles: string[] = stylesAndNormalizedViewDirMetas[0];
|
||||||
commands = this._compileCommandsRuntime(compMeta, templateId, parsedTemplate,
|
tmpStyles.forEach(style => styles.push(style));
|
||||||
changeDetectorFactories,
|
var tmpCommands: TemplateCmd[] = this._compileCommandsRuntime(
|
||||||
compilingComponentCacheKeys, childPromises);
|
compMeta, parsedTemplate, changeDetectorFactories,
|
||||||
return PromiseWrapper.all(childPromises);
|
compilingComponentCacheKeys, childPromises);
|
||||||
})
|
tmpCommands.forEach(cmd => commands.push(cmd));
|
||||||
.then((_) => {
|
return PromiseWrapper.all(childPromises);
|
||||||
SetWrapper.delete(compilingComponentCacheKeys, cacheKey);
|
})
|
||||||
return compiledTemplate;
|
.then((_) => {
|
||||||
});
|
SetWrapper.delete(compilingComponentCacheKeys, cacheKey);
|
||||||
|
return compiledTemplate;
|
||||||
|
});
|
||||||
this._compiledTemplateDone.set(cacheKey, done);
|
this._compiledTemplateDone.set(cacheKey, done);
|
||||||
}
|
}
|
||||||
return compiledTemplate;
|
return compiledTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _compileCommandsRuntime(compMeta: CompileDirectiveMetadata, templateId: number,
|
private _compileCommandsRuntime(compMeta: CompileDirectiveMetadata, parsedTemplate: TemplateAst[],
|
||||||
parsedTemplate: TemplateAst[],
|
|
||||||
changeDetectorFactories: Function[],
|
changeDetectorFactories: Function[],
|
||||||
compilingComponentCacheKeys: Set<Type>,
|
compilingComponentCacheKeys: Set<Type>,
|
||||||
childPromises: Promise<any>[]): TemplateCmd[] {
|
childPromises: Promise<any>[]): TemplateCmd[] {
|
||||||
return this._commandCompiler.compileComponentRuntime(
|
var cmds: TemplateCmd[] = this._commandCompiler.compileComponentRuntime(
|
||||||
compMeta, this._appId, templateId, parsedTemplate, changeDetectorFactories,
|
compMeta, parsedTemplate, changeDetectorFactories,
|
||||||
(childComponentDir: CompileDirectiveMetadata) => {
|
(childComponentDir: CompileDirectiveMetadata) => {
|
||||||
var childCacheKey = childComponentDir.type.runtime;
|
var childCacheKey = childComponentDir.type.runtime;
|
||||||
var childViewDirectives: CompileDirectiveMetadata[] =
|
var childViewDirectives: CompileDirectiveMetadata[] =
|
||||||
|
@ -160,8 +154,14 @@ export class TemplateCompiler {
|
||||||
// Only wait for a child if it is not a cycle
|
// Only wait for a child if it is not a cycle
|
||||||
childPromises.push(this._compiledTemplateDone.get(childCacheKey));
|
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 {
|
compileTemplatesCodeGen(components: NormalizedComponentWithViewDirectives[]): SourceModule {
|
||||||
|
@ -171,40 +171,35 @@ export class TemplateCompiler {
|
||||||
var declarations = [];
|
var declarations = [];
|
||||||
var templateArguments = [];
|
var templateArguments = [];
|
||||||
var componentMetas: CompileDirectiveMetadata[] = [];
|
var componentMetas: CompileDirectiveMetadata[] = [];
|
||||||
var templateIdVariable = 'templateId';
|
|
||||||
var appIdVariable = 'appId';
|
|
||||||
components.forEach(componentWithDirs => {
|
components.forEach(componentWithDirs => {
|
||||||
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
|
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
|
||||||
assertComponent(compMeta);
|
assertComponent(compMeta);
|
||||||
componentMetas.push(compMeta);
|
componentMetas.push(compMeta);
|
||||||
this._processTemplateCodeGen(compMeta, appIdVariable, templateIdVariable,
|
this._processTemplateCodeGen(compMeta,
|
||||||
<CompileDirectiveMetadata[]>componentWithDirs.directives,
|
<CompileDirectiveMetadata[]>componentWithDirs.directives,
|
||||||
declarations, templateArguments);
|
declarations, templateArguments);
|
||||||
if (compMeta.dynamicLoadable) {
|
if (compMeta.dynamicLoadable) {
|
||||||
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
|
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
|
||||||
componentMetas.push(hostMeta);
|
componentMetas.push(hostMeta);
|
||||||
this._processTemplateCodeGen(hostMeta, appIdVariable, templateIdVariable, [compMeta],
|
this._processTemplateCodeGen(hostMeta, [compMeta], declarations, templateArguments);
|
||||||
declarations, templateArguments);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ListWrapper.forEachWithIndex(componentMetas, (compMeta: CompileDirectiveMetadata,
|
ListWrapper.forEachWithIndex(componentMetas, (compMeta: CompileDirectiveMetadata,
|
||||||
index: number) => {
|
index: number) => {
|
||||||
var templateDataFn = codeGenValueFn([appIdVariable, templateIdVariable],
|
var templateId = `${compMeta.type.moduleUrl}|${compMeta.type.name}`;
|
||||||
`[${(<any[]>templateArguments[index]).join(',')}]`);
|
var constructionKeyword = IS_DART ? 'const' : 'new';
|
||||||
var compiledTemplateExpr =
|
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;
|
var variableValueExpr;
|
||||||
if (compMeta.type.isHost) {
|
if (compMeta.type.isHost) {
|
||||||
var factoryName = `_hostTemplateFactory${index}`;
|
|
||||||
declarations.push(`${codeGenValueFn([], compiledTemplateExpr, factoryName)};`);
|
|
||||||
var constructionKeyword = IS_DART ? 'const' : 'new';
|
|
||||||
variableValueExpr =
|
variableValueExpr =
|
||||||
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${factoryName})`;
|
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${compiledTemplateExpr})`;
|
||||||
} else {
|
} else {
|
||||||
variableValueExpr = compiledTemplateExpr;
|
variableValueExpr = compiledTemplateExpr;
|
||||||
}
|
}
|
||||||
declarations.push(
|
var varName = templateVariableName(compMeta.type);
|
||||||
`${codeGenExportVariable(templateVariableName(compMeta.type), compMeta.type.isHost)}${variableValueExpr};`);
|
declarations.push(`${codeGenExportVariable(varName)}${variableValueExpr};`);
|
||||||
|
declarations.push(`${codeGenValueFn([], varName, templateGetterName(compMeta.type))};`);
|
||||||
});
|
});
|
||||||
var moduleUrl = components[0].component.type.moduleUrl;
|
var moduleUrl = components[0].component.type.moduleUrl;
|
||||||
return new SourceModule(`${templateModuleUrl(moduleUrl)}`, declarations.join('\n'));
|
return new SourceModule(`${templateModuleUrl(moduleUrl)}`, declarations.join('\n'));
|
||||||
|
@ -214,17 +209,16 @@ export class TemplateCompiler {
|
||||||
return this._styleCompiler.compileStylesheetCodeGen(stylesheetUrl, cssText);
|
return this._styleCompiler.compileStylesheetCodeGen(stylesheetUrl, cssText);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata, appIdExpr: string,
|
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata,
|
||||||
templateIdExpr: string, directives: CompileDirectiveMetadata[],
|
directives: CompileDirectiveMetadata[],
|
||||||
targetDeclarations: string[], targetTemplateArguments: any[][]) {
|
targetDeclarations: string[], targetTemplateArguments: any[][]) {
|
||||||
var styleExpr =
|
var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta.template);
|
||||||
this._styleCompiler.compileComponentCodeGen(appIdExpr, templateIdExpr, compMeta.template);
|
|
||||||
var parsedTemplate =
|
var parsedTemplate =
|
||||||
this._templateParser.parse(compMeta.template.template, directives, compMeta.type.name);
|
this._templateParser.parse(compMeta.template.template, directives, compMeta.type.name);
|
||||||
var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen(
|
var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen(
|
||||||
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
||||||
var commandsExpr = this._commandCompiler.compileComponentCodeGen(
|
var commandsExpr = this._commandCompiler.compileComponentCodeGen(
|
||||||
compMeta, appIdExpr, templateIdExpr, parsedTemplate, changeDetectorsExprs.expressions,
|
compMeta, parsedTemplate, changeDetectorsExprs.expressions,
|
||||||
codeGenComponentTemplateFactory);
|
codeGenComponentTemplateFactory);
|
||||||
|
|
||||||
addAll(styleExpr.declarations, targetDeclarations);
|
addAll(styleExpr.declarations, targetDeclarations);
|
||||||
|
@ -251,6 +245,10 @@ function templateVariableName(type: CompileTypeMetadata): string {
|
||||||
return `${type.name}Template`;
|
return `${type.name}Template`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function templateGetterName(type: CompileTypeMetadata): string {
|
||||||
|
return `${templateVariableName(type)}Getter`;
|
||||||
|
}
|
||||||
|
|
||||||
function templateModuleUrl(moduleUrl: string): string {
|
function templateModuleUrl(moduleUrl: string): string {
|
||||||
var urlWithoutSuffix = moduleUrl.substring(0, moduleUrl.length - MODULE_SUFFIX.length);
|
var urlWithoutSuffix = moduleUrl.substring(0, moduleUrl.length - MODULE_SUFFIX.length);
|
||||||
return `${urlWithoutSuffix}.template${MODULE_SUFFIX}`;
|
return `${urlWithoutSuffix}.template${MODULE_SUFFIX}`;
|
||||||
|
@ -263,5 +261,5 @@ function addAll(source: any[], target: any[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string {
|
function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string {
|
||||||
return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateVariableName(nestedCompType.type)}`;
|
return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateGetterName(nestedCompType.type)}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
if (IS_DART) {
|
||||||
return isConst ? `const ${name} = ` : `final ${name} = `;
|
return `const ${name} = `;
|
||||||
} else {
|
} else {
|
||||||
return `var ${name} = exports['${name}'] = `;
|
return `var ${name} = exports['${name}'] = `;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function codeGenConcatArray(expression: string): string {
|
export function codeGenConstConstructorCall(name: string): string {
|
||||||
return `${IS_DART ? '..addAll' : '.concat'}(${expression})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function codeGenMapArray(argNames: string[], callback: string): string {
|
|
||||||
if (IS_DART) {
|
if (IS_DART) {
|
||||||
return `.map( (${argNames.join(',')}) => ${callback} ).toList()`;
|
return `const ${name}`;
|
||||||
} else {
|
} else {
|
||||||
return `.map(function(${argNames.join(',')}) { return ${callback}; })`;
|
return `new ${name}`;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function codeGenReplaceAll(pattern: string, expression: string): string {
|
|
||||||
if (IS_DART) {
|
|
||||||
return `.replaceAll('${pattern}', ${expression})`;
|
|
||||||
} else {
|
|
||||||
return `.replace(/${pattern}/g, ${expression})`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {isPresent, isBlank, Type, isArray, isNumber} from 'angular2/src/facade/lang';
|
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';
|
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 {DirectiveResolver} from './directive_resolver';
|
||||||
import {ViewResolver} from './view_resolver';
|
import {ViewResolver} from './view_resolver';
|
||||||
import {PipeResolver} from './pipe_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 {AMBIENT_PIPES} from 'angular2/src/core/ambient';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
visitAllCommands,
|
visitAllCommands,
|
||||||
CompiledTemplate,
|
CompiledComponentTemplate,
|
||||||
CompiledHostTemplate,
|
CompiledHostTemplate,
|
||||||
TemplateCmd,
|
TemplateCmd,
|
||||||
CommandVisitor,
|
CommandVisitor,
|
||||||
|
@ -36,7 +36,9 @@ import {APP_ID} from 'angular2/src/core/application_tokens';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ProtoViewFactory {
|
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,
|
constructor(private _renderer: Renderer,
|
||||||
@Optional() @Inject(AMBIENT_PIPES) private _ambientPipes: Array<Type | any[]>,
|
@Optional() @Inject(AMBIENT_PIPES) private _ambientPipes: Array<Type | any[]>,
|
||||||
private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver,
|
private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver,
|
||||||
|
@ -45,13 +47,16 @@ export class ProtoViewFactory {
|
||||||
clearCache() { this._cache.clear(); }
|
clearCache() { this._cache.clear(); }
|
||||||
|
|
||||||
createHost(compiledHostTemplate: CompiledHostTemplate): AppProtoView {
|
createHost(compiledHostTemplate: CompiledHostTemplate): AppProtoView {
|
||||||
var compiledTemplate = compiledHostTemplate.getTemplate();
|
var compiledTemplate = compiledHostTemplate.template;
|
||||||
var result = this._cache.get(compiledTemplate.id);
|
var result = this._cache.get(compiledTemplate.id);
|
||||||
if (isBlank(result)) {
|
if (isBlank(result)) {
|
||||||
var templateData = compiledTemplate.getData(this._appId);
|
|
||||||
var emptyMap: {[key: string]: PipeProvider} = {};
|
var emptyMap: {[key: string]: PipeProvider} = {};
|
||||||
result = new AppProtoView(templateData.commands, ViewType.HOST, true,
|
var shortId = `${this._appId}-${this._nextTemplateId++}`;
|
||||||
templateData.changeDetectorFactory, null, new ProtoPipes(emptyMap));
|
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);
|
this._cache.set(compiledTemplate.id, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -62,18 +67,19 @@ export class ProtoViewFactory {
|
||||||
if (isBlank(nestedProtoView)) {
|
if (isBlank(nestedProtoView)) {
|
||||||
var component = cmd.directives[0];
|
var component = cmd.directives[0];
|
||||||
var view = this._viewResolver.resolve(component);
|
var view = this._viewResolver.resolve(component);
|
||||||
var compiledTemplateData = cmd.template.getData(this._appId);
|
var compiledTemplate = cmd.templateGetter();
|
||||||
|
var styles = _flattenStyleArr(compiledTemplate.styles, []);
|
||||||
this._renderer.registerComponentTemplate(cmd.templateId, compiledTemplateData.commands,
|
var shortId = `${this._appId}-${this._nextTemplateId++}`;
|
||||||
compiledTemplateData.styles, cmd.nativeShadow);
|
this._renderer.registerComponentTemplate(new RenderComponentTemplate(
|
||||||
|
compiledTemplate.id, shortId, cmd.encapsulation, compiledTemplate.commands, styles));
|
||||||
var boundPipes = this._flattenPipes(view).map(pipe => this._bindPipe(pipe));
|
var boundPipes = this._flattenPipes(view).map(pipe => this._bindPipe(pipe));
|
||||||
|
|
||||||
nestedProtoView = new AppProtoView(compiledTemplateData.commands, ViewType.COMPONENT, true,
|
nestedProtoView = new AppProtoView(
|
||||||
compiledTemplateData.changeDetectorFactory, null,
|
compiledTemplate.id, compiledTemplate.commands, ViewType.COMPONENT, true,
|
||||||
ProtoPipes.fromProviders(boundPipes));
|
compiledTemplate.changeDetectorFactory, null, ProtoPipes.fromProviders(boundPipes));
|
||||||
// Note: The cache is updated before recursing
|
// Note: The cache is updated before recursing
|
||||||
// to be able to resolve cycles
|
// to be able to resolve cycles
|
||||||
this._cache.set(cmd.template.id, nestedProtoView);
|
this._cache.set(compiledTemplate.id, nestedProtoView);
|
||||||
this._initializeProtoView(nestedProtoView, null);
|
this._initializeProtoView(nestedProtoView, null);
|
||||||
}
|
}
|
||||||
return nestedProtoView;
|
return nestedProtoView;
|
||||||
|
@ -81,7 +87,7 @@ export class ProtoViewFactory {
|
||||||
|
|
||||||
private _createEmbeddedTemplate(cmd: EmbeddedTemplateCmd, parent: AppProtoView): AppProtoView {
|
private _createEmbeddedTemplate(cmd: EmbeddedTemplateCmd, parent: AppProtoView): AppProtoView {
|
||||||
var nestedProtoView = new 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));
|
arrayToMap(cmd.variableNameAndValues, true), new ProtoPipes(parent.pipes.config));
|
||||||
if (cmd.isMerged) {
|
if (cmd.isMerged) {
|
||||||
this.initializeProtoViewIfNeeded(nestedProtoView);
|
this.initializeProtoViewIfNeeded(nestedProtoView);
|
||||||
|
@ -91,7 +97,7 @@ export class ProtoViewFactory {
|
||||||
|
|
||||||
initializeProtoViewIfNeeded(protoView: AppProtoView) {
|
initializeProtoViewIfNeeded(protoView: AppProtoView) {
|
||||||
if (!protoView.isInitialized()) {
|
if (!protoView.isInitialized()) {
|
||||||
var render = this._renderer.createProtoView(protoView.templateCmds);
|
var render = this._renderer.createProtoView(protoView.templateId, protoView.templateCmds);
|
||||||
this._initializeProtoView(protoView, render);
|
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 {Type, CONST_EXPR, CONST, isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||||
|
import {unimplemented} from 'angular2/src/facade/exceptions';
|
||||||
import {
|
import {
|
||||||
RenderTemplateCmd,
|
RenderTemplateCmd,
|
||||||
RenderCommandVisitor,
|
RenderCommandVisitor,
|
||||||
|
@ -8,12 +9,10 @@ import {
|
||||||
RenderBeginComponentCmd,
|
RenderBeginComponentCmd,
|
||||||
RenderEmbeddedTemplateCmd
|
RenderEmbeddedTemplateCmd
|
||||||
} from 'angular2/src/core/render/render';
|
} from 'angular2/src/core/render/render';
|
||||||
|
import {ViewEncapsulation} from 'angular2/src/core/metadata';
|
||||||
var _nextTemplateId: number = 0;
|
// Export ViewEncapsulation so that compiled templates only need to depend
|
||||||
|
// on template_commands.
|
||||||
export function nextTemplateId(): number {
|
export {ViewEncapsulation} from 'angular2/src/core/metadata';
|
||||||
return _nextTemplateId++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A compiled host template.
|
* A compiled host template.
|
||||||
|
@ -23,34 +22,16 @@ export function nextTemplateId(): number {
|
||||||
*/
|
*/
|
||||||
@CONST()
|
@CONST()
|
||||||
export class CompiledHostTemplate {
|
export class CompiledHostTemplate {
|
||||||
// Note: _templateGetter is a function so that CompiledHostTemplate can be
|
constructor(public template: CompiledComponentTemplate) {}
|
||||||
// a const!
|
|
||||||
constructor(private _templateGetter: Function) {}
|
|
||||||
|
|
||||||
getTemplate(): CompiledTemplate { return this._templateGetter(); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A compiled template.
|
* A compiled template.
|
||||||
*/
|
*/
|
||||||
export class CompiledTemplate {
|
@CONST()
|
||||||
// Note: paramGetter is a function so that we can have cycles between templates!
|
export class CompiledComponentTemplate {
|
||||||
// paramGetter returns a tuple with:
|
constructor(public id: string, public changeDetectorFactory: Function,
|
||||||
// - ChangeDetector factory function
|
public commands: TemplateCmd[], public styles: string[]) {}
|
||||||
// - 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 EMPTY_ARR = CONST_EXPR([]);
|
const EMPTY_ARR = CONST_EXPR([]);
|
||||||
|
@ -59,6 +40,7 @@ export interface TemplateCmd extends RenderTemplateCmd {
|
||||||
visit(visitor: RenderCommandVisitor, context: any): any;
|
visit(visitor: RenderCommandVisitor, context: any): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CONST()
|
||||||
export class TextCmd implements TemplateCmd, RenderTextCmd {
|
export class TextCmd implements TemplateCmd, RenderTextCmd {
|
||||||
constructor(public value: string, public isBound: boolean, public ngContentIndex: number) {}
|
constructor(public value: string, public isBound: boolean, public ngContentIndex: number) {}
|
||||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
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 {
|
@CONST()
|
||||||
return new TextCmd(value, isBound, ngContentIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NgContentCmd implements TemplateCmd, RenderNgContentCmd {
|
export class NgContentCmd implements TemplateCmd, RenderNgContentCmd {
|
||||||
isBound: boolean = false;
|
isBound: boolean = false;
|
||||||
constructor(public index: number, public ngContentIndex: number) {}
|
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 {
|
export abstract class IBeginElementCmd extends RenderBeginElementCmd implements TemplateCmd {
|
||||||
return new NgContentCmd(index, ngContentIndex);
|
get variableNameAndValues(): Array<string | number> { return unimplemented(); }
|
||||||
}
|
get eventTargetAndNames(): string[] { return unimplemented(); }
|
||||||
|
get directives(): Type[] { return unimplemented(); }
|
||||||
export interface IBeginElementCmd extends TemplateCmd, RenderBeginElementCmd {
|
abstract visit(visitor: RenderCommandVisitor, context: any): any;
|
||||||
variableNameAndValues: Array<string | number>;
|
|
||||||
eventTargetAndNames: string[];
|
|
||||||
directives: Type[];
|
|
||||||
visit(visitor: RenderCommandVisitor, context: any): any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CONST()
|
||||||
export class BeginElementCmd implements TemplateCmd, IBeginElementCmd, RenderBeginElementCmd {
|
export class BeginElementCmd implements TemplateCmd, IBeginElementCmd, RenderBeginElementCmd {
|
||||||
constructor(public name: string, public attrNameAndValues: string[],
|
constructor(public name: string, public attrNameAndValues: string[],
|
||||||
public eventTargetAndNames: 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 {
|
export class EndElementCmd implements TemplateCmd {
|
||||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
return visitor.visitEndElement(context);
|
return visitor.visitEndElement(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function endElement(): TemplateCmd {
|
@CONST()
|
||||||
return new EndElementCmd();
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BeginComponentCmd implements TemplateCmd, IBeginElementCmd, RenderBeginComponentCmd {
|
export class BeginComponentCmd implements TemplateCmd, IBeginElementCmd, RenderBeginComponentCmd {
|
||||||
isBound: boolean = true;
|
isBound: boolean = true;
|
||||||
templateId: number;
|
|
||||||
constructor(public name: string, public attrNameAndValues: string[],
|
constructor(public name: string, public attrNameAndValues: string[],
|
||||||
public eventTargetAndNames: string[],
|
public eventTargetAndNames: string[],
|
||||||
public variableNameAndValues: Array<string | number>, public directives: Type[],
|
public variableNameAndValues: Array<string | number>, public directives: Type[],
|
||||||
public nativeShadow: boolean, public ngContentIndex: number,
|
public encapsulation: ViewEncapsulation, public ngContentIndex: number,
|
||||||
public template: CompiledTemplate) {
|
// Note: the template needs to be stored as a function
|
||||||
this.templateId = template.id;
|
// so that we can resolve cycles
|
||||||
}
|
public templateGetter: Function /*() => CompiledComponentTemplate*/) {}
|
||||||
|
|
||||||
|
get templateId(): string { return this.templateGetter().id; }
|
||||||
|
|
||||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
return visitor.visitBeginComponent(this, context);
|
return visitor.visitBeginComponent(this, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function beginComponent(
|
@CONST()
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class EndComponentCmd implements TemplateCmd {
|
export class EndComponentCmd implements TemplateCmd {
|
||||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
return visitor.visitEndComponent(context);
|
return visitor.visitEndComponent(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function endComponent(): TemplateCmd {
|
@CONST()
|
||||||
return new EndComponentCmd();
|
|
||||||
}
|
|
||||||
|
|
||||||
export class EmbeddedTemplateCmd implements TemplateCmd, IBeginElementCmd,
|
export class EmbeddedTemplateCmd implements TemplateCmd, IBeginElementCmd,
|
||||||
RenderEmbeddedTemplateCmd {
|
RenderEmbeddedTemplateCmd {
|
||||||
isBound: boolean = true;
|
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 {
|
export interface CommandVisitor extends RenderCommandVisitor {
|
||||||
visitText(cmd: TextCmd, context: any): any;
|
visitText(cmd: TextCmd, context: any): any;
|
||||||
|
|
|
@ -318,8 +318,8 @@ export class AppProtoView {
|
||||||
textBindingCount = null;
|
textBindingCount = null;
|
||||||
render: renderApi.RenderProtoViewRef = null;
|
render: renderApi.RenderProtoViewRef = null;
|
||||||
|
|
||||||
constructor(public templateCmds: TemplateCmd[], public type: ViewType, public isMergable: boolean,
|
constructor(public templateId: string, public templateCmds: TemplateCmd[], public type: ViewType,
|
||||||
public changeDetectorFactory: Function,
|
public isMergable: boolean, public changeDetectorFactory: Function,
|
||||||
public templateVariableBindings: Map<string, string>, public pipes: ProtoPipes) {
|
public templateVariableBindings: Map<string, string>, public pipes: ProtoPipes) {
|
||||||
this.ref = new ProtoViewRef_(this);
|
this.ref = new ProtoViewRef_(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
import {unimplemented} from 'angular2/src/facade/exceptions';
|
||||||
import {Map} from 'angular2/src/facade/collection';
|
import {Map} from 'angular2/src/facade/collection';
|
||||||
|
import {ViewEncapsulation} from 'angular2/src/core/metadata';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an Angular ProtoView in the Rendering Context.
|
* Represents an Angular ProtoView in the Rendering Context.
|
||||||
|
@ -69,37 +71,40 @@ export class RenderFragmentRef {}
|
||||||
// TODO(i): refactor into an interface
|
// TODO(i): refactor into an interface
|
||||||
export class RenderViewRef {}
|
export class RenderViewRef {}
|
||||||
|
|
||||||
export interface RenderTemplateCmd { visit(visitor: RenderCommandVisitor, context: any): any; }
|
export abstract class RenderTemplateCmd {
|
||||||
|
abstract visit(visitor: RenderCommandVisitor, context: any): any;
|
||||||
export interface RenderBeginCmd extends RenderTemplateCmd {
|
|
||||||
ngContentIndex: number;
|
|
||||||
isBound: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// The index of this NgContent element
|
||||||
index: number;
|
get index(): number { return unimplemented(); };
|
||||||
// The index of the NgContent element into which this
|
// The index of the NgContent element into which this
|
||||||
// NgContent element should be projected (if any)
|
// NgContent element should be projected (if any)
|
||||||
ngContentIndex: number;
|
get ngContentIndex(): number { return unimplemented(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RenderBeginElementCmd extends RenderBeginCmd {
|
export abstract class RenderBeginElementCmd extends RenderBeginCmd {
|
||||||
name: string;
|
get name(): string { return unimplemented(); };
|
||||||
attrNameAndValues: string[];
|
get attrNameAndValues(): string[] { return unimplemented(); };
|
||||||
eventTargetAndNames: string[];
|
get eventTargetAndNames(): string[] { return unimplemented(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RenderBeginComponentCmd extends RenderBeginElementCmd {
|
export abstract class RenderBeginComponentCmd extends RenderBeginElementCmd {
|
||||||
nativeShadow: boolean;
|
get templateId(): string { return unimplemented(); };
|
||||||
templateId: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RenderEmbeddedTemplateCmd extends RenderBeginElementCmd {
|
export abstract class RenderEmbeddedTemplateCmd extends RenderBeginElementCmd {
|
||||||
isMerged: boolean;
|
get isMerged(): boolean { return unimplemented(); };
|
||||||
children: RenderTemplateCmd[];
|
get children(): RenderTemplateCmd[] { return unimplemented(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RenderCommandVisitor {
|
export interface RenderCommandVisitor {
|
||||||
|
@ -156,6 +161,10 @@ export interface RenderElementRef {
|
||||||
boundElementIndex: number;
|
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.
|
* 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
|
* Once a template is registered it can be referenced via {@link RenderBeginComponentCmd} when
|
||||||
* {@link #createProtoView creating Render ProtoView}.
|
* {@link #createProtoView creating Render ProtoView}.
|
||||||
*/
|
*/
|
||||||
abstract registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[],
|
abstract registerComponentTemplate(template: RenderComponentTemplate);
|
||||||
styles: string[], nativeShadow: boolean);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link RenderProtoViewRef} from an array of {@link RenderTemplateCmd}`s.
|
* 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`.
|
* Creates a Root Host View based on the provided `hostProtoViewRef`.
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
import {Inject, Injectable, OpaqueToken} from 'angular2/src/core/di';
|
import {Inject, Injectable, OpaqueToken} from 'angular2/src/core/di';
|
||||||
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
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 {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||||
|
|
||||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
|
@ -18,13 +25,15 @@ import {
|
||||||
RenderFragmentRef,
|
RenderFragmentRef,
|
||||||
RenderViewWithFragments,
|
RenderViewWithFragments,
|
||||||
RenderTemplateCmd,
|
RenderTemplateCmd,
|
||||||
RenderEventDispatcher
|
RenderEventDispatcher,
|
||||||
|
RenderComponentTemplate
|
||||||
} from '../api';
|
} from '../api';
|
||||||
|
|
||||||
import {DOCUMENT} from './dom_tokens';
|
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 {DefaultRenderView, DefaultRenderFragmentRef, DefaultProtoViewRef} from '../view';
|
||||||
import {camelCaseToDashCase} from './util';
|
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
|
// TODO(tbosch): solve SVG properly once https://github.com/angular/angular/issues/4417 is done
|
||||||
const XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink';
|
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});
|
const SVG_ATTR_NAMESPACES = CONST_EXPR({'href': XLINK_NAMESPACE, 'xlink:href': XLINK_NAMESPACE});
|
||||||
|
|
||||||
export abstract class DomRenderer extends Renderer implements NodeFactory<Node> {
|
export abstract class DomRenderer extends Renderer implements NodeFactory<Node> {
|
||||||
abstract registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[],
|
abstract registerComponentTemplate(template: RenderComponentTemplate);
|
||||||
styles: string[], nativeShadow: boolean);
|
|
||||||
|
|
||||||
abstract resolveComponentTemplate(templateId: number): RenderTemplateCmd[];
|
abstract resolveComponentTemplate(templateId: string): RenderComponentTemplate;
|
||||||
|
|
||||||
createProtoView(cmds: RenderTemplateCmd[]): RenderProtoViewRef {
|
abstract createProtoView(componentTemplateId: string,
|
||||||
return new DefaultProtoViewRef(cmds);
|
cmds: RenderTemplateCmd[]): RenderProtoViewRef;
|
||||||
}
|
|
||||||
|
|
||||||
abstract createRootHostView(hostProtoViewRef: RenderProtoViewRef, fragmentCount: number,
|
abstract createRootHostView(hostProtoViewRef: RenderProtoViewRef, fragmentCount: number,
|
||||||
hostElementSelector: string): RenderViewWithFragments;
|
hostElementSelector: string): RenderViewWithFragments;
|
||||||
|
@ -189,7 +196,7 @@ export abstract class DomRenderer extends Renderer implements NodeFactory<Node>
|
||||||
}
|
}
|
||||||
abstract createElement(name: string, attrNameAndValues: string[]): Node;
|
abstract createElement(name: string, attrNameAndValues: string[]): Node;
|
||||||
abstract mergeElement(existing: Node, attrNameAndValues: string[]);
|
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 : ''); }
|
createText(value: string): Node { return DOM.createTextNode(isPresent(value) ? value : ''); }
|
||||||
appendChild(parent: Node, child: Node) { DOM.appendChild(parent, child); }
|
appendChild(parent: Node, child: Node) { DOM.appendChild(parent, child); }
|
||||||
abstract on(element: Node, eventName: string, callback: Function);
|
abstract on(element: Node, eventName: string, callback: Function);
|
||||||
|
@ -252,8 +259,8 @@ export abstract class DomRenderer extends Renderer implements NodeFactory<Node>
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DomRenderer_ extends DomRenderer {
|
export class DomRenderer_ extends DomRenderer {
|
||||||
private _componentCmds: Map<number, RenderTemplateCmd[]> = new Map<number, RenderTemplateCmd[]>();
|
private _componentTpls: Map<string, RenderComponentTemplate> =
|
||||||
private _nativeShadowStyles: Map<number, string[]> = new Map<number, string[]>();
|
new Map<string, RenderComponentTemplate>();
|
||||||
private _document;
|
private _document;
|
||||||
|
|
||||||
constructor(private _eventManager: EventManager,
|
constructor(private _eventManager: EventManager,
|
||||||
|
@ -263,18 +270,20 @@ export class DomRenderer_ extends DomRenderer {
|
||||||
this._document = document;
|
this._document = document;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[],
|
registerComponentTemplate(template: RenderComponentTemplate) {
|
||||||
nativeShadow: boolean) {
|
this._componentTpls.set(template.id, template);
|
||||||
this._componentCmds.set(templateId, commands);
|
if (template.encapsulation !== ViewEncapsulation.Native) {
|
||||||
if (nativeShadow) {
|
var encapsulatedStyles = encapsulateStyles(template);
|
||||||
this._nativeShadowStyles.set(templateId, styles);
|
this._domSharedStylesHost.addStyles(encapsulatedStyles);
|
||||||
} else {
|
|
||||||
this._domSharedStylesHost.addStyles(styles);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveComponentTemplate(templateId: number): RenderTemplateCmd[] {
|
createProtoView(componentTemplateId: string, cmds: RenderTemplateCmd[]): RenderProtoViewRef {
|
||||||
return this._componentCmds.get(templateId);
|
return new DefaultProtoViewRef(this._componentTpls.get(componentTemplateId), cmds);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveComponentTemplate(templateId: string): RenderComponentTemplate {
|
||||||
|
return this._componentTpls.get(templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
@ -299,7 +308,8 @@ export class DomRenderer_ extends DomRenderer {
|
||||||
|
|
||||||
private _createView(protoViewRef: RenderProtoViewRef,
|
private _createView(protoViewRef: RenderProtoViewRef,
|
||||||
inplaceElement: HTMLElement): RenderViewWithFragments {
|
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;
|
var sdRoots = view.nativeShadowRoots;
|
||||||
for (var i = 0; i < sdRoots.length; i++) {
|
for (var i = 0; i < sdRoots.length; i++) {
|
||||||
this._domSharedStylesHost.addHost(sdRoots[i]);
|
this._domSharedStylesHost.addHost(sdRoots[i]);
|
||||||
|
@ -375,11 +385,11 @@ export class DomRenderer_ extends DomRenderer {
|
||||||
createRootContentInsertionPoint(): Node {
|
createRootContentInsertionPoint(): Node {
|
||||||
return DOM.createComment('root-content-insertion-point');
|
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 sr = DOM.createShadowRoot(host);
|
||||||
var styles = this._nativeShadowStyles.get(templateId);
|
var tpl = this._componentTpls.get(templateId);
|
||||||
for (var i = 0; i < styles.length; i++) {
|
for (var i = 0; i < tpl.styles.length; i++) {
|
||||||
DOM.appendChild(sr, DOM.createStyleElement(styles[i]));
|
DOM.appendChild(sr, DOM.createStyleElement(tpl.styles[i]));
|
||||||
}
|
}
|
||||||
return sr;
|
return sr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {ListWrapper, MapWrapper, Map, StringMapWrapper} from 'angular2/src/facad
|
||||||
import {isPresent, isBlank, stringify} from 'angular2/src/facade/lang';
|
import {isPresent, isBlank, stringify} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
RenderComponentTemplate,
|
||||||
RenderViewRef,
|
RenderViewRef,
|
||||||
RenderEventDispatcher,
|
RenderEventDispatcher,
|
||||||
RenderTemplateCmd,
|
RenderTemplateCmd,
|
||||||
|
@ -11,7 +12,9 @@ import {
|
||||||
} from './api';
|
} from './api';
|
||||||
|
|
||||||
export class DefaultProtoViewRef extends RenderProtoViewRef {
|
export class DefaultProtoViewRef extends RenderProtoViewRef {
|
||||||
constructor(public cmds: RenderTemplateCmd[]) { super(); }
|
constructor(public template: RenderComponentTemplate, public cmds: RenderTemplateCmd[]) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DefaultRenderFragmentRef<N> extends RenderFragmentRef {
|
export class DefaultRenderFragmentRef<N> extends RenderFragmentRef {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
import {isBlank, isPresent, StringWrapper} from 'angular2/src/facade/lang';
|
||||||
import {
|
import {
|
||||||
RenderEventDispatcher,
|
RenderEventDispatcher,
|
||||||
RenderTemplateCmd,
|
RenderTemplateCmd,
|
||||||
|
@ -7,17 +7,34 @@ import {
|
||||||
RenderBeginComponentCmd,
|
RenderBeginComponentCmd,
|
||||||
RenderNgContentCmd,
|
RenderNgContentCmd,
|
||||||
RenderTextCmd,
|
RenderTextCmd,
|
||||||
RenderEmbeddedTemplateCmd
|
RenderEmbeddedTemplateCmd,
|
||||||
|
RenderComponentTemplate
|
||||||
} from './api';
|
} from './api';
|
||||||
import {DefaultRenderView, DefaultRenderFragmentRef} from './view';
|
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> {
|
nodeFactory: NodeFactory<any>): DefaultRenderView<any> {
|
||||||
var view: DefaultRenderView<any>;
|
var view: DefaultRenderView<any>;
|
||||||
var eventDispatcher = (boundElementIndex: number, eventName: string, event: any) =>
|
var eventDispatcher = (boundElementIndex: number, eventName: string, event: any) =>
|
||||||
view.dispatchRenderEvent(boundElementIndex, eventName, event);
|
view.dispatchRenderEvent(boundElementIndex, eventName, event);
|
||||||
var context = new BuildContext(eventDispatcher, nodeFactory, inplaceElement);
|
var context = new BuildContext(eventDispatcher, nodeFactory, inplaceElement);
|
||||||
context.build(fragmentCmds);
|
context.build(componentTemplate, cmds);
|
||||||
var fragments: DefaultRenderFragmentRef<any>[] = [];
|
var fragments: DefaultRenderFragmentRef<any>[] = [];
|
||||||
for (var i = 0; i < context.fragments.length; i++) {
|
for (var i = 0; i < context.fragments.length; i++) {
|
||||||
fragments.push(new DefaultRenderFragmentRef(context.fragments[i]));
|
fragments.push(new DefaultRenderFragmentRef(context.fragments[i]));
|
||||||
|
@ -29,12 +46,12 @@ export function createRenderView(fragmentCmds: RenderTemplateCmd[], inplaceEleme
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NodeFactory<N> {
|
export interface NodeFactory<N> {
|
||||||
resolveComponentTemplate(templateId: number): RenderTemplateCmd[];
|
resolveComponentTemplate(templateId: string): RenderComponentTemplate;
|
||||||
createTemplateAnchor(attrNameAndValues: string[]): N;
|
createTemplateAnchor(attrNameAndValues: string[]): N;
|
||||||
createElement(name: string, attrNameAndValues: string[]): N;
|
createElement(name: string, attrNameAndValues: string[]): N;
|
||||||
createRootContentInsertionPoint(): N;
|
createRootContentInsertionPoint(): N;
|
||||||
mergeElement(existing: N, attrNameAndValues: string[]);
|
mergeElement(existing: N, attrNameAndValues: string[]);
|
||||||
createShadowRoot(host: N, templateId: number): N;
|
createShadowRoot(host: N, templateId: string): N;
|
||||||
createText(value: string): N;
|
createText(value: string): N;
|
||||||
appendChild(parent: N, child: N);
|
appendChild(parent: N, child: N);
|
||||||
on(element: N, eventName: string, callback: Function);
|
on(element: N, eventName: string, callback: Function);
|
||||||
|
@ -57,8 +74,8 @@ class BuildContext<N> {
|
||||||
componentCount: number = 0;
|
componentCount: number = 0;
|
||||||
isHost: boolean;
|
isHost: boolean;
|
||||||
|
|
||||||
build(fragmentCmds: RenderTemplateCmd[]) {
|
build(template: RenderComponentTemplate, cmds: RenderTemplateCmd[]) {
|
||||||
this.enqueueFragmentBuilder(null, fragmentCmds);
|
this.enqueueRootBuilder(template, cmds);
|
||||||
this._build(this._builders[0]);
|
this._build(this._builders[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,14 +90,22 @@ class BuildContext<N> {
|
||||||
|
|
||||||
enqueueComponentBuilder(component: Component<N>) {
|
enqueueComponentBuilder(component: Component<N>) {
|
||||||
this.componentCount++;
|
this.componentCount++;
|
||||||
this._builders.push(new RenderViewBuilder<N>(
|
this._builders.push(
|
||||||
component, null, this.factory.resolveComponentTemplate(component.cmd.templateId)));
|
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 = [];
|
var rootNodes = [];
|
||||||
this.fragments.push(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 {
|
consumeInplaceElement(): N {
|
||||||
|
@ -116,14 +141,15 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
|
||||||
parentStack: Array<N | Component<N>>;
|
parentStack: Array<N | Component<N>>;
|
||||||
|
|
||||||
constructor(public parentComponent: Component<N>, public fragmentRootNodes: 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;
|
var rootNodesParent = isPresent(fragmentRootNodes) ? null : parentComponent.shadowRoot;
|
||||||
this.parentStack = [rootNodesParent];
|
this.parentStack = [rootNodesParent];
|
||||||
}
|
}
|
||||||
|
|
||||||
build(context: BuildContext<N>) {
|
build(context: BuildContext<N>) {
|
||||||
for (var i = 0; i < this.commands.length; i++) {
|
var cmds = this.cmds;
|
||||||
this.commands[i].visit(this, context);
|
for (var i = 0; i < cmds.length; i++) {
|
||||||
|
cmds[i].visit(this, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +184,7 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
visitBeginElement(cmd: RenderBeginElementCmd, context: BuildContext<N>): any {
|
visitBeginElement(cmd: RenderBeginElementCmd, context: BuildContext<N>): any {
|
||||||
this.parentStack.push(this._beginElement(cmd, context));
|
this.parentStack.push(this._beginElement(cmd, context, null));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
visitEndElement(context: BuildContext<N>): any {
|
visitEndElement(context: BuildContext<N>): any {
|
||||||
|
@ -166,14 +192,17 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
visitBeginComponent(cmd: RenderBeginComponentCmd, context: BuildContext<N>): any {
|
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;
|
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);
|
context.nativeShadowRoots.push(root);
|
||||||
}
|
}
|
||||||
var isRoot = context.componentCount === 0 && context.isHost;
|
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);
|
context.enqueueComponentBuilder(component);
|
||||||
this.parentStack.push(component);
|
this.parentStack.push(component);
|
||||||
return null;
|
return null;
|
||||||
|
@ -187,18 +216,34 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
|
||||||
this._addChild(el, cmd.ngContentIndex, context);
|
this._addChild(el, cmd.ngContentIndex, context);
|
||||||
context.boundElements.push(el);
|
context.boundElements.push(el);
|
||||||
if (cmd.isMerged) {
|
if (cmd.isMerged) {
|
||||||
context.enqueueFragmentBuilder(this.parentComponent, cmd.children);
|
context.enqueueFragmentBuilder(this.parentComponent, this.template, cmd.children);
|
||||||
}
|
}
|
||||||
return null;
|
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 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)) {
|
if (isPresent(el)) {
|
||||||
context.factory.mergeElement(el, cmd.attrNameAndValues);
|
context.factory.mergeElement(el, attrNameAndValues);
|
||||||
this.fragmentRootNodes.push(el);
|
this.fragmentRootNodes.push(el);
|
||||||
} else {
|
} else {
|
||||||
el = context.factory.createElement(cmd.name, cmd.attrNameAndValues);
|
el = context.factory.createElement(cmd.name, attrNameAndValues);
|
||||||
this._addChild(el, cmd.ngContentIndex, context);
|
this._addChild(el, cmd.ngContentIndex, context);
|
||||||
}
|
}
|
||||||
if (cmd.isBound) {
|
if (cmd.isBound) {
|
||||||
|
@ -232,11 +277,11 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
|
||||||
class Component<N> {
|
class Component<N> {
|
||||||
private contentNodesByNgContentIndex: N[][] = [];
|
private contentNodesByNgContentIndex: N[][] = [];
|
||||||
|
|
||||||
constructor(public hostElement: N, public shadowRoot: N, public cmd: RenderBeginComponentCmd,
|
constructor(public hostElement: N, public shadowRoot: N, public isRoot: boolean,
|
||||||
public isRoot: boolean) {}
|
public template: RenderComponentTemplate) {}
|
||||||
addContentNode(ngContentIndex: number, node: N, context: BuildContext<N>) {
|
addContentNode(ngContentIndex: number, node: N, context: BuildContext<N>) {
|
||||||
if (isBlank(ngContentIndex)) {
|
if (isBlank(ngContentIndex)) {
|
||||||
if (this.cmd.nativeShadow) {
|
if (this.template.encapsulation === ViewEncapsulation.Native) {
|
||||||
context.factory.appendChild(this.hostElement, node);
|
context.factory.appendChild(this.hostElement, node);
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
||||||
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ export class WebWorkerEndElementCmd implements RenderTemplateCmd {
|
||||||
export class WebWorkerBeginComponentCmd implements RenderBeginComponentCmd {
|
export class WebWorkerBeginComponentCmd implements RenderBeginComponentCmd {
|
||||||
constructor(public isBound: boolean, public ngContentIndex: number, public name: string,
|
constructor(public isBound: boolean, public ngContentIndex: number, public name: string,
|
||||||
public attrNameAndValues: string[], public eventTargetAndNames: string[],
|
public attrNameAndValues: string[], public eventTargetAndNames: string[],
|
||||||
public nativeShadow: boolean, public templateId: number) {}
|
public templateId: string) {}
|
||||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
return visitor.visitBeginComponent(this, context);
|
return visitor.visitBeginComponent(this, context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ import {
|
||||||
RenderNgContentCmd,
|
RenderNgContentCmd,
|
||||||
RenderBeginElementCmd,
|
RenderBeginElementCmd,
|
||||||
RenderBeginComponentCmd,
|
RenderBeginComponentCmd,
|
||||||
RenderEmbeddedTemplateCmd
|
RenderEmbeddedTemplateCmd,
|
||||||
|
RenderComponentTemplate
|
||||||
} from "angular2/src/core/render/api";
|
} from "angular2/src/core/render/api";
|
||||||
import {
|
import {
|
||||||
WebWorkerElementRef,
|
WebWorkerElementRef,
|
||||||
|
@ -31,6 +32,7 @@ import {RenderProtoViewRefStore} from 'angular2/src/web_workers/shared/render_pr
|
||||||
import {
|
import {
|
||||||
RenderViewWithFragmentsStore
|
RenderViewWithFragmentsStore
|
||||||
} from 'angular2/src/web_workers/shared/render_view_with_fragments_store';
|
} 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)
|
// 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.
|
// We set it to String so that it is considered a Type.
|
||||||
|
@ -41,7 +43,7 @@ export class Serializer {
|
||||||
constructor(private _protoViewStore: RenderProtoViewRefStore,
|
constructor(private _protoViewStore: RenderProtoViewRefStore,
|
||||||
private _renderViewStore: RenderViewWithFragmentsStore) {}
|
private _renderViewStore: RenderViewWithFragmentsStore) {}
|
||||||
|
|
||||||
serialize(obj: any, type: Type): Object {
|
serialize(obj: any, type: any): Object {
|
||||||
if (!isPresent(obj)) {
|
if (!isPresent(obj)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -61,12 +63,16 @@ export class Serializer {
|
||||||
return this._serializeWorkerElementRef(obj);
|
return this._serializeWorkerElementRef(obj);
|
||||||
} else if (type == WebWorkerTemplateCmd) {
|
} else if (type == WebWorkerTemplateCmd) {
|
||||||
return serializeTemplateCmd(obj);
|
return serializeTemplateCmd(obj);
|
||||||
|
} else if (type === RenderComponentTemplate) {
|
||||||
|
return this._serializeRenderTemplate(obj);
|
||||||
|
} else if (type === ViewEncapsulation) {
|
||||||
|
return serializeEnum(obj);
|
||||||
} else {
|
} else {
|
||||||
throw new BaseException("No serializer for " + type.toString());
|
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)) {
|
if (!isPresent(map)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -89,6 +95,10 @@ export class Serializer {
|
||||||
return this._deserializeWorkerElementRef(map);
|
return this._deserializeWorkerElementRef(map);
|
||||||
} else if (type == WebWorkerTemplateCmd) {
|
} else if (type == WebWorkerTemplateCmd) {
|
||||||
return deserializeTemplateCmd(map);
|
return deserializeTemplateCmd(map);
|
||||||
|
} else if (type === RenderComponentTemplate) {
|
||||||
|
return this._deserializeRenderTemplate(map);
|
||||||
|
} else if (type === ViewEncapsulation) {
|
||||||
|
return VIEW_ENCAPSULATION_VALUES[map];
|
||||||
} else {
|
} else {
|
||||||
throw new BaseException("No deserializer for " + type.toString());
|
throw new BaseException("No deserializer for " + type.toString());
|
||||||
}
|
}
|
||||||
|
@ -137,8 +147,27 @@ export class Serializer {
|
||||||
return new WebWorkerElementRef(this.deserialize(map['renderView'], RenderViewRef),
|
return new WebWorkerElementRef(this.deserialize(map['renderView'], RenderViewRef),
|
||||||
map['boundElementIndex']);
|
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 {
|
function serializeTemplateCmd(cmd: RenderTemplateCmd): Object {
|
||||||
return cmd.visit(RENDER_TEMPLATE_CMD_SERIALIZER, null);
|
return cmd.visit(RENDER_TEMPLATE_CMD_SERIALIZER, null);
|
||||||
}
|
}
|
||||||
|
@ -178,7 +207,6 @@ class RenderTemplateCmdSerializer implements RenderCommandVisitor {
|
||||||
'name': cmd.name,
|
'name': cmd.name,
|
||||||
'attrNameAndValues': cmd.attrNameAndValues,
|
'attrNameAndValues': cmd.attrNameAndValues,
|
||||||
'eventTargetAndNames': cmd.eventTargetAndNames,
|
'eventTargetAndNames': cmd.eventTargetAndNames,
|
||||||
'nativeShadow': cmd.nativeShadow,
|
|
||||||
'templateId': cmd.templateId
|
'templateId': cmd.templateId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -210,7 +238,7 @@ var RENDER_TEMPLATE_CMD_DESERIALIZERS = [
|
||||||
(data: {[key: string]: any}) => new WebWorkerEndElementCmd(),
|
(data: {[key: string]: any}) => new WebWorkerEndElementCmd(),
|
||||||
(data: {[key: string]: any}) => new WebWorkerBeginComponentCmd(
|
(data: {[key: string]: any}) => new WebWorkerBeginComponentCmd(
|
||||||
data['isBound'], data['ngContentIndex'], data['name'], data['attrNameAndValues'],
|
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 WebWorkerEndComponentCmd(),
|
||||||
(data: {[key: string]: any}) => new WebWorkerEmbeddedTemplateCmd(
|
(data: {[key: string]: any}) => new WebWorkerEmbeddedTemplateCmd(
|
||||||
data['isBound'], data['ngContentIndex'], data['name'], data['attrNameAndValues'],
|
data['isBound'], data['ngContentIndex'], data['name'], data['attrNameAndValues'],
|
||||||
|
|
|
@ -6,7 +6,8 @@ import {
|
||||||
RenderFragmentRef,
|
RenderFragmentRef,
|
||||||
RenderProtoViewRef,
|
RenderProtoViewRef,
|
||||||
Renderer,
|
Renderer,
|
||||||
RenderTemplateCmd
|
RenderTemplateCmd,
|
||||||
|
RenderComponentTemplate
|
||||||
} from 'angular2/src/core/render/api';
|
} from 'angular2/src/core/render/api';
|
||||||
import {WebWorkerElementRef, WebWorkerTemplateCmd} from 'angular2/src/web_workers/shared/api';
|
import {WebWorkerElementRef, WebWorkerTemplateCmd} from 'angular2/src/web_workers/shared/api';
|
||||||
import {EVENT_CHANNEL, RENDERER_CHANNEL} from 'angular2/src/web_workers/shared/messaging_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);
|
var broker = this._brokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
||||||
this._bus.initChannel(EVENT_CHANNEL);
|
this._bus.initChannel(EVENT_CHANNEL);
|
||||||
|
|
||||||
broker.registerMethod("registerComponentTemplate",
|
broker.registerMethod("registerComponentTemplate", [RenderComponentTemplate],
|
||||||
[PRIMITIVE, WebWorkerTemplateCmd, PRIMITIVE, PRIMITIVE],
|
|
||||||
bind(this._renderer.registerComponentTemplate, this._renderer));
|
bind(this._renderer.registerComponentTemplate, this._renderer));
|
||||||
broker.registerMethod("createProtoView", [WebWorkerTemplateCmd, PRIMITIVE],
|
broker.registerMethod("createProtoView", [PRIMITIVE, WebWorkerTemplateCmd, PRIMITIVE],
|
||||||
bind(this._createProtoView, this));
|
bind(this._createProtoView, this));
|
||||||
broker.registerMethod("createRootHostView",
|
broker.registerMethod("createRootHostView",
|
||||||
[RenderProtoViewRef, PRIMITIVE, PRIMITIVE, PRIMITIVE],
|
[RenderProtoViewRef, PRIMITIVE, PRIMITIVE, PRIMITIVE],
|
||||||
|
@ -73,8 +73,9 @@ export class MessageBasedRenderer {
|
||||||
this._renderViewWithFragmentsStore.remove(viewRef);
|
this._renderViewWithFragmentsStore.remove(viewRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createProtoView(cmds: RenderTemplateCmd[], refIndex: number) {
|
private _createProtoView(componentTemplateId: string, cmds: RenderTemplateCmd[],
|
||||||
var protoViewRef = this._renderer.createProtoView(cmds);
|
refIndex: number) {
|
||||||
|
var protoViewRef = this._renderer.createProtoView(componentTemplateId, cmds);
|
||||||
this._renderProtoViewRefStore.store(protoViewRef, refIndex);
|
this._renderProtoViewRefStore.store(protoViewRef, refIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ import {
|
||||||
RenderEventDispatcher,
|
RenderEventDispatcher,
|
||||||
RenderViewWithFragments,
|
RenderViewWithFragments,
|
||||||
RenderFragmentRef,
|
RenderFragmentRef,
|
||||||
RenderTemplateCmd
|
RenderTemplateCmd,
|
||||||
|
RenderComponentTemplate
|
||||||
} from 'angular2/src/core/render/api';
|
} from 'angular2/src/core/render/api';
|
||||||
import {
|
import {
|
||||||
ClientMessageBroker,
|
ClientMessageBroker,
|
||||||
|
@ -35,23 +36,20 @@ export class WebWorkerRenderer implements Renderer {
|
||||||
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[],
|
registerComponentTemplate(template: RenderComponentTemplate) {
|
||||||
nativeShadow: boolean) {
|
var fnArgs = [new FnArg(template, RenderComponentTemplate)];
|
||||||
var fnArgs = [
|
|
||||||
new FnArg(templateId, null),
|
|
||||||
new FnArg(commands, WebWorkerTemplateCmd),
|
|
||||||
new FnArg(styles, null),
|
|
||||||
new FnArg(nativeShadow, null)
|
|
||||||
];
|
|
||||||
var args = new UiArguments("registerComponentTemplate", fnArgs);
|
var args = new UiArguments("registerComponentTemplate", fnArgs);
|
||||||
this._messageBroker.runOnService(args, null);
|
this._messageBroker.runOnService(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
createProtoView(cmds: RenderTemplateCmd[]): RenderProtoViewRef {
|
createProtoView(componentTemplateId: string, cmds: RenderTemplateCmd[]): RenderProtoViewRef {
|
||||||
var renderProtoViewRef = this._renderProtoViewRefStore.allocate();
|
var renderProtoViewRef = this._renderProtoViewRefStore.allocate();
|
||||||
|
|
||||||
var fnArgs: FnArg[] =
|
var fnArgs: FnArg[] = [
|
||||||
[new FnArg(cmds, WebWorkerTemplateCmd), new FnArg(renderProtoViewRef, RenderProtoViewRef)];
|
new FnArg(componentTemplateId, null),
|
||||||
|
new FnArg(cmds, WebWorkerTemplateCmd),
|
||||||
|
new FnArg(renderProtoViewRef, RenderProtoViewRef)
|
||||||
|
];
|
||||||
var args: UiArguments = new UiArguments("createProtoView", fnArgs);
|
var args: UiArguments = new UiArguments("createProtoView", fnArgs);
|
||||||
this._messageBroker.runOnService(args, null);
|
this._messageBroker.runOnService(args, null);
|
||||||
return renderProtoViewRef;
|
return renderProtoViewRef;
|
||||||
|
|
|
@ -134,7 +134,8 @@ function createTestableModule(source: SourceExpressions,
|
||||||
var resultExpression =
|
var resultExpression =
|
||||||
`${THIS_MODULE_REF}testChangeDetector(([${source.expressions.join(',')}])[${changeDetectorIndex}])`;
|
`${THIS_MODULE_REF}testChangeDetector(([${source.expressions.join(',')}])[${changeDetectorIndex}])`;
|
||||||
var testableSource = `${source.declarations.join('\n')}
|
var testableSource = `${source.declarations.join('\n')}
|
||||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], resultExpression)};`;
|
${codeGenValueFn(['_'], resultExpression, '_run')};
|
||||||
|
${codeGenExportVariable('run')}_run;`;
|
||||||
return new SourceModule(null, testableSource);
|
return new SourceModule(null, testableSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,15 @@ import {
|
||||||
beforeEachBindings
|
beforeEachBindings
|
||||||
} from 'angular2/testing_internal';
|
} from 'angular2/testing_internal';
|
||||||
|
|
||||||
import {CONST_EXPR, stringify, isType, Type, isBlank} from 'angular2/src/facade/lang';
|
import {
|
||||||
|
CONST_EXPR,
|
||||||
|
stringify,
|
||||||
|
isType,
|
||||||
|
Type,
|
||||||
|
isBlank,
|
||||||
|
serializeEnum,
|
||||||
|
IS_DART
|
||||||
|
} from 'angular2/src/facade/lang';
|
||||||
import {MapWrapper} from 'angular2/src/facade/collection';
|
import {MapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
import {TemplateParser} from 'angular2/src/compiler/template_parser';
|
import {TemplateParser} from 'angular2/src/compiler/template_parser';
|
||||||
|
@ -26,7 +34,7 @@ import {
|
||||||
EmbeddedTemplateCmd,
|
EmbeddedTemplateCmd,
|
||||||
TemplateCmd,
|
TemplateCmd,
|
||||||
visitAllCommands,
|
visitAllCommands,
|
||||||
CompiledTemplate
|
CompiledComponentTemplate
|
||||||
} from 'angular2/src/core/linker/template_commands';
|
} from 'angular2/src/core/linker/template_commands';
|
||||||
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
|
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
|
||||||
import {
|
import {
|
||||||
|
@ -41,6 +49,7 @@ import {
|
||||||
escapeSingleQuoteString,
|
escapeSingleQuoteString,
|
||||||
codeGenValueFn,
|
codeGenValueFn,
|
||||||
codeGenExportVariable,
|
codeGenExportVariable,
|
||||||
|
codeGenConstConstructorCall,
|
||||||
MODULE_SUFFIX
|
MODULE_SUFFIX
|
||||||
} from 'angular2/src/compiler/util';
|
} from 'angular2/src/compiler/util';
|
||||||
import {TEST_PROVIDERS} from './test_bindings';
|
import {TEST_PROVIDERS} from './test_bindings';
|
||||||
|
@ -70,11 +79,8 @@ var SomeDirTypeMeta =
|
||||||
new CompileTypeMetadata({name: 'SomeDir', runtime: SomeDir, moduleUrl: THIS_MODULE_URL});
|
new CompileTypeMetadata({name: 'SomeDir', runtime: SomeDir, moduleUrl: THIS_MODULE_URL});
|
||||||
var ACompTypeMeta =
|
var ACompTypeMeta =
|
||||||
new CompileTypeMetadata({name: 'AComp', runtime: AComp, moduleUrl: THIS_MODULE_URL});
|
new CompileTypeMetadata({name: 'AComp', runtime: AComp, moduleUrl: THIS_MODULE_URL});
|
||||||
var compTypeTemplateId: Map<CompileTypeMetadata, number> =
|
var compTypeTemplateId: Map<CompileTypeMetadata, string> = MapWrapper.createFromPairs(
|
||||||
MapWrapper.createFromPairs([[RootCompTypeMeta, 1], [SomeDirTypeMeta, 2], [ACompTypeMeta, 3]]);
|
[[RootCompTypeMeta, 'rootCompId'], [SomeDirTypeMeta, 'someDirId'], [ACompTypeMeta, 'aCompId']]);
|
||||||
const APP_ID = 'app1';
|
|
||||||
|
|
||||||
var NESTED_COMPONENT = new CompiledTemplate(45, () => []);
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('CommandCompiler', () => {
|
describe('CommandCompiler', () => {
|
||||||
|
@ -260,22 +266,6 @@ export function main() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should emulate style encapsulation', inject([AsyncTestCompleter], (async) => {
|
|
||||||
var rootComp = createComp({
|
|
||||||
type: RootCompTypeMeta,
|
|
||||||
template: '<div>',
|
|
||||||
encapsulation: ViewEncapsulation.Emulated
|
|
||||||
});
|
|
||||||
run(rootComp, [])
|
|
||||||
.then((data) => {
|
|
||||||
expect(data).toEqual([
|
|
||||||
[BEGIN_ELEMENT, 'div', ['_ngcontent-app1-1', ''], [], [], [], false, null],
|
|
||||||
[END_ELEMENT]
|
|
||||||
]);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should create nested nodes', inject([AsyncTestCompleter], (async) => {
|
it('should create nested nodes', inject([AsyncTestCompleter], (async) => {
|
||||||
var rootComp = createComp({type: RootCompTypeMeta, template: '<div>a</div>'});
|
var rootComp = createComp({type: RootCompTypeMeta, template: '<div>a</div>'});
|
||||||
run(rootComp, [])
|
run(rootComp, [])
|
||||||
|
@ -306,9 +296,9 @@ export function main() {
|
||||||
[null, 'click'],
|
[null, 'click'],
|
||||||
['someVar', 0],
|
['someVar', 0],
|
||||||
['ACompType'],
|
['ACompType'],
|
||||||
false,
|
serializeEnum(ViewEncapsulation.None),
|
||||||
null,
|
null,
|
||||||
3
|
'aCompId'
|
||||||
],
|
],
|
||||||
[END_COMPONENT]
|
[END_COMPONENT]
|
||||||
]);
|
]);
|
||||||
|
@ -316,43 +306,24 @@ export function main() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should emulate style encapsulation on host elements',
|
it('should store viewEncapsulation', inject([AsyncTestCompleter], (async) => {
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
var rootComp = createComp({
|
|
||||||
type: RootCompTypeMeta,
|
|
||||||
template: '<a></a>',
|
|
||||||
encapsulation: ViewEncapsulation.Emulated
|
|
||||||
});
|
|
||||||
var comp = createComp(
|
|
||||||
{type: ACompTypeMeta, selector: 'a', encapsulation: ViewEncapsulation.Emulated});
|
|
||||||
run(rootComp, [comp])
|
|
||||||
.then((data) => {
|
|
||||||
expect(data).toEqual([
|
|
||||||
[
|
|
||||||
BEGIN_COMPONENT,
|
|
||||||
'a',
|
|
||||||
['_nghost-app1-3', '', '_ngcontent-app1-1', ''],
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
['ACompType'],
|
|
||||||
false,
|
|
||||||
null,
|
|
||||||
3
|
|
||||||
],
|
|
||||||
[END_COMPONENT]
|
|
||||||
]);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set nativeShadow flag', inject([AsyncTestCompleter], (async) => {
|
|
||||||
var rootComp = createComp({type: RootCompTypeMeta, template: '<a></a>'});
|
var rootComp = createComp({type: RootCompTypeMeta, template: '<a></a>'});
|
||||||
var comp = createComp(
|
var comp = createComp(
|
||||||
{type: ACompTypeMeta, selector: 'a', encapsulation: ViewEncapsulation.Native});
|
{type: ACompTypeMeta, selector: 'a', encapsulation: ViewEncapsulation.Native});
|
||||||
run(rootComp, [comp])
|
run(rootComp, [comp])
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
expect(data).toEqual([
|
expect(data).toEqual([
|
||||||
[BEGIN_COMPONENT, 'a', [], [], [], ['ACompType'], true, null, 3],
|
[
|
||||||
|
BEGIN_COMPONENT,
|
||||||
|
'a',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
['ACompType'],
|
||||||
|
serializeEnum(ViewEncapsulation.Native),
|
||||||
|
null,
|
||||||
|
'aCompId'
|
||||||
|
],
|
||||||
[END_COMPONENT]
|
[END_COMPONENT]
|
||||||
]);
|
]);
|
||||||
async.done();
|
async.done();
|
||||||
|
@ -366,7 +337,17 @@ export function main() {
|
||||||
run(rootComp, [comp])
|
run(rootComp, [comp])
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
expect(data).toEqual([
|
expect(data).toEqual([
|
||||||
[BEGIN_COMPONENT, 'a', [], [], [], ['ACompType'], false, null, 3],
|
[
|
||||||
|
BEGIN_COMPONENT,
|
||||||
|
'a',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
['ACompType'],
|
||||||
|
serializeEnum(ViewEncapsulation.None),
|
||||||
|
null,
|
||||||
|
'aCompId'
|
||||||
|
],
|
||||||
[TEXT, 't', false, 0],
|
[TEXT, 't', false, 0],
|
||||||
[END_COMPONENT]
|
[END_COMPONENT]
|
||||||
]);
|
]);
|
||||||
|
@ -472,7 +453,8 @@ export function main() {
|
||||||
describe('compileComponentRuntime', () => {
|
describe('compileComponentRuntime', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
componentTemplateFactory = (directive: CompileDirectiveMetadata) => {
|
componentTemplateFactory = (directive: CompileDirectiveMetadata) => {
|
||||||
return new CompiledTemplate(compTypeTemplateId.get(directive.type), () => []);
|
return () => new CompiledComponentTemplate(compTypeTemplateId.get(directive.type), null,
|
||||||
|
null, null);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -485,8 +467,7 @@ export function main() {
|
||||||
var parsedTemplate =
|
var parsedTemplate =
|
||||||
parser.parse(component.template.template, directives, component.type.name);
|
parser.parse(component.template.template, directives, component.type.name);
|
||||||
var commands = commandCompiler.compileComponentRuntime(
|
var commands = commandCompiler.compileComponentRuntime(
|
||||||
component, APP_ID, compTypeTemplateId.get(component.type), parsedTemplate,
|
component, parsedTemplate, changeDetectorFactories, componentTemplateFactory);
|
||||||
changeDetectorFactories, componentTemplateFactory);
|
|
||||||
return PromiseWrapper.resolve(humanize(commands));
|
return PromiseWrapper.resolve(humanize(commands));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,22 +478,34 @@ export function main() {
|
||||||
describe('compileComponentCodeGen', () => {
|
describe('compileComponentCodeGen', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
componentTemplateFactory = (directive: CompileDirectiveMetadata) => {
|
componentTemplateFactory = (directive: CompileDirectiveMetadata) => {
|
||||||
return `new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${compTypeTemplateId.get(directive.type)}, ${codeGenValueFn([], '{}')})`;
|
return `${directive.type.name}TemplateGetter`;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
function run(component: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[],
|
function run(component: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[],
|
||||||
embeddedTemplateCount: number = 0): Promise<any[][]> {
|
embeddedTemplateCount: number = 0): Promise<any[][]> {
|
||||||
|
var testDeclarations = [];
|
||||||
var changeDetectorFactoryExpressions = [];
|
var changeDetectorFactoryExpressions = [];
|
||||||
for (var i = 0; i < embeddedTemplateCount + 1; i++) {
|
for (var i = 0; i < embeddedTemplateCount + 1; i++) {
|
||||||
changeDetectorFactoryExpressions.push(codeGenValueFn(['_'], `'cd${i}'`));
|
var fnName = `cd${i}`;
|
||||||
|
testDeclarations.push(`${codeGenValueFn(['_'], ` 'cd${i}' `, fnName)};`);
|
||||||
|
changeDetectorFactoryExpressions.push(fnName);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < directives.length; i++) {
|
||||||
|
var directive = directives[i];
|
||||||
|
if (directive.isComponent) {
|
||||||
|
var nestedTemplate =
|
||||||
|
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'CompiledComponentTemplate')}('${compTypeTemplateId.get(directive.type)}', null, null, null)`;
|
||||||
|
var getterName = `${directive.type.name}TemplateGetter`;
|
||||||
|
testDeclarations.push(`${codeGenValueFn([], nestedTemplate, getterName)};`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var parsedTemplate =
|
var parsedTemplate =
|
||||||
parser.parse(component.template.template, directives, component.type.name);
|
parser.parse(component.template.template, directives, component.type.name);
|
||||||
var sourceModule = commandCompiler.compileComponentCodeGen(
|
var sourceExpression = commandCompiler.compileComponentCodeGen(
|
||||||
component, `'${APP_ID}'`, `${compTypeTemplateId.get(component.type)}`, parsedTemplate,
|
component, parsedTemplate, changeDetectorFactoryExpressions, componentTemplateFactory);
|
||||||
changeDetectorFactoryExpressions, componentTemplateFactory);
|
testDeclarations.forEach(decl => sourceExpression.declarations.push(decl));
|
||||||
var testableModule = createTestableModule(sourceModule).getSourceWithImports();
|
var testableModule = createTestableModule(sourceExpression).getSourceWithImports();
|
||||||
return evalModule(testableModule.source, testableModule.imports, null);
|
return evalModule(testableModule.source, testableModule.imports, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,9 +562,9 @@ class CommandHumanizer implements CommandVisitor {
|
||||||
cmd.eventTargetAndNames,
|
cmd.eventTargetAndNames,
|
||||||
cmd.variableNameAndValues,
|
cmd.variableNameAndValues,
|
||||||
cmd.directives.map(checkAndStringifyType),
|
cmd.directives.map(checkAndStringifyType),
|
||||||
cmd.nativeShadow,
|
serializeEnum(cmd.encapsulation),
|
||||||
cmd.ngContentIndex,
|
cmd.ngContentIndex,
|
||||||
cmd.template.id
|
cmd.templateId
|
||||||
]);
|
]);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -597,6 +590,8 @@ class CommandHumanizer implements CommandVisitor {
|
||||||
function createTestableModule(source: SourceExpression): SourceModule {
|
function createTestableModule(source: SourceExpression): SourceModule {
|
||||||
var resultExpression = `${THIS_MODULE_REF}humanize(${source.expression})`;
|
var resultExpression = `${THIS_MODULE_REF}humanize(${source.expression})`;
|
||||||
var testableSource = `${source.declarations.join('\n')}
|
var testableSource = `${source.declarations.join('\n')}
|
||||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], resultExpression)};`;
|
${codeGenValueFn(['_'], resultExpression, '_run')};
|
||||||
|
${codeGenExportVariable('run')}_run;
|
||||||
|
`;
|
||||||
return new SourceModule(null, testableSource);
|
return new SourceModule(null, testableSource);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||||
import {SpyProtoViewFactory} from '../core/spies';
|
import {SpyProtoViewFactory} from '../core/spies';
|
||||||
import {
|
import {
|
||||||
CompiledHostTemplate,
|
CompiledHostTemplate,
|
||||||
CompiledTemplate,
|
CompiledComponentTemplate,
|
||||||
BeginComponentCmd
|
BeginComponentCmd
|
||||||
} from 'angular2/src/core/linker/template_commands';
|
} from 'angular2/src/core/linker/template_commands';
|
||||||
import {RuntimeCompiler} from 'angular2/src/compiler/runtime_compiler';
|
import {RuntimeCompiler} from 'angular2/src/compiler/runtime_compiler';
|
||||||
|
@ -37,7 +37,7 @@ export function main() {
|
||||||
|
|
||||||
beforeEachBindings(() => {
|
beforeEachBindings(() => {
|
||||||
protoViewFactorySpy = new SpyProtoViewFactory();
|
protoViewFactorySpy = new SpyProtoViewFactory();
|
||||||
someProtoView = new AppProtoView(null, null, null, null, null, null);
|
someProtoView = new AppProtoView(null, null, null, null, null, null, null);
|
||||||
protoViewFactorySpy.spy('createHost').andReturn(someProtoView);
|
protoViewFactorySpy.spy('createHost').andReturn(someProtoView);
|
||||||
return [provide(ProtoViewFactory, {useValue: protoViewFactorySpy})];
|
return [provide(ProtoViewFactory, {useValue: protoViewFactorySpy})];
|
||||||
});
|
});
|
||||||
|
@ -52,8 +52,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
compiler.compileInHost(SomeComponent)
|
compiler.compileInHost(SomeComponent)
|
||||||
.then((_) => {
|
.then((_) => {
|
||||||
var beginComponentCmd =
|
var beginComponentCmd = <BeginComponentCmd>cht.template.commands[0];
|
||||||
<BeginComponentCmd>cht.getTemplate().getData('app1').commands[0];
|
|
||||||
expect(beginComponentCmd.name).toEqual('some-comp');
|
expect(beginComponentCmd.name).toEqual('some-comp');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
|
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
// used by style_compiler_spec.ts
|
// used by style_compiler_spec.ts
|
||||||
export var STYLES = ['span[_ngcontent-%COMP%] {\ncolor: blue;\n}'];
|
export const STYLES = CONST_EXPR(['span[_ngcontent-%COMP%] {\ncolor: blue;\n}']);
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
|
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
// used by style_compiler_spec.ts
|
// used by style_compiler_spec.ts
|
||||||
export var STYLES = ['span {color: blue}'];
|
export const STYLES = CONST_EXPR(['span {color: blue}']);
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {SpyXHR} from './spies';
|
||||||
import {XHR} from 'angular2/src/compiler/xhr';
|
import {XHR} from 'angular2/src/compiler/xhr';
|
||||||
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||||
|
|
||||||
import {CONST_EXPR, isPresent, isBlank, StringWrapper} from 'angular2/src/facade/lang';
|
import {CONST_EXPR, isPresent, isBlank, StringWrapper, isArray} from 'angular2/src/facade/lang';
|
||||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
import {evalModule} from './eval_module';
|
import {evalModule} from './eval_module';
|
||||||
import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
|
import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
|
||||||
|
@ -42,8 +42,6 @@ var IMPORT_ABS_STYLESHEET_URL_WITH_IMPORT =
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('StyleCompiler', () => {
|
describe('StyleCompiler', () => {
|
||||||
var xhr: SpyXHR;
|
var xhr: SpyXHR;
|
||||||
var templateId;
|
|
||||||
var appId;
|
|
||||||
|
|
||||||
beforeEachBindings(() => {
|
beforeEachBindings(() => {
|
||||||
xhr = <any>new SpyXHR();
|
xhr = <any>new SpyXHR();
|
||||||
|
@ -52,11 +50,7 @@ export function main() {
|
||||||
|
|
||||||
var compiler: StyleCompiler;
|
var compiler: StyleCompiler;
|
||||||
|
|
||||||
beforeEach(inject([StyleCompiler], (_compiler) => {
|
beforeEach(inject([StyleCompiler], (_compiler) => { compiler = _compiler; }));
|
||||||
templateId = 23;
|
|
||||||
appId = 'app1';
|
|
||||||
compiler = _compiler;
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('compileComponentRuntime', () => {
|
describe('compileComponentRuntime', () => {
|
||||||
var xhrUrlResults;
|
var xhrUrlResults;
|
||||||
|
@ -82,10 +76,8 @@ export function main() {
|
||||||
}
|
}
|
||||||
return PromiseWrapper.resolve(response);
|
return PromiseWrapper.resolve(response);
|
||||||
});
|
});
|
||||||
return compiler.compileComponentRuntime(
|
return compiler.compileComponentRuntime(new CompileTemplateMetadata(
|
||||||
appId, templateId,
|
{styles: styles, styleUrls: styleAbsUrls, encapsulation: encapsulation}));
|
||||||
new CompileTemplateMetadata(
|
|
||||||
{styles: styles, styleUrls: styleAbsUrls, encapsulation: encapsulation}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('no shim', () => {
|
describe('no shim', () => {
|
||||||
|
@ -102,7 +94,7 @@ export function main() {
|
||||||
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
||||||
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
expect(styles).toEqual(['div {color: red}', 'span {color: blue}']);
|
expect(styles).toEqual(['div {color: red}', ['span {color: blue}']]);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -111,7 +103,7 @@ export function main() {
|
||||||
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL_WITH_IMPORT], encapsulation)
|
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL_WITH_IMPORT], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
expect(styles)
|
expect(styles)
|
||||||
.toEqual(['div {color: red}', 'a {color: green}', 'span {color: blue}']);
|
.toEqual(['div {color: red}', ['a {color: green}', ['span {color: blue}']]]);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -124,8 +116,8 @@ export function main() {
|
||||||
compile(['div {\ncolor: red;\n}', 'span {\ncolor: blue;\n}'], [], encapsulation)
|
compile(['div {\ncolor: red;\n}', 'span {\ncolor: blue;\n}'], [], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
compareStyles(styles, [
|
compareStyles(styles, [
|
||||||
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
|
'div[_ngcontent-%COMP%] {\ncolor: red;\n}',
|
||||||
'span[_ngcontent-app1-23] {\ncolor: blue;\n}'
|
'span[_ngcontent-%COMP%] {\ncolor: blue;\n}'
|
||||||
]);
|
]);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -135,8 +127,8 @@ export function main() {
|
||||||
compile(['div {\ncolor: red;\n}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
compile(['div {\ncolor: red;\n}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
compareStyles(styles, [
|
compareStyles(styles, [
|
||||||
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
|
'div[_ngcontent-%COMP%] {\ncolor: red;\n}',
|
||||||
'span[_ngcontent-app1-23] {color: blue}'
|
['span[_ngcontent-%COMP%] {color: blue}']
|
||||||
]);
|
]);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -147,9 +139,11 @@ export function main() {
|
||||||
encapsulation)
|
encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
compareStyles(styles, [
|
compareStyles(styles, [
|
||||||
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
|
'div[_ngcontent-%COMP%] {\ncolor: red;\n}',
|
||||||
'a[_ngcontent-app1-23] {color: green}',
|
[
|
||||||
'span[_ngcontent-app1-23] {color: blue}'
|
'a[_ngcontent-%COMP%] {color: green}',
|
||||||
|
['span[_ngcontent-%COMP%] {color: blue}']
|
||||||
|
]
|
||||||
]);
|
]);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -162,8 +156,8 @@ export function main() {
|
||||||
compile([], [IMPORT_ABS_STYLESHEET_URL], ViewEncapsulation.None)
|
compile([], [IMPORT_ABS_STYLESHEET_URL], ViewEncapsulation.None)
|
||||||
])
|
])
|
||||||
.then((styleArrays) => {
|
.then((styleArrays) => {
|
||||||
expect(styleArrays[0]).toEqual(['span {color: blue}']);
|
expect(styleArrays[0]).toEqual([['span {color: blue}']]);
|
||||||
expect(styleArrays[1]).toEqual(['span {color: blue}']);
|
expect(styleArrays[1]).toEqual([['span {color: blue}']]);
|
||||||
expect(xhrCount).toBe(1);
|
expect(xhrCount).toBe(1);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -175,8 +169,8 @@ export function main() {
|
||||||
xhrUrlResults[IMPORT_ABS_STYLESHEET_URL] = 'span {color: black}';
|
xhrUrlResults[IMPORT_ABS_STYLESHEET_URL] = 'span {color: black}';
|
||||||
return compile([], [IMPORT_ABS_STYLESHEET_URL], ViewEncapsulation.None)
|
return compile([], [IMPORT_ABS_STYLESHEET_URL], ViewEncapsulation.None)
|
||||||
.then((styles1) => {
|
.then((styles1) => {
|
||||||
expect(styles0).toEqual(['span {color: blue}']);
|
expect(styles0).toEqual([['span {color: blue}']]);
|
||||||
expect(styles1).toEqual(['span {color: blue}']);
|
expect(styles1).toEqual([['span {color: blue}']]);
|
||||||
expect(xhrCount).toBe(1);
|
expect(xhrCount).toBe(1);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -192,7 +186,7 @@ export function main() {
|
||||||
})
|
})
|
||||||
.then((styles) => {
|
.then((styles) => {
|
||||||
expect(xhrCount).toBe(2);
|
expect(xhrCount).toBe(2);
|
||||||
expect(styles).toEqual(['span {color: black}']);
|
expect(styles).toEqual([['span {color: black}']]);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -201,10 +195,8 @@ export function main() {
|
||||||
describe('compileComponentCodeGen', () => {
|
describe('compileComponentCodeGen', () => {
|
||||||
function compile(styles: string[], styleAbsUrls: string[],
|
function compile(styles: string[], styleAbsUrls: string[],
|
||||||
encapsulation: ViewEncapsulation): Promise<string[]> {
|
encapsulation: ViewEncapsulation): Promise<string[]> {
|
||||||
var sourceExpression = compiler.compileComponentCodeGen(
|
var sourceExpression = compiler.compileComponentCodeGen(new CompileTemplateMetadata(
|
||||||
`'${appId}'`, `${templateId}`,
|
{styles: styles, styleUrls: styleAbsUrls, encapsulation: encapsulation}));
|
||||||
new CompileTemplateMetadata(
|
|
||||||
{styles: styles, styleUrls: styleAbsUrls, encapsulation: encapsulation}));
|
|
||||||
var sourceWithImports = testableExpression(sourceExpression).getSourceWithImports();
|
var sourceWithImports = testableExpression(sourceExpression).getSourceWithImports();
|
||||||
return evalModule(sourceWithImports.source, sourceWithImports.imports, null);
|
return evalModule(sourceWithImports.source, sourceWithImports.imports, null);
|
||||||
};
|
};
|
||||||
|
@ -232,7 +224,7 @@ export function main() {
|
||||||
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
||||||
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
expect(styles).toEqual(['div {color: red}', 'span {color: blue}']);
|
expect(styles).toEqual(['div {color: red}', ['span {color: blue}']]);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}), 1000);
|
}), 1000);
|
||||||
|
@ -245,8 +237,8 @@ export function main() {
|
||||||
compile(['div {\ncolor: red;\n}', 'span {\ncolor: blue;\n}'], [], encapsulation)
|
compile(['div {\ncolor: red;\n}', 'span {\ncolor: blue;\n}'], [], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
compareStyles(styles, [
|
compareStyles(styles, [
|
||||||
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
|
'div[_ngcontent-%COMP%] {\ncolor: red;\n}',
|
||||||
'span[_ngcontent-app1-23] {\ncolor: blue;\n}'
|
'span[_ngcontent-%COMP%] {\ncolor: blue;\n}'
|
||||||
]);
|
]);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -256,8 +248,8 @@ export function main() {
|
||||||
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
compareStyles(styles, [
|
compareStyles(styles, [
|
||||||
'div[_ngcontent-app1-23] {color: red}',
|
'div[_ngcontent-%COMP%] {color: red}',
|
||||||
'span[_ngcontent-app1-23] {\ncolor: blue;\n}'
|
['span[_ngcontent-%COMP%] {\ncolor: blue;\n}']
|
||||||
]);
|
]);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -289,10 +281,10 @@ export function main() {
|
||||||
compile(`div {color: red}@import ${IMPORT_REL_STYLESHEET_URL};`)
|
compile(`div {color: red}@import ${IMPORT_REL_STYLESHEET_URL};`)
|
||||||
.then(stylesAndShimStyles => {
|
.then(stylesAndShimStyles => {
|
||||||
var expected = [
|
var expected = [
|
||||||
['div {color: red}', 'span {color: blue}'],
|
['div {color: red}', ['span {color: blue}']],
|
||||||
[
|
[
|
||||||
'div[_ngcontent-%COMP%] {color: red}',
|
'div[_ngcontent-%COMP%] {color: red}',
|
||||||
'span[_ngcontent-%COMP%] {\ncolor: blue;\n}'
|
['span[_ngcontent-%COMP%] {\ncolor: blue;\n}']
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
compareStyles(stylesAndShimStyles[0], expected[0]);
|
compareStyles(stylesAndShimStyles[0], expected[0]);
|
||||||
|
@ -307,20 +299,27 @@ export function main() {
|
||||||
|
|
||||||
function testableExpression(source: SourceExpression): SourceModule {
|
function testableExpression(source: SourceExpression): SourceModule {
|
||||||
var testableSource = `${source.declarations.join('\n')}
|
var testableSource = `${source.declarations.join('\n')}
|
||||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], source.expression)};`;
|
${codeGenValueFn(['_'], source.expression, '_run')};
|
||||||
|
${codeGenExportVariable('run')}_run;`;
|
||||||
return new SourceModule(null, testableSource);
|
return new SourceModule(null, testableSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testableModule(sourceModule: SourceModule): SourceModule {
|
function testableModule(sourceModule: SourceModule): SourceModule {
|
||||||
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
||||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], 'STYLES')};`;
|
${codeGenValueFn(['_'], 'STYLES', '_run')};
|
||||||
|
${codeGenExportVariable('run')}_run;`;
|
||||||
return new SourceModule(sourceModule.moduleUrl, testableSource);
|
return new SourceModule(sourceModule.moduleUrl, testableSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needed for Android browsers which add an extra space at the end of some lines
|
// Needed for Android browsers which add an extra space at the end of some lines
|
||||||
function compareStyles(styles: string[], expectedStyles: string[]) {
|
function compareStyles(styles: Array<string | any[]>, expectedStyles: Array<string | any[]>) {
|
||||||
expect(styles.length).toEqual(expectedStyles.length);
|
expect(styles.length).toEqual(expectedStyles.length);
|
||||||
for (var i = 0; i < styles.length; i++) {
|
for (var i = 0; i < styles.length; i++) {
|
||||||
expect(StringWrapper.replaceAll(styles[i], /\s+\n/g, '\n')).toEqual(expectedStyles[i]);
|
var style = styles[i];
|
||||||
|
if (isArray(style)) {
|
||||||
|
compareStyles(<any[]>style, <any[]>expectedStyles[i]);
|
||||||
|
} else {
|
||||||
|
expect(StringWrapper.replaceAll(<string>style, /\s+\n/g, '\n')).toEqual(expectedStyles[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ import {
|
||||||
EmbeddedTemplateCmd,
|
EmbeddedTemplateCmd,
|
||||||
TemplateCmd,
|
TemplateCmd,
|
||||||
visitAllCommands,
|
visitAllCommands,
|
||||||
CompiledTemplate
|
CompiledComponentTemplate
|
||||||
} from 'angular2/src/core/linker/template_commands';
|
} from 'angular2/src/core/linker/template_commands';
|
||||||
|
|
||||||
import {Component, View, Directive, provide} from 'angular2/core';
|
import {Component, View, Directive, provide} from 'angular2/core';
|
||||||
|
@ -47,20 +47,17 @@ import {Component, View, Directive, provide} from 'angular2/core';
|
||||||
import {TEST_PROVIDERS} from './test_bindings';
|
import {TEST_PROVIDERS} from './test_bindings';
|
||||||
import {TestDispatcher, TestPipes} from './change_detector_mocks';
|
import {TestDispatcher, TestPipes} from './change_detector_mocks';
|
||||||
import {codeGenValueFn, codeGenExportVariable, MODULE_SUFFIX} from 'angular2/src/compiler/util';
|
import {codeGenValueFn, codeGenExportVariable, MODULE_SUFFIX} from 'angular2/src/compiler/util';
|
||||||
import {APP_ID} from 'angular2/src/core/application_tokens';
|
|
||||||
|
|
||||||
// Attention: This path has to point to this test file!
|
// Attention: This path has to point to this test file!
|
||||||
const THIS_MODULE_ID = 'angular2/test/compiler/template_compiler_spec';
|
const THIS_MODULE_ID = 'angular2/test/compiler/template_compiler_spec';
|
||||||
var THIS_MODULE_REF = moduleRef(`package:${THIS_MODULE_ID}${MODULE_SUFFIX}`);
|
var THIS_MODULE_REF = moduleRef(`package:${THIS_MODULE_ID}${MODULE_SUFFIX}`);
|
||||||
|
|
||||||
const APP_ID_VALUE = 'app1';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('TemplateCompiler', () => {
|
describe('TemplateCompiler', () => {
|
||||||
var compiler: TemplateCompiler;
|
var compiler: TemplateCompiler;
|
||||||
var runtimeMetadataResolver: RuntimeMetadataResolver;
|
var runtimeMetadataResolver: RuntimeMetadataResolver;
|
||||||
|
|
||||||
beforeEachBindings(() => [provide(APP_ID, {useValue: APP_ID_VALUE}), TEST_PROVIDERS]);
|
beforeEachBindings(() => TEST_PROVIDERS);
|
||||||
beforeEach(inject([TemplateCompiler, RuntimeMetadataResolver],
|
beforeEach(inject([TemplateCompiler, RuntimeMetadataResolver],
|
||||||
(_compiler, _runtimeMetadataResolver) => {
|
(_compiler, _runtimeMetadataResolver) => {
|
||||||
compiler = _compiler;
|
compiler = _compiler;
|
||||||
|
@ -127,10 +124,10 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('compileHostComponentRuntime', () => {
|
xdescribe('compileHostComponentRuntime', () => {
|
||||||
function compile(components: Type[]): Promise<any[]> {
|
function compile(components: Type[]): Promise<any[]> {
|
||||||
return compiler.compileHostComponentRuntime(components[0])
|
return compiler.compileHostComponentRuntime(components[0])
|
||||||
.then((compiledHostTemplate) => humanizeTemplate(compiledHostTemplate.getTemplate()));
|
.then((compiledHostTemplate) => humanizeTemplate(compiledHostTemplate.template));
|
||||||
}
|
}
|
||||||
|
|
||||||
runTests(compile);
|
runTests(compile);
|
||||||
|
@ -315,38 +312,39 @@ class NonComponent {
|
||||||
function testableTemplateModule(sourceModule: SourceModule,
|
function testableTemplateModule(sourceModule: SourceModule,
|
||||||
normComp: CompileDirectiveMetadata): SourceModule {
|
normComp: CompileDirectiveMetadata): SourceModule {
|
||||||
var resultExpression =
|
var resultExpression =
|
||||||
`${THIS_MODULE_REF}humanizeTemplate(Host${normComp.type.name}Template.getTemplate())`;
|
`${THIS_MODULE_REF}humanizeTemplate(Host${normComp.type.name}Template.template)`;
|
||||||
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
||||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], resultExpression)};`;
|
${codeGenValueFn(['_'], resultExpression, '_run')};
|
||||||
|
${codeGenExportVariable('run')}_run;`;
|
||||||
return new SourceModule(sourceModule.moduleUrl, testableSource);
|
return new SourceModule(sourceModule.moduleUrl, testableSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testableStylesModule(sourceModule: SourceModule): SourceModule {
|
function testableStylesModule(sourceModule: SourceModule): SourceModule {
|
||||||
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
||||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], 'STYLES')};`;
|
${codeGenValueFn(['_'], 'STYLES', '_run')};
|
||||||
|
${codeGenExportVariable('run')}_run;`;
|
||||||
return new SourceModule(sourceModule.moduleUrl, testableSource);
|
return new SourceModule(sourceModule.moduleUrl, testableSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attention: read by eval!
|
// Attention: read by eval!
|
||||||
export function humanizeTemplate(
|
export function humanizeTemplate(
|
||||||
template: CompiledTemplate,
|
template: CompiledComponentTemplate,
|
||||||
humanizedTemplates: Map<number, {[key: string]: any}> = null): {[key: string]: any} {
|
humanizedTemplates: Map<string, {[key: string]: any}> = null): {[key: string]: any} {
|
||||||
if (isBlank(humanizedTemplates)) {
|
if (isBlank(humanizedTemplates)) {
|
||||||
humanizedTemplates = new Map<number, {[key: string]: any}>();
|
humanizedTemplates = new Map<string, {[key: string]: any}>();
|
||||||
}
|
}
|
||||||
var result = humanizedTemplates.get(template.id);
|
var result = humanizedTemplates.get(template.id);
|
||||||
if (isPresent(result)) {
|
if (isPresent(result)) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
var templateData = template.getData(APP_ID_VALUE);
|
|
||||||
var commands = [];
|
var commands = [];
|
||||||
result = {
|
result = {
|
||||||
'styles': templateData.styles,
|
'styles': template.styles,
|
||||||
'commands': commands,
|
'commands': commands,
|
||||||
'cd': testChangeDetector(templateData.changeDetectorFactory)
|
'cd': testChangeDetector(template.changeDetectorFactory)
|
||||||
};
|
};
|
||||||
humanizedTemplates.set(template.id, result);
|
humanizedTemplates.set(template.id, result);
|
||||||
visitAllCommands(new CommandHumanizer(commands, humanizedTemplates), templateData.commands);
|
visitAllCommands(new CommandHumanizer(commands, humanizedTemplates), template.commands);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,7 +371,7 @@ function testChangeDetector(changeDetectorFactory: Function): string[] {
|
||||||
|
|
||||||
class CommandHumanizer implements CommandVisitor {
|
class CommandHumanizer implements CommandVisitor {
|
||||||
constructor(private result: any[],
|
constructor(private result: any[],
|
||||||
private humanizedTemplates: Map<number, {[key: string]: any}>) {}
|
private humanizedTemplates: Map<string, {[key: string]: any}>) {}
|
||||||
visitText(cmd: TextCmd, context: any): any {
|
visitText(cmd: TextCmd, context: any): any {
|
||||||
this.result.push(`#text(${cmd.value})`);
|
this.result.push(`#text(${cmd.value})`);
|
||||||
return null;
|
return null;
|
||||||
|
@ -389,7 +387,7 @@ class CommandHumanizer implements CommandVisitor {
|
||||||
}
|
}
|
||||||
visitBeginComponent(cmd: BeginComponentCmd, context: any): any {
|
visitBeginComponent(cmd: BeginComponentCmd, context: any): any {
|
||||||
this.result.push(`<${cmd.name}>`);
|
this.result.push(`<${cmd.name}>`);
|
||||||
this.result.push(humanizeTemplate(cmd.template, this.humanizedTemplates));
|
this.result.push(humanizeTemplate(cmd.templateGetter(), this.humanizedTemplates));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
visitEndComponent(context: any): any { return this.visitEndElement(context); }
|
visitEndComponent(context: any): any { return this.visitEndElement(context); }
|
||||||
|
|
|
@ -75,14 +75,16 @@ export function main() {
|
||||||
|
|
||||||
describe(`${cdType} Change Detector`, () => {
|
describe(`${cdType} Change Detector`, () => {
|
||||||
|
|
||||||
function _getProtoChangeDetector(def: ChangeDetectorDefinition) {
|
function _getChangeDetectorFactory(def: ChangeDetectorDefinition) {
|
||||||
switch (cdType) {
|
switch (cdType) {
|
||||||
case 'dynamic':
|
case 'dynamic':
|
||||||
return new DynamicProtoChangeDetector(def);
|
var dynProto = new DynamicProtoChangeDetector(def);
|
||||||
|
return (dispatcher) => dynProto.instantiate(dispatcher);
|
||||||
case 'JIT':
|
case 'JIT':
|
||||||
return new JitProtoChangeDetector(def);
|
var jitProto = new JitProtoChangeDetector(def);
|
||||||
|
return (dispatcher) => jitProto.instantiate(dispatcher);
|
||||||
case 'Pregen':
|
case 'Pregen':
|
||||||
return getFactoryById(def.id)(def);
|
return getFactoryById(def.id);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +92,7 @@ export function main() {
|
||||||
|
|
||||||
function _createWithoutHydrate(expression: string) {
|
function _createWithoutHydrate(expression: string) {
|
||||||
var dispatcher = new TestDispatcher();
|
var dispatcher = new TestDispatcher();
|
||||||
var cd = _getProtoChangeDetector(getDefinition(expression).cdDef).instantiate(dispatcher);
|
var cd = _getChangeDetectorFactory(getDefinition(expression).cdDef)(dispatcher);
|
||||||
return new _ChangeDetectorAndDispatcher(cd, dispatcher);
|
return new _ChangeDetectorAndDispatcher(cd, dispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,8 +101,7 @@ export function main() {
|
||||||
registry = null, dispatcher = null) {
|
registry = null, dispatcher = null) {
|
||||||
if (isBlank(dispatcher)) dispatcher = new TestDispatcher();
|
if (isBlank(dispatcher)) dispatcher = new TestDispatcher();
|
||||||
var testDef = getDefinition(expression);
|
var testDef = getDefinition(expression);
|
||||||
var protoCd = _getProtoChangeDetector(testDef.cdDef);
|
var cd = _getChangeDetectorFactory(testDef.cdDef)(dispatcher);
|
||||||
var cd = protoCd.instantiate(dispatcher);
|
|
||||||
cd.hydrate(context, testDef.locals, null, registry);
|
cd.hydrate(context, testDef.locals, null, registry);
|
||||||
return new _ChangeDetectorAndDispatcher(cd, dispatcher);
|
return new _ChangeDetectorAndDispatcher(cd, dispatcher);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ void main(List<String> args) {
|
||||||
buf.write(',');
|
buf.write(',');
|
||||||
}
|
}
|
||||||
buf.write(" '''${_escape(allDefs[i].cdDef.id)}''': "
|
buf.write(" '''${_escape(allDefs[i].cdDef.id)}''': "
|
||||||
"$className.$PROTO_CHANGE_DETECTOR_FACTORY_METHOD");
|
"$className.$CHANGE_DETECTOR_FACTORY_METHOD");
|
||||||
}
|
}
|
||||||
buf.write('};');
|
buf.write('};');
|
||||||
print(new DartFormatter().format('''
|
print(new DartFormatter().format('''
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {Component, View, provide} from 'angular2/core';
|
||||||
import {SpyProtoViewFactory} from '../spies';
|
import {SpyProtoViewFactory} from '../spies';
|
||||||
import {
|
import {
|
||||||
CompiledHostTemplate,
|
CompiledHostTemplate,
|
||||||
CompiledTemplate,
|
CompiledComponentTemplate,
|
||||||
BeginComponentCmd
|
BeginComponentCmd
|
||||||
} from 'angular2/src/core/linker/template_commands';
|
} from 'angular2/src/core/linker/template_commands';
|
||||||
import {Compiler} from 'angular2/src/core/linker/compiler';
|
import {Compiler} from 'angular2/src/core/linker/compiler';
|
||||||
|
@ -35,7 +35,7 @@ export function main() {
|
||||||
|
|
||||||
beforeEachBindings(() => {
|
beforeEachBindings(() => {
|
||||||
protoViewFactorySpy = new SpyProtoViewFactory();
|
protoViewFactorySpy = new SpyProtoViewFactory();
|
||||||
someProtoView = new AppProtoView(null, null, null, null, null, null);
|
someProtoView = new AppProtoView(null, null, null, null, null, null, null);
|
||||||
protoViewFactorySpy.spy('createHost').andReturn(someProtoView);
|
protoViewFactorySpy.spy('createHost').andReturn(someProtoView);
|
||||||
var factory = provide(ProtoViewFactory, {useValue: protoViewFactorySpy});
|
var factory = provide(ProtoViewFactory, {useValue: protoViewFactorySpy});
|
||||||
var classProvider = provide(Compiler, {useClass: Compiler_});
|
var classProvider = provide(Compiler, {useClass: Compiler_});
|
||||||
|
@ -45,7 +45,7 @@ export function main() {
|
||||||
|
|
||||||
beforeEach(inject([Compiler], (_compiler) => {
|
beforeEach(inject([Compiler], (_compiler) => {
|
||||||
compiler = _compiler;
|
compiler = _compiler;
|
||||||
cht = new CompiledHostTemplate(() => new CompiledTemplate(23, null));
|
cht = new CompiledHostTemplate(new CompiledComponentTemplate('aCompId', null, null, null));
|
||||||
reflector.registerType(SomeComponent, new ReflectionInfo([cht]));
|
reflector.registerType(SomeComponent, new ReflectionInfo([cht]));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -444,6 +444,27 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DOM.supportsDOMEvents()) {
|
||||||
|
it('should support emulated style encapsulation',
|
||||||
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
tcb.overrideView(MainComp, new ViewMetadata({
|
||||||
|
template: '<div></div>',
|
||||||
|
styles: ['div { color: red}'],
|
||||||
|
encapsulation: ViewEncapsulation.Emulated
|
||||||
|
}))
|
||||||
|
.createAsync(MainComp)
|
||||||
|
.then((main) => {
|
||||||
|
var mainEl = main.debugElement.nativeElement;
|
||||||
|
var div1 = DOM.firstChild(mainEl);
|
||||||
|
var div2 = DOM.createElement('div');
|
||||||
|
DOM.appendChild(mainEl, div2);
|
||||||
|
expect(DOM.getComputedStyle(div1).color).toEqual('rgb(255, 0, 0)');
|
||||||
|
expect(DOM.getComputedStyle(div2).color).toEqual('rgb(0, 0, 0)');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
it('should support nested conditionals that contain ng-contents',
|
it('should support nested conditionals that contain ng-contents',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
tcb.overrideView(MainComp, new ViewMetadata({
|
tcb.overrideView(MainComp, new ViewMetadata({
|
||||||
|
|
|
@ -250,8 +250,8 @@ function _createProtoView(type: ViewType, binders: ElementBinder[] = null) {
|
||||||
if (isBlank(binders)) {
|
if (isBlank(binders)) {
|
||||||
binders = [];
|
binders = [];
|
||||||
}
|
}
|
||||||
var res = new AppProtoView([], type, true, (_) => new SpyChangeDetector(), new Map<string, any>(),
|
var res = new AppProtoView(null, [], type, true, (_) => new SpyChangeDetector(),
|
||||||
null);
|
new Map<string, any>(), null);
|
||||||
var mergedElementCount = 0;
|
var mergedElementCount = 0;
|
||||||
var mergedEmbeddedViewCount = 0;
|
var mergedEmbeddedViewCount = 0;
|
||||||
var mergedViewCount = 1;
|
var mergedViewCount = 1;
|
||||||
|
|
|
@ -24,7 +24,9 @@ export function main() {
|
||||||
|
|
||||||
function createViewPool({capacity}): AppViewPool { return new AppViewPool(capacity); }
|
function createViewPool({capacity}): AppViewPool { return new AppViewPool(capacity); }
|
||||||
|
|
||||||
function createProtoView() { return new AppProtoView(null, null, null, null, null, null); }
|
function createProtoView() {
|
||||||
|
return new AppProtoView(null, null, null, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
function createView(pv) {
|
function createView(pv) {
|
||||||
return new AppView(null, pv, null, null, null, new Map<string, any>(), null, null, null);
|
return new AppView(null, pv, null, null, null, new Map<string, any>(), null, null, null);
|
||||||
|
|
|
@ -14,132 +14,150 @@ import {
|
||||||
import {isPresent} from 'angular2/src/facade/lang';
|
import {isPresent} from 'angular2/src/facade/lang';
|
||||||
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||||
import * as appCmds from 'angular2/src/core/linker/template_commands';
|
import * as appCmds from 'angular2/src/core/linker/template_commands';
|
||||||
import {createRenderView, NodeFactory} from 'angular2/src/core/render/view_factory';
|
import {
|
||||||
import {RenderTemplateCmd, RenderBeginElementCmd} from 'angular2/src/core/render/api';
|
createRenderView,
|
||||||
|
encapsulateStyles,
|
||||||
|
NodeFactory
|
||||||
|
} from 'angular2/src/core/render/view_factory';
|
||||||
|
import {
|
||||||
|
RenderTemplateCmd,
|
||||||
|
RenderBeginElementCmd,
|
||||||
|
RenderComponentTemplate
|
||||||
|
} from 'angular2/src/core/render/api';
|
||||||
import {SpyRenderEventDispatcher} from '../spies';
|
import {SpyRenderEventDispatcher} from '../spies';
|
||||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
|
import {ViewEncapsulation} from 'angular2/src/core/metadata';
|
||||||
|
|
||||||
function beginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
function beginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||||
isBound: boolean, ngContentIndex: number): RenderBeginElementCmd {
|
isBound: boolean, ngContentIndex: number): RenderBeginElementCmd {
|
||||||
return appCmds.beginElement(name, attrNameAndValues, eventTargetAndNames, [], [], isBound,
|
return new appCmds.BeginElementCmd(name, attrNameAndValues, eventTargetAndNames, [], [], isBound,
|
||||||
ngContentIndex)
|
ngContentIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
function endElement() {
|
function endElement() {
|
||||||
return appCmds.endElement();
|
return new appCmds.EndElementCmd();
|
||||||
}
|
}
|
||||||
|
|
||||||
function text(value: string, isBound: boolean, ngContentIndex: number) {
|
function text(value: string, isBound: boolean, ngContentIndex: number) {
|
||||||
return appCmds.text(value, isBound, ngContentIndex);
|
return new appCmds.TextCmd(value, isBound, ngContentIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
function embeddedTemplate(attrNameAndValues: string[], isMerged: boolean, ngContentIndex: number,
|
function embeddedTemplate(attrNameAndValues: string[], isMerged: boolean, ngContentIndex: number,
|
||||||
children: any[]) {
|
children: any[]) {
|
||||||
return appCmds.embeddedTemplate(attrNameAndValues, [], [], isMerged, ngContentIndex, null,
|
return new appCmds.EmbeddedTemplateCmd(attrNameAndValues, [], [], isMerged, ngContentIndex, null,
|
||||||
children);
|
children);
|
||||||
}
|
}
|
||||||
|
|
||||||
function beginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
function beginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||||
nativeShadow: boolean, ngContentIndex: number, templateId: number) {
|
ngContentIndex: number, templateId: string) {
|
||||||
return appCmds.beginComponent(name, attrNameAndValues, eventTargetAndNames, [], [], nativeShadow,
|
return new appCmds.BeginComponentCmd(
|
||||||
ngContentIndex, new appCmds.CompiledTemplate(templateId, null));
|
name, attrNameAndValues, eventTargetAndNames, [], [], null, ngContentIndex,
|
||||||
|
() => new appCmds.CompiledComponentTemplate(templateId, null, null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
function endComponent() {
|
function endComponent() {
|
||||||
return appCmds.endComponent();
|
return new appCmds.EndComponentCmd();
|
||||||
}
|
}
|
||||||
|
|
||||||
function ngContent(index: number, ngContentIndex: number) {
|
function ngContent(index: number, ngContentIndex: number) {
|
||||||
return appCmds.ngContent(index, ngContentIndex);
|
return new appCmds.NgContentCmd(index, ngContentIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('createRenderView', () => {
|
describe('createRenderView', () => {
|
||||||
var nodeFactory: DomNodeFactory;
|
var nodeFactory: DomNodeFactory;
|
||||||
var eventDispatcher: SpyRenderEventDispatcher;
|
var eventDispatcher: SpyRenderEventDispatcher;
|
||||||
var componentTemplates = new Map<number, RenderTemplateCmd[]>();
|
var componentTemplates = new Map<string, RenderComponentTemplate | RenderTemplateCmd[]>();
|
||||||
|
var defaultCmpTpl: RenderComponentTemplate;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
nodeFactory = new DomNodeFactory(componentTemplates);
|
nodeFactory = new DomNodeFactory(componentTemplates);
|
||||||
eventDispatcher = new SpyRenderEventDispatcher();
|
eventDispatcher = new SpyRenderEventDispatcher();
|
||||||
|
defaultCmpTpl =
|
||||||
|
new RenderComponentTemplate('someId', 'shortid', ViewEncapsulation.None, [], []);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('primitives', () => {
|
describe('primitives', () => {
|
||||||
|
|
||||||
it('should create elements with attributes', () => {
|
it('should create elements with attributes', () => {
|
||||||
var view = createRenderView(
|
var view = createRenderView(
|
||||||
|
defaultCmpTpl,
|
||||||
[beginElement('div', ['attr1', 'value1'], [], false, null), endElement()], null,
|
[beginElement('div', ['attr1', 'value1'], [], false, null), endElement()], null,
|
||||||
nodeFactory);
|
nodeFactory);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<div attr1="value1"></div>');
|
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<div attr1="value1"></div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create host elements with attributes', () => {
|
it('should create host elements with attributes', () => {
|
||||||
componentTemplates.set(0, []);
|
componentTemplates.set('0', []);
|
||||||
var view = createRenderView(
|
var view = createRenderView(
|
||||||
[beginComponent('a-comp', ['attr1', 'value1'], [], false, null, 0), endElement()], null,
|
defaultCmpTpl,
|
||||||
|
[beginComponent('a-comp', ['attr1', 'value1'], [], null, '0'), endElement()], null,
|
||||||
nodeFactory);
|
nodeFactory);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes))
|
expect(stringifyFragment(view.fragments[0].nodes))
|
||||||
.toEqual('<a-comp attr1="value1"></a-comp>');
|
.toEqual('<a-comp attr1="value1"></a-comp>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create embedded templates with attributes', () => {
|
it('should create embedded templates with attributes', () => {
|
||||||
componentTemplates.set(0, []);
|
componentTemplates.set('0', []);
|
||||||
var view = createRenderView([embeddedTemplate(['attr1', 'value1'], false, null, [])], null,
|
var view = createRenderView(defaultCmpTpl,
|
||||||
|
[embeddedTemplate(['attr1', 'value1'], false, null, [])], null,
|
||||||
nodeFactory);
|
nodeFactory);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes))
|
expect(stringifyFragment(view.fragments[0].nodes))
|
||||||
.toEqual('<template attr1="value1"></template>');
|
.toEqual('<template attr1="value1"></template>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should store bound elements', () => {
|
it('should store bound elements', () => {
|
||||||
componentTemplates.set(0, []);
|
componentTemplates.set('0', []);
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginElement('div', ['id', '1'], [], false, null),
|
beginElement('div', ['id', '1'], [], false, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
beginElement('span', ['id', '2'], [], true, null),
|
beginElement('span', ['id', '2'], [], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
beginComponent('a-comp', ['id', '3'], [], false, null, 0),
|
beginComponent('a-comp', ['id', '3'], [], null, '0'),
|
||||||
endElement(),
|
endElement(),
|
||||||
embeddedTemplate(['id', '4'], false, null, [])
|
embeddedTemplate(['id', '4'], false, null, [])
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
expect(mapAttrs(view.boundElements, 'id')).toEqual(['2', '3', '4']);
|
expect(mapAttrs(view.boundElements, 'id')).toEqual(['2', '3', '4']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use the inplace element for the first create element', () => {
|
it('should use the inplace element for the first create element', () => {
|
||||||
var el = DOM.createElement('span');
|
var el = DOM.createElement('span');
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginElement('div', ['attr1', 'value1'], [], false, null),
|
beginElement('div', ['attr1', 'value1'], [], false, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
beginElement('div', [], [], false, null),
|
beginElement('div', [], [], false, null),
|
||||||
endElement()
|
endElement()
|
||||||
],
|
],
|
||||||
el, nodeFactory);
|
el, nodeFactory);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes))
|
expect(stringifyFragment(view.fragments[0].nodes))
|
||||||
.toEqual('<span attr1="value1"></span><div></div>');
|
.toEqual('<span attr1="value1"></span><div></div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create text nodes', () => {
|
it('should create text nodes', () => {
|
||||||
var view = createRenderView([text('someText', false, null)], null, nodeFactory);
|
var view =
|
||||||
|
createRenderView(defaultCmpTpl, [text('someText', false, null)], null, nodeFactory);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('someText');
|
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('someText');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should store bound text nodes', () => {
|
it('should store bound text nodes', () => {
|
||||||
var view =
|
var view = createRenderView(defaultCmpTpl, [text('1', false, null), text('2', true, null)],
|
||||||
createRenderView([text('1', false, null), text('2', true, null)], null, nodeFactory);
|
null, nodeFactory);
|
||||||
expect(stringifyElement(view.boundTextNodes[0])).toEqual('2');
|
expect(stringifyElement(view.boundTextNodes[0])).toEqual('2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should register element event listeners', () => {
|
it('should register element event listeners', () => {
|
||||||
componentTemplates.set(0, []);
|
componentTemplates.set('0', []);
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginElement('div', [], [null, 'click'], true, null),
|
beginElement('div', [], [null, 'click'], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
beginComponent('a-comp', [], [null, 'click'], false, null, 0),
|
beginComponent('a-comp', [], [null, 'click'], null, '0'),
|
||||||
endElement(),
|
endElement(),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
view.setEventDispatcher(<any>eventDispatcher);
|
view.setEventDispatcher(<any>eventDispatcher);
|
||||||
var event = {};
|
var event = {};
|
||||||
nodeFactory.triggerLocalEvent(view.boundElements[0], 'click', event);
|
nodeFactory.triggerLocalEvent(view.boundElements[0], 'click', event);
|
||||||
|
@ -151,14 +169,14 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should register element global event listeners', () => {
|
it('should register element global event listeners', () => {
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginElement('div', [], ['window', 'scroll'], true, null),
|
beginElement('div', [], ['window', 'scroll'], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
beginComponent('a-comp', [], ['window', 'scroll'], false, null, 0),
|
beginComponent('a-comp', [], ['window', 'scroll'], null, '0'),
|
||||||
endElement(),
|
endElement(),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
view.hydrate();
|
view.hydrate();
|
||||||
view.setEventDispatcher(<any>eventDispatcher);
|
view.setEventDispatcher(<any>eventDispatcher);
|
||||||
var event = {};
|
var event = {};
|
||||||
|
@ -175,67 +193,72 @@ export function main() {
|
||||||
|
|
||||||
describe('nested nodes', () => {
|
describe('nested nodes', () => {
|
||||||
it('should create nested node', () => {
|
it('should create nested node', () => {
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginElement('a', [], [], false, null),
|
beginElement('a', [], [], false, null),
|
||||||
beginElement('b', [], [], false, null),
|
beginElement('b', [], [], false, null),
|
||||||
text('someText', false, null),
|
text('someText', false, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
endElement(),
|
endElement(),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<a><b>someText</b></a>');
|
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<a><b>someText</b></a>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should store bound elements in depth first order', () => {
|
it('should store bound elements in depth first order', () => {
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginElement('a', ['id', '1'], [], false, null),
|
beginElement('a', ['id', '1'], [], false, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
beginElement('a', ['id', '2'], [], true, null),
|
beginElement('a', ['id', '2'], [], true, null),
|
||||||
beginElement('a', ['id', '3'], [], false, null),
|
beginElement('a', ['id', '3'], [], false, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
beginElement('a', ['id', '4'], [], true, null),
|
beginElement('a', ['id', '4'], [], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
endElement(),
|
endElement(),
|
||||||
beginElement('a', ['id', '5'], [], false, null),
|
beginElement('a', ['id', '5'], [], false, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
beginElement('a', ['id', '6'], [], true, null),
|
beginElement('a', ['id', '6'], [], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
expect(mapAttrs(view.boundElements, 'id')).toEqual(['2', '4', '6']);
|
expect(mapAttrs(view.boundElements, 'id')).toEqual(['2', '4', '6']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should store bound text nodes in depth first order', () => {
|
it('should store bound text nodes in depth first order', () => {
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
text('1', false, null),
|
text('1', false, null),
|
||||||
text('2', true, null),
|
text('2', true, null),
|
||||||
beginElement('a', [], [], false, null),
|
beginElement('a', [], [], false, null),
|
||||||
text('3', false, null),
|
text('3', false, null),
|
||||||
text('4', true, null),
|
text('4', true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
text('5', false, null),
|
text('5', false, null),
|
||||||
text('6', true, null),
|
text('6', true, null),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
expect(mapText(view.boundTextNodes)).toEqual(['2', '4', '6']);
|
expect(mapText(view.boundTextNodes)).toEqual(['2', '4', '6']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('merged embedded templates', () => {
|
describe('merged embedded templates',
|
||||||
it('should create separate fragments', () => {
|
() => {
|
||||||
var view = createRenderView(
|
it('should create separate fragments', () => {
|
||||||
[embeddedTemplate(['attr1', 'value1'], true, null, [text('someText', false, null)])],
|
var view = createRenderView(defaultCmpTpl,
|
||||||
null, nodeFactory);
|
[
|
||||||
expect(view.fragments.length).toBe(2);
|
embeddedTemplate(['attr1', 'value1'], true, null,
|
||||||
expect(stringifyFragment(view.fragments[1].nodes)).toEqual('someText');
|
[text('someText', false, null)])
|
||||||
});
|
],
|
||||||
|
null, nodeFactory);
|
||||||
|
expect(view.fragments.length).toBe(2);
|
||||||
|
expect(stringifyFragment(view.fragments[1].nodes)).toEqual('someText');
|
||||||
|
});
|
||||||
|
|
||||||
it('should store bound elements after the bound elements of earlier fragments', () => {
|
it('should store bound elements after the bound elements of earlier fragments',
|
||||||
var view =
|
() => {
|
||||||
createRenderView(
|
var view =
|
||||||
|
createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginElement('a', ['id', '1.1'], [], true, null),
|
beginElement('a', ['id', '1.1'], [], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
|
@ -254,13 +277,14 @@ export function main() {
|
||||||
endElement(),
|
endElement(),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
expect(mapAttrs(view.boundElements, 'id'))
|
expect(mapAttrs(view.boundElements, 'id'))
|
||||||
.toEqual(['1.1', '1.2', '1.3', '2.1', '2.2', '3.1']);
|
.toEqual(['1.1', '1.2', '1.3', '2.1', '2.2', '3.1']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should store bound text nodes after the bound text nodes of earlier fragments', () => {
|
it('should store bound text nodes after the bound text nodes of earlier fragments',
|
||||||
var view =
|
() => {
|
||||||
createRenderView(
|
var view =
|
||||||
|
createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
text('1.1', true, null),
|
text('1.1', true, null),
|
||||||
embeddedTemplate(['id', '1.2'], true, null,
|
embeddedTemplate(['id', '1.2'], true, null,
|
||||||
|
@ -275,23 +299,25 @@ export function main() {
|
||||||
text('1.2', true, null),
|
text('1.2', true, null),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
expect(mapText(view.boundTextNodes)).toEqual(['1.1', '1.2', '2.1', '2.2', '3.1']);
|
expect(mapText(view.boundTextNodes))
|
||||||
});
|
.toEqual(['1.1', '1.2', '2.1', '2.2', '3.1']);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('non merged embedded templates', () => {
|
describe('non merged embedded templates', () => {
|
||||||
it('should only create the anchor element', () => {
|
it('should only create the anchor element', () => {
|
||||||
var view = createRenderView(
|
var view =
|
||||||
[
|
createRenderView(defaultCmpTpl,
|
||||||
embeddedTemplate(['id', '1.1'], false, null,
|
[
|
||||||
[
|
embeddedTemplate(['id', '1.1'], false, null,
|
||||||
text('someText', true, null),
|
[
|
||||||
beginElement('a', ['id', '2.1'], [], true, null),
|
text('someText', true, null),
|
||||||
endElement()
|
beginElement('a', ['id', '2.1'], [], true, null),
|
||||||
])
|
endElement()
|
||||||
],
|
])
|
||||||
null, nodeFactory);
|
],
|
||||||
|
null, nodeFactory);
|
||||||
expect(view.fragments.length).toBe(1);
|
expect(view.fragments.length).toBe(1);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes))
|
expect(stringifyFragment(view.fragments[0].nodes))
|
||||||
.toEqual('<template id="1.1"></template>');
|
.toEqual('<template id="1.1"></template>');
|
||||||
|
@ -302,46 +328,52 @@ export function main() {
|
||||||
|
|
||||||
describe('components', () => {
|
describe('components', () => {
|
||||||
it('should store the component template in the same fragment', () => {
|
it('should store the component template in the same fragment', () => {
|
||||||
componentTemplates.set(0, [
|
componentTemplates.set('0', [
|
||||||
text('hello', false, null),
|
text('hello', false, null),
|
||||||
]);
|
]);
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[beginComponent('my-comp', [], [], false, null, 0), endComponent()], null, nodeFactory);
|
[beginComponent('my-comp', [], [], null, '0'), endComponent()],
|
||||||
|
null, nodeFactory);
|
||||||
expect(view.fragments.length).toBe(1);
|
expect(view.fragments.length).toBe(1);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<my-comp>hello</my-comp>');
|
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<my-comp>hello</my-comp>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use native shadow DOM', () => {
|
it('should use native shadow DOM', () => {
|
||||||
componentTemplates.set(0, [
|
componentTemplates.set(
|
||||||
text('hello', false, null),
|
'0', new RenderComponentTemplate('someId', 'shortid', ViewEncapsulation.Native,
|
||||||
]);
|
[
|
||||||
var view = createRenderView(
|
text('hello', false, null),
|
||||||
[beginComponent('my-comp', [], [], true, null, 0), endComponent()], null, nodeFactory);
|
],
|
||||||
|
[]));
|
||||||
|
var view = createRenderView(defaultCmpTpl,
|
||||||
|
[beginComponent('my-comp', [], [], null, '0'), endComponent()],
|
||||||
|
null, nodeFactory);
|
||||||
expect(view.fragments.length).toBe(1);
|
expect(view.fragments.length).toBe(1);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes))
|
expect(stringifyFragment(view.fragments[0].nodes))
|
||||||
.toEqual('<my-comp><shadow-root>hello</shadow-root></my-comp>');
|
.toEqual('<my-comp><shadow-root>hello</shadow-root></my-comp>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should store bound elements after the bound elements of the main template', () => {
|
it('should store bound elements after the bound elements of the main template', () => {
|
||||||
componentTemplates.set(0, [
|
componentTemplates.set('0', [
|
||||||
beginComponent('b-comp', ['id', '2.1'], [], false, null, 1),
|
beginComponent('b-comp', ['id', '2.1'], [], null, '1'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
beginComponent('b-comp', ['id', '2.2'], [], false, null, 1),
|
beginComponent('b-comp', ['id', '2.2'], [], null, '1'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
]);
|
]);
|
||||||
componentTemplates.set(1, [beginElement('a', ['id', '3.1'], [], true, null), endElement()]);
|
componentTemplates.set('1',
|
||||||
var view = createRenderView(
|
[beginElement('a', ['id', '3.1'], [], true, null), endElement()]);
|
||||||
[
|
var view = createRenderView(defaultCmpTpl,
|
||||||
beginElement('a', ['id', '1.1'], [], true, null),
|
[
|
||||||
endElement(),
|
beginElement('a', ['id', '1.1'], [], true, null),
|
||||||
beginComponent('a-comp', ['id', '1.2'], [], false, null, 0),
|
endElement(),
|
||||||
beginElement('a', ['id', '1.3'], [], true, null),
|
beginComponent('a-comp', ['id', '1.2'], [], null, '0'),
|
||||||
endElement(),
|
beginElement('a', ['id', '1.3'], [], true, null),
|
||||||
endComponent(),
|
endElement(),
|
||||||
beginElement('a', ['id', '1.4'], [], true, null),
|
endComponent(),
|
||||||
endElement(),
|
beginElement('a', ['id', '1.4'], [], true, null),
|
||||||
],
|
endElement(),
|
||||||
null, nodeFactory);
|
],
|
||||||
|
null, nodeFactory);
|
||||||
|
|
||||||
expect(mapAttrs(view.boundElements, 'id'))
|
expect(mapAttrs(view.boundElements, 'id'))
|
||||||
.toEqual(['1.1', '1.2', '1.3', '1.4', '2.1', '2.2', '3.1', '3.1']);
|
.toEqual(['1.1', '1.2', '1.3', '1.4', '2.1', '2.2', '3.1', '3.1']);
|
||||||
|
@ -349,64 +381,64 @@ export function main() {
|
||||||
|
|
||||||
it('should store bound elements from the view before bound elements from content components',
|
it('should store bound elements from the view before bound elements from content components',
|
||||||
() => {
|
() => {
|
||||||
componentTemplates.set(0, [
|
componentTemplates.set('0', [
|
||||||
beginElement('a', ['id', '2.1'], [], true, null),
|
beginElement('a', ['id', '2.1'], [], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
]);
|
]);
|
||||||
componentTemplates.set(1, [
|
componentTemplates.set('1', [
|
||||||
beginElement('a', ['id', '3.1'], [], true, null),
|
beginElement('a', ['id', '3.1'], [], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
]);
|
]);
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginComponent('a-comp', ['id', '1.1'], [], false, null, 0),
|
beginComponent('a-comp', ['id', '1.1'], [], null, '0'),
|
||||||
beginComponent('b-comp', ['id', '1.2'], [], false, null, 1),
|
beginComponent('b-comp', ['id', '1.2'], [], null, '1'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
|
|
||||||
expect(mapAttrs(view.boundElements, 'id')).toEqual(['1.1', '1.2', '2.1', '3.1']);
|
expect(mapAttrs(view.boundElements, 'id')).toEqual(['1.1', '1.2', '2.1', '3.1']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should process nested components in depth first order', () => {
|
it('should process nested components in depth first order', () => {
|
||||||
componentTemplates.set(0, [
|
componentTemplates.set('0', [
|
||||||
beginComponent('b11-comp', ['id', '2.1'], [], false, null, 2),
|
beginComponent('b11-comp', ['id', '2.1'], [], null, '2'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
beginComponent('b12-comp', ['id', '2.2'], [], false, null, 3),
|
beginComponent('b12-comp', ['id', '2.2'], [], null, '3'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
]);
|
]);
|
||||||
componentTemplates.set(1, [
|
componentTemplates.set('1', [
|
||||||
beginComponent('b21-comp', ['id', '3.1'], [], false, null, 4),
|
beginComponent('b21-comp', ['id', '3.1'], [], null, '4'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
beginComponent('b22-comp', ['id', '3.2'], [], false, null, 5),
|
beginComponent('b22-comp', ['id', '3.2'], [], null, '5'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
]);
|
]);
|
||||||
componentTemplates.set(2, [
|
componentTemplates.set('2', [
|
||||||
beginElement('b11', ['id', '4.11'], [], true, null),
|
beginElement('b11', ['id', '4.11'], [], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
]);
|
]);
|
||||||
componentTemplates.set(3, [
|
componentTemplates.set('3', [
|
||||||
beginElement('b12', ['id', '4.12'], [], true, null),
|
beginElement('b12', ['id', '4.12'], [], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
]);
|
]);
|
||||||
componentTemplates.set(4, [
|
componentTemplates.set('4', [
|
||||||
beginElement('b21', ['id', '4.21'], [], true, null),
|
beginElement('b21', ['id', '4.21'], [], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
]);
|
]);
|
||||||
componentTemplates.set(5, [
|
componentTemplates.set('5', [
|
||||||
beginElement('b22', ['id', '4.22'], [], true, null),
|
beginElement('b22', ['id', '4.22'], [], true, null),
|
||||||
endElement(),
|
endElement(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginComponent('a1-comp', ['id', '1.1'], [], false, null, 0),
|
beginComponent('a1-comp', ['id', '1.1'], [], null, '0'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
beginComponent('a2-comp', ['id', '1.2'], [], false, null, 1),
|
beginComponent('a2-comp', ['id', '1.2'], [], null, '1'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
|
|
||||||
expect(mapAttrs(view.boundElements, 'id'))
|
expect(mapAttrs(view.boundElements, 'id'))
|
||||||
.toEqual(['1.1', '1.2', '2.1', '2.2', '4.11', '4.12', '3.1', '3.2', '4.21', '4.22']);
|
.toEqual(['1.1', '1.2', '2.1', '2.2', '4.11', '4.12', '3.1', '3.2', '4.21', '4.22']);
|
||||||
|
@ -414,26 +446,26 @@ export function main() {
|
||||||
|
|
||||||
|
|
||||||
it('should store bound text nodes after the bound text nodes of the main template', () => {
|
it('should store bound text nodes after the bound text nodes of the main template', () => {
|
||||||
componentTemplates.set(0, [
|
componentTemplates.set('0', [
|
||||||
text('2.1', true, null),
|
text('2.1', true, null),
|
||||||
beginComponent('b-comp', [], [], false, null, 1),
|
beginComponent('b-comp', [], [], null, '1'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
beginComponent('b-comp', [], [], false, null, 1),
|
beginComponent('b-comp', [], [], null, '1'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
text('2.2', true, null),
|
text('2.2', true, null),
|
||||||
]);
|
]);
|
||||||
componentTemplates.set(1, [
|
componentTemplates.set('1', [
|
||||||
text('3.1', true, null),
|
text('3.1', true, null),
|
||||||
]);
|
]);
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
text('1.1', true, null),
|
text('1.1', true, null),
|
||||||
beginComponent('a-comp', [], [], false, null, 0),
|
beginComponent('a-comp', [], [], null, '0'),
|
||||||
text('1.2', true, null),
|
text('1.2', true, null),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
text('1.3', true, null),
|
text('1.3', true, null),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
|
|
||||||
expect(mapText(view.boundTextNodes))
|
expect(mapText(view.boundTextNodes))
|
||||||
.toEqual(['1.1', '1.2', '1.3', '2.1', '2.2', '3.1', '3.1']);
|
.toEqual(['1.1', '1.2', '1.3', '2.1', '2.2', '3.1', '3.1']);
|
||||||
|
@ -442,77 +474,75 @@ export function main() {
|
||||||
|
|
||||||
it('should store bound text nodes from the view before bound text nodes from content components',
|
it('should store bound text nodes from the view before bound text nodes from content components',
|
||||||
() => {
|
() => {
|
||||||
componentTemplates.set(0, [text('2.1', true, null)]);
|
componentTemplates.set('0', [text('2.1', true, null)]);
|
||||||
componentTemplates.set(1, [text('3.1', true, null)]);
|
componentTemplates.set('1', [text('3.1', true, null)]);
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginComponent('a-comp', [], [], false, null, 0),
|
beginComponent('a-comp', [], [], null, '0'),
|
||||||
beginComponent('b-comp', [], [], false, null, 1),
|
beginComponent('b-comp', [], [], null, '1'),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
endComponent(),
|
endComponent(),
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
|
|
||||||
expect(mapText(view.boundTextNodes)).toEqual(['2.1', '3.1']);
|
expect(mapText(view.boundTextNodes)).toEqual(['2.1', '3.1']);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('content projection', () => {
|
describe('content projection', () => {
|
||||||
it('should remove non projected nodes', () => {
|
it('should remove non projected nodes', () => {
|
||||||
componentTemplates.set(0, []);
|
componentTemplates.set('0', []);
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginComponent('my-comp', [], [], false, null, 0),
|
beginComponent('my-comp', [], [], null, '0'),
|
||||||
text('hello', false, null),
|
text('hello', false, null),
|
||||||
endComponent()
|
endComponent()
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<my-comp></my-comp>');
|
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<my-comp></my-comp>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should keep non projected nodes in the light dom when using native shadow dom', () => {
|
it('should keep non projected nodes in the light dom when using native shadow dom', () => {
|
||||||
componentTemplates.set(0, []);
|
componentTemplates.set('0', new RenderComponentTemplate('someId', 'shortid',
|
||||||
var view = createRenderView(
|
ViewEncapsulation.Native, [], []));
|
||||||
[
|
var view = createRenderView(defaultCmpTpl,
|
||||||
beginComponent('my-comp', [], [], true, null, 0),
|
[
|
||||||
text('hello', false, null),
|
beginComponent('my-comp', [], [], null, '0'),
|
||||||
endComponent()
|
text('hello', false, null),
|
||||||
],
|
endComponent()
|
||||||
null, nodeFactory);
|
],
|
||||||
|
null, nodeFactory);
|
||||||
var rootEl = view.fragments[0].nodes[0];
|
var rootEl = view.fragments[0].nodes[0];
|
||||||
expect(stringifyElement(rootEl))
|
expect(stringifyElement(rootEl))
|
||||||
.toEqual('<my-comp><shadow-root></shadow-root>hello</my-comp>');
|
.toEqual('<my-comp><shadow-root></shadow-root>hello</my-comp>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should project commands based on their ngContentIndex', () => {
|
it('should project commands based on their ngContentIndex', () => {
|
||||||
componentTemplates.set(0, [
|
componentTemplates.set('0', [
|
||||||
text('(', false, null),
|
text('(', false, null),
|
||||||
ngContent(0, null),
|
ngContent(0, null),
|
||||||
text(',', false, null),
|
text(',', false, null),
|
||||||
ngContent(1, null),
|
ngContent(1, null),
|
||||||
text(')', false, null)
|
text(')', false, null)
|
||||||
]);
|
]);
|
||||||
var view = createRenderView(
|
var view = createRenderView(defaultCmpTpl,
|
||||||
[
|
[
|
||||||
beginComponent('my-comp', [], [], false, null, 0),
|
beginComponent('my-comp', [], [], null, '0'),
|
||||||
text('2', false, 1),
|
text('2', false, 1),
|
||||||
text('1', false, 0),
|
text('1', false, 0),
|
||||||
endComponent()
|
endComponent()
|
||||||
],
|
],
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<my-comp>(1,2)</my-comp>');
|
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<my-comp>(1,2)</my-comp>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reproject nodes over multiple ng-content commands', () => {
|
it('should reproject nodes over multiple ng-content commands', () => {
|
||||||
componentTemplates.set(
|
componentTemplates.set(
|
||||||
0, [beginComponent('b-comp', [], [], false, null, 1), ngContent(0, 0), endComponent()]);
|
'0', [beginComponent('b-comp', [], [], null, '1'), ngContent(0, 0), endComponent()]);
|
||||||
componentTemplates.set(
|
componentTemplates.set(
|
||||||
1, [text('(', false, null), ngContent(0, null), text(')', false, null)]);
|
'1', [text('(', false, null), ngContent(0, null), text(')', false, null)]);
|
||||||
var view = createRenderView(
|
var view = createRenderView(
|
||||||
[
|
defaultCmpTpl,
|
||||||
beginComponent('a-comp', [], [], false, null, 0),
|
[beginComponent('a-comp', [], [], null, '0'), text('hello', false, 0), endComponent()],
|
||||||
text('hello', false, 0),
|
|
||||||
endComponent()
|
|
||||||
],
|
|
||||||
null, nodeFactory);
|
null, nodeFactory);
|
||||||
expect(stringifyFragment(view.fragments[0].nodes))
|
expect(stringifyFragment(view.fragments[0].nodes))
|
||||||
.toEqual('<a-comp><b-comp>(hello)</b-comp></a-comp>');
|
.toEqual('<a-comp><b-comp>(hello)</b-comp></a-comp>');
|
||||||
|
@ -520,14 +550,97 @@ export function main() {
|
||||||
|
|
||||||
|
|
||||||
it('should store content injection points for root component in a view', () => {
|
it('should store content injection points for root component in a view', () => {
|
||||||
componentTemplates.set(0, [ngContent(0, null)]);
|
componentTemplates.set('0', [ngContent(0, null)]);
|
||||||
var view =
|
var view = createRenderView(defaultCmpTpl,
|
||||||
createRenderView([beginComponent('a-comp', [], [], false, null, 0), endComponent()],
|
[beginComponent('a-comp', [], [], null, '0'), endComponent()],
|
||||||
DOM.createElement('root'), nodeFactory);
|
DOM.createElement('root'), nodeFactory);
|
||||||
expect(stringifyFragment(view.rootContentInsertionPoints))
|
expect(stringifyFragment(view.rootContentInsertionPoints))
|
||||||
.toEqual('<root-content-insertion-point></root-content-insertion-point>');
|
.toEqual('<root-content-insertion-point></root-content-insertion-point>');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('view encapsulation', () => {
|
||||||
|
it('should not add attributes to elements in template with ViewEncapsulation.None', () => {
|
||||||
|
var tpl = new RenderComponentTemplate('someId', 'shortid', ViewEncapsulation.None, [], []);
|
||||||
|
var view = createRenderView(tpl, [beginElement('div', [], [], false, null), endElement()],
|
||||||
|
null, nodeFactory);
|
||||||
|
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<div></div>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not add attributes to elements in template with ViewEncapsulation.Native', () => {
|
||||||
|
var tpl =
|
||||||
|
new RenderComponentTemplate('someId', 'shortid', ViewEncapsulation.Native, [], []);
|
||||||
|
var view = createRenderView(tpl, [beginElement('div', [], [], false, null), endElement()],
|
||||||
|
null, nodeFactory);
|
||||||
|
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<div></div>');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ViewEncapsulation.Emulated', () => {
|
||||||
|
var encapsulatedTpl;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
encapsulatedTpl =
|
||||||
|
new RenderComponentTemplate('someId', 'shortid', ViewEncapsulation.Emulated, [], []);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add marker attributes to content elements', () => {
|
||||||
|
var view = createRenderView(encapsulatedTpl,
|
||||||
|
[beginElement('div', [], [], false, null), endElement()],
|
||||||
|
null, nodeFactory);
|
||||||
|
expect(stringifyFragment(view.fragments[0].nodes))
|
||||||
|
.toEqual('<div _ngcontent-shortid=""></div>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add marker attributes to content elements in merged embedded templates', () => {
|
||||||
|
var view = createRenderView(
|
||||||
|
encapsulatedTpl,
|
||||||
|
[
|
||||||
|
embeddedTemplate([], true, null,
|
||||||
|
[beginElement('div', [], [], false, null), endElement()])
|
||||||
|
],
|
||||||
|
null, nodeFactory);
|
||||||
|
expect(stringifyFragment(view.fragments[0].nodes)).toEqual('<template></template>');
|
||||||
|
expect(stringifyFragment(view.fragments[1].nodes))
|
||||||
|
.toEqual('<div _ngcontent-shortid=""></div>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add marker attributes to host elements and content elements of nested components',
|
||||||
|
() => {
|
||||||
|
componentTemplates.set(
|
||||||
|
'0', new RenderComponentTemplate(
|
||||||
|
'innerComp', 'innerid', ViewEncapsulation.Emulated,
|
||||||
|
[beginElement('div', [], [], false, null), endElement()], []));
|
||||||
|
var view = createRenderView(
|
||||||
|
encapsulatedTpl, [beginComponent('my-comp', [], [], null, '0'), endComponent()],
|
||||||
|
null, nodeFactory);
|
||||||
|
expect(stringifyFragment(view.fragments[0].nodes))
|
||||||
|
.toEqual(
|
||||||
|
'<my-comp _ngcontent-shortid="" _nghost-innerid=""><div _ngcontent-innerid=""></div></my-comp>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('encapsulateStyles', () => {
|
||||||
|
const input = 'div[%COMP%] {}';
|
||||||
|
|
||||||
|
it('should not change styles for ViewEncapsulation.Native', () => {
|
||||||
|
var tpl =
|
||||||
|
new RenderComponentTemplate('someId', 'shortid', ViewEncapsulation.Native, [], [input]);
|
||||||
|
expect(encapsulateStyles(tpl)).toEqual([input]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not change styles for ViewEncapsulation.None', () => {
|
||||||
|
var tpl =
|
||||||
|
new RenderComponentTemplate('someId', 'shortid', ViewEncapsulation.None, [], [input]);
|
||||||
|
expect(encapsulateStyles(tpl)).toEqual([input]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change styles for ViewEncapsulation.Emulated', () => {
|
||||||
|
var tpl =
|
||||||
|
new RenderComponentTemplate('someId', 'shortid', ViewEncapsulation.Emulated, [], [input]);
|
||||||
|
expect(encapsulateStyles(tpl)).toEqual(['div[shortid] {}']);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,7 +648,7 @@ class DomNodeFactory implements NodeFactory<Node> {
|
||||||
private _globalEventListeners: GlobalEventListener[] = [];
|
private _globalEventListeners: GlobalEventListener[] = [];
|
||||||
private _localEventListeners: LocalEventListener[] = [];
|
private _localEventListeners: LocalEventListener[] = [];
|
||||||
|
|
||||||
constructor(private _components: Map<number, RenderTemplateCmd[]>) {}
|
constructor(private _components: Map<string, RenderComponentTemplate | RenderTemplateCmd[]>) {}
|
||||||
|
|
||||||
triggerLocalEvent(el: Element, eventName: string, event: any) {
|
triggerLocalEvent(el: Element, eventName: string, event: any) {
|
||||||
this._localEventListeners.forEach(listener => {
|
this._localEventListeners.forEach(listener => {
|
||||||
|
@ -553,8 +666,14 @@ class DomNodeFactory implements NodeFactory<Node> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveComponentTemplate(templateId: number): RenderTemplateCmd[] {
|
resolveComponentTemplate(templateId: string): RenderComponentTemplate {
|
||||||
return this._components.get(templateId);
|
var data = this._components.get(templateId);
|
||||||
|
if (data instanceof RenderComponentTemplate) {
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
return new RenderComponentTemplate(templateId, templateId, ViewEncapsulation.None,
|
||||||
|
<RenderTemplateCmd[]>data, []);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
createTemplateAnchor(attrNameAndValues: string[]): Node {
|
createTemplateAnchor(attrNameAndValues: string[]): Node {
|
||||||
var el = DOM.createElement('template');
|
var el = DOM.createElement('template');
|
||||||
|
@ -575,7 +694,7 @@ class DomNodeFactory implements NodeFactory<Node> {
|
||||||
DOM.setAttribute(el, attrNameAndValues[attrIdx], attrNameAndValues[attrIdx + 1]);
|
DOM.setAttribute(el, attrNameAndValues[attrIdx], attrNameAndValues[attrIdx + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createShadowRoot(host: Node, templateId: number): Node {
|
createShadowRoot(host: Node, templateId: string): Node {
|
||||||
var root = DOM.createElement('shadow-root');
|
var root = DOM.createElement('shadow-root');
|
||||||
DOM.appendChild(host, root);
|
DOM.appendChild(host, root);
|
||||||
return root;
|
return root;
|
||||||
|
|
|
@ -1274,34 +1274,36 @@ var NG_ALL = [
|
||||||
'PipeTransform:dart',
|
'PipeTransform:dart',
|
||||||
'RenderBeginCmd:dart',
|
'RenderBeginCmd:dart',
|
||||||
'RenderBeginCmd.isBound',
|
'RenderBeginCmd.isBound',
|
||||||
'RenderBeginCmd.isBound=',
|
|
||||||
'RenderBeginCmd.ngContentIndex',
|
'RenderBeginCmd.ngContentIndex',
|
||||||
'RenderBeginCmd.ngContentIndex=',
|
|
||||||
'RenderBeginComponentCmd:dart',
|
'RenderBeginComponentCmd:dart',
|
||||||
'RenderBeginComponentCmd.nativeShadow',
|
'RenderBeginComponentCmd.attrNameAndValues',
|
||||||
'RenderBeginComponentCmd.nativeShadow=',
|
'RenderBeginComponentCmd.eventTargetAndNames',
|
||||||
|
'RenderBeginComponentCmd.isBound',
|
||||||
|
'RenderBeginComponentCmd.name',
|
||||||
|
'RenderBeginComponentCmd.ngContentIndex',
|
||||||
'RenderBeginComponentCmd.templateId',
|
'RenderBeginComponentCmd.templateId',
|
||||||
'RenderBeginComponentCmd.templateId=',
|
|
||||||
'RenderBeginElementCmd:dart',
|
'RenderBeginElementCmd:dart',
|
||||||
'RenderBeginElementCmd.attrNameAndValues',
|
'RenderBeginElementCmd.attrNameAndValues',
|
||||||
'RenderBeginElementCmd.attrNameAndValues=',
|
'RenderBeginElementCmd.isBound',
|
||||||
'RenderBeginElementCmd.eventTargetAndNames',
|
'RenderBeginElementCmd.eventTargetAndNames',
|
||||||
'RenderBeginElementCmd.eventTargetAndNames=',
|
|
||||||
'RenderBeginElementCmd.name',
|
'RenderBeginElementCmd.name',
|
||||||
'RenderBeginElementCmd.name=',
|
'RenderBeginElementCmd.ngContentIndex',
|
||||||
'RenderCommandVisitor:dart',
|
'RenderCommandVisitor:dart',
|
||||||
'RenderEmbeddedTemplateCmd:dart',
|
'RenderEmbeddedTemplateCmd:dart',
|
||||||
|
'RenderEmbeddedTemplateCmd.attrNameAndValues',
|
||||||
'RenderEmbeddedTemplateCmd.children',
|
'RenderEmbeddedTemplateCmd.children',
|
||||||
'RenderEmbeddedTemplateCmd.children=',
|
'RenderEmbeddedTemplateCmd.eventTargetAndNames',
|
||||||
|
'RenderEmbeddedTemplateCmd.isBound',
|
||||||
'RenderEmbeddedTemplateCmd.isMerged',
|
'RenderEmbeddedTemplateCmd.isMerged',
|
||||||
'RenderEmbeddedTemplateCmd.isMerged=',
|
'RenderEmbeddedTemplateCmd.name',
|
||||||
|
'RenderEmbeddedTemplateCmd.ngContentIndex',
|
||||||
'RenderNgContentCmd:dart',
|
'RenderNgContentCmd:dart',
|
||||||
'RenderNgContentCmd.ngContentIndex',
|
'RenderNgContentCmd.ngContentIndex',
|
||||||
'RenderNgContentCmd.ngContentIndex=',
|
|
||||||
'RenderTemplateCmd:dart',
|
'RenderTemplateCmd:dart',
|
||||||
'RenderTextCmd:dart',
|
'RenderTextCmd:dart',
|
||||||
|
'RenderTextCmd.isBound',
|
||||||
|
'RenderTextCmd.ngContentIndex',
|
||||||
'RenderTextCmd.value',
|
'RenderTextCmd.value',
|
||||||
'RenderTextCmd.value=',
|
|
||||||
'RenderElementRef:dart',
|
'RenderElementRef:dart',
|
||||||
'RenderElementRef.boundElementIndex',
|
'RenderElementRef.boundElementIndex',
|
||||||
'RenderElementRef.boundElementIndex=',
|
'RenderElementRef.boundElementIndex=',
|
||||||
|
@ -1309,7 +1311,6 @@ var NG_ALL = [
|
||||||
'RenderElementRef.renderView=',
|
'RenderElementRef.renderView=',
|
||||||
'RenderEventDispatcher:dart',
|
'RenderEventDispatcher:dart',
|
||||||
'RenderNgContentCmd.index',
|
'RenderNgContentCmd.index',
|
||||||
'RenderNgContentCmd.index=',
|
|
||||||
'Stream:dart',
|
'Stream:dart',
|
||||||
'Stream.any():dart',
|
'Stream.any():dart',
|
||||||
'Stream.asBroadcastStream():dart',
|
'Stream.asBroadcastStream():dart',
|
||||||
|
|
|
@ -35,6 +35,5 @@ TemplateCompiler createTemplateCompiler(AssetReader reader,
|
||||||
templateParser,
|
templateParser,
|
||||||
new StyleCompiler(_xhr, _urlResolver),
|
new StyleCompiler(_xhr, _urlResolver),
|
||||||
new CommandCompiler(),
|
new CommandCompiler(),
|
||||||
cdCompiler,
|
cdCompiler);
|
||||||
null /* appId */);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,12 +176,9 @@ class _CodegenState {
|
||||||
|
|
||||||
${_genDirectiveIndices()};
|
${_genDirectiveIndices()};
|
||||||
|
|
||||||
static ${_genPrefix}ProtoChangeDetector
|
static ${_genPrefix}ChangeDetector
|
||||||
$PROTO_CHANGE_DETECTOR_FACTORY_METHOD(
|
$CHANGE_DETECTOR_FACTORY_METHOD(a) {
|
||||||
${_genPrefix}ChangeDetectorDefinition def) {
|
return new $_changeDetectorTypeName(a);
|
||||||
return new ${_genPrefix}PregenProtoChangeDetector(
|
|
||||||
(a) => new $_changeDetectorTypeName(a),
|
|
||||||
def);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
''');
|
''');
|
||||||
|
@ -575,7 +572,7 @@ class _CodegenState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PROTO_CHANGE_DETECTOR_FACTORY_METHOD = 'newProtoChangeDetector';
|
const CHANGE_DETECTOR_FACTORY_METHOD = 'newChangeDetector';
|
||||||
|
|
||||||
const _BASE_CLASS = 'AbstractChangeDetector';
|
const _BASE_CLASS = 'AbstractChangeDetector';
|
||||||
const _CHANGES_LOCAL = 'changes';
|
const _CHANGES_LOCAL = 'changes';
|
||||||
|
|
|
@ -4,7 +4,7 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
observe: '^0.13.1'
|
observe: '^0.13.1'
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
guinness: '^0.1.17'
|
guinness: '^0.1.18'
|
||||||
intl: '^0.12.4'
|
intl: '^0.12.4'
|
||||||
unittest: '^0.11.5+4'
|
unittest: '^0.11.5+4'
|
||||||
quiver: '^0.21.4'
|
quiver: '^0.21.4'
|
||||||
|
|
Loading…
Reference in New Issue