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