refactor(compiler): use the new compiler everywhere
Closes #3605 BREAKING CHANGE: - we don't mark an element as bound any more if it only contains text bindings E.g. <div>{{hello}}</div> This changes the indices when using `DebugElement.componentViewChildren` / `DebugElement.children`. - `@Directive.compileChildren` was removed, `ng-non-bindable` is now builtin and not a directive any more - angular no more adds the `ng-binding` class to elements with bindings - directives are now ordered as they are listed in the View.directives regarding change detection. Previously they had an undefined order. - the `Renderer` interface has new methods `createProtoView` and `registerComponentTemplate`. See `DomRenderer` for default implementations. - reprojection with `ng-content` is now all or nothing per `ng-content` element - angular2 transformer can't be used in tests that modify directive metadata. Use `angular2/src/transform/inliner_for_test` transformer instead.
This commit is contained in:
parent
30ca0434a2
commit
76247b7097
|
@ -189,8 +189,7 @@ function createChangeDefinitions(pvVisitors: ProtoViewVisitor[], componentType:
|
||||||
genConfig: ChangeDetectorGenConfig): ChangeDetectorDefinition[] {
|
genConfig: ChangeDetectorGenConfig): ChangeDetectorDefinition[] {
|
||||||
var pvVariableNames = _collectNestedProtoViewsVariableNames(pvVisitors);
|
var pvVariableNames = _collectNestedProtoViewsVariableNames(pvVisitors);
|
||||||
return pvVisitors.map(pvVisitor => {
|
return pvVisitors.map(pvVisitor => {
|
||||||
var viewType = pvVisitor.viewIndex === 0 ? 'component' : 'embedded';
|
var id = `${componentType.name}_${pvVisitor.viewIndex}`;
|
||||||
var id = _protoViewId(componentType, pvVisitor.viewIndex, viewType);
|
|
||||||
return new ChangeDetectorDefinition(
|
return new ChangeDetectorDefinition(
|
||||||
id, pvVisitor.strategy, pvVariableNames[pvVisitor.viewIndex], pvVisitor.bindingRecords,
|
id, pvVisitor.strategy, pvVariableNames[pvVisitor.viewIndex], pvVisitor.bindingRecords,
|
||||||
pvVisitor.eventRecords, pvVisitor.directiveRecords, genConfig);
|
pvVisitor.eventRecords, pvVisitor.directiveRecords, genConfig);
|
||||||
|
@ -207,9 +206,3 @@ function _collectNestedProtoViewsVariableNames(pvVisitors: ProtoViewVisitor[]):
|
||||||
});
|
});
|
||||||
return nestedPvVariableNames;
|
return nestedPvVariableNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function _protoViewId(hostComponentType: CompileTypeMetadata, pvIndex: number, viewType: string):
|
|
||||||
string {
|
|
||||||
return `${hostComponentType.name}_${viewType}_${pvIndex}`;
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,17 +16,18 @@ import {
|
||||||
|
|
||||||
import {TemplateAst} from './template_ast';
|
import {TemplateAst} from './template_ast';
|
||||||
import {Codegen} from 'angular2/src/transform/template_compiler/change_detector_codegen';
|
import {Codegen} from 'angular2/src/transform/template_compiler/change_detector_codegen';
|
||||||
import {IS_DART} from './util';
|
import {IS_DART, MODULE_SUFFIX} from './util';
|
||||||
import {Injectable} from 'angular2/src/core/di';
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
|
|
||||||
const ABSTRACT_CHANGE_DETECTOR = "AbstractChangeDetector";
|
const ABSTRACT_CHANGE_DETECTOR = "AbstractChangeDetector";
|
||||||
const UTIL = "ChangeDetectionUtil";
|
const UTIL = "ChangeDetectionUtil";
|
||||||
|
|
||||||
var ABSTRACT_CHANGE_DETECTOR_MODULE =
|
var ABSTRACT_CHANGE_DETECTOR_MODULE = moduleRef(
|
||||||
moduleRef('angular2/src/core/change_detection/abstract_change_detector');
|
`package:angular2/src/core/change_detection/abstract_change_detector${MODULE_SUFFIX}`);
|
||||||
var UTIL_MODULE = moduleRef('angular2/src/core/change_detection/change_detection_util');
|
var UTIL_MODULE =
|
||||||
var PREGEN_PROTO_CHANGE_DETECTOR_MODULE =
|
moduleRef(`package:angular2/src/core/change_detection/change_detection_util${MODULE_SUFFIX}`);
|
||||||
moduleRef('angular2/src/core/change_detection/pregen_proto_change_detector');
|
var PREGEN_PROTO_CHANGE_DETECTOR_MODULE = moduleRef(
|
||||||
|
`package:angular2/src/core/change_detection/pregen_proto_change_detector${MODULE_SUFFIX}`);
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ChangeDetectionCompiler {
|
export class ChangeDetectionCompiler {
|
||||||
|
@ -54,24 +55,31 @@ export class ChangeDetectionCompiler {
|
||||||
var changeDetectorDefinitions =
|
var changeDetectorDefinitions =
|
||||||
createChangeDetectorDefinitions(componentType, strategy, this._genConfig, parsedTemplate);
|
createChangeDetectorDefinitions(componentType, strategy, this._genConfig, parsedTemplate);
|
||||||
var factories = [];
|
var factories = [];
|
||||||
|
var index = 0;
|
||||||
var sourceParts = changeDetectorDefinitions.map(definition => {
|
var sourceParts = changeDetectorDefinitions.map(definition => {
|
||||||
var codegen: any;
|
var codegen: any;
|
||||||
|
var sourcePart;
|
||||||
// TODO(tbosch): move the 2 code generators to the same place, one with .dart and one with .ts
|
// TODO(tbosch): move the 2 code generators to the same place, one with .dart and one with .ts
|
||||||
// suffix
|
// suffix
|
||||||
// and have the same API for calling them!
|
// and have the same API for calling them!
|
||||||
if (IS_DART) {
|
if (IS_DART) {
|
||||||
codegen = new Codegen(PREGEN_PROTO_CHANGE_DETECTOR_MODULE);
|
codegen = new Codegen(PREGEN_PROTO_CHANGE_DETECTOR_MODULE);
|
||||||
var className = definition.id;
|
var className = definition.id;
|
||||||
codegen.generate(componentType.name, className, definition);
|
var typeRef = (index === 0 && componentType.isHost) ?
|
||||||
|
'dynamic' :
|
||||||
|
`${moduleRef(componentType.moduleUrl)}${componentType.name}`;
|
||||||
|
codegen.generate(typeRef, className, definition);
|
||||||
factories.push(`(dispatcher) => new ${className}(dispatcher)`);
|
factories.push(`(dispatcher) => new ${className}(dispatcher)`);
|
||||||
return codegen.toString();
|
sourcePart = codegen.toString();
|
||||||
} else {
|
} else {
|
||||||
codegen = new ChangeDetectorJITGenerator(
|
codegen = new ChangeDetectorJITGenerator(
|
||||||
definition, `${UTIL_MODULE}${UTIL}`,
|
definition, `${UTIL_MODULE}${UTIL}`,
|
||||||
`${ABSTRACT_CHANGE_DETECTOR_MODULE}${ABSTRACT_CHANGE_DETECTOR}`);
|
`${ABSTRACT_CHANGE_DETECTOR_MODULE}${ABSTRACT_CHANGE_DETECTOR}`);
|
||||||
factories.push(`function(dispatcher) { return new ${codegen.typeName}(dispatcher); }`);
|
factories.push(`function(dispatcher) { return new ${codegen.typeName}(dispatcher); }`);
|
||||||
return codegen.generateSource();
|
sourcePart = codegen.generateSource();
|
||||||
}
|
}
|
||||||
|
index++;
|
||||||
|
return sourcePart;
|
||||||
});
|
});
|
||||||
return new SourceExpressions(sourceParts, factories);
|
return new SourceExpressions(sourceParts, factories);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,11 @@ import {
|
||||||
shimContentAttributeExpr,
|
shimContentAttributeExpr,
|
||||||
shimHostAttributeExpr
|
shimHostAttributeExpr
|
||||||
} from './style_compiler';
|
} from './style_compiler';
|
||||||
import {escapeSingleQuoteString} from './util';
|
import {escapeSingleQuoteString, MODULE_SUFFIX} from './util';
|
||||||
import {Injectable} from 'angular2/src/core/di';
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
|
|
||||||
export var TEMPLATE_COMMANDS_MODULE_REF = moduleRef('angular2/src/core/compiler/template_commands');
|
export var TEMPLATE_COMMANDS_MODULE_REF =
|
||||||
|
moduleRef(`package:angular2/src/core/compiler/template_commands${MODULE_SUFFIX}`);
|
||||||
|
|
||||||
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
|
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
|
||||||
|
|
||||||
|
@ -353,6 +354,6 @@ function codeGenArray(data: any[]): string {
|
||||||
|
|
||||||
function codeGenDirectivesArray(directives: CompileDirectiveMetadata[]): string {
|
function codeGenDirectivesArray(directives: CompileDirectiveMetadata[]): string {
|
||||||
var expressions = directives.map(
|
var expressions = directives.map(
|
||||||
directiveType => `${moduleRef(directiveType.type.moduleId)}${directiveType.type.name}`);
|
directiveType => `${moduleRef(directiveType.type.moduleUrl)}${directiveType.type.name}`);
|
||||||
return `[${expressions.join(',')}]`;
|
return `[${expressions.join(',')}]`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,12 @@ import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
|
||||||
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
|
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
|
||||||
import {TemplateCompiler} from 'angular2/src/compiler/template_compiler';
|
import {TemplateCompiler} from 'angular2/src/compiler/template_compiler';
|
||||||
import {ChangeDetectorGenConfig} from 'angular2/src/core/change_detection/change_detection';
|
import {ChangeDetectorGenConfig} from 'angular2/src/core/change_detection/change_detection';
|
||||||
|
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
||||||
|
import {RuntimeCompiler} from 'angular2/src/compiler/runtime_compiler';
|
||||||
|
import {ElementSchemaRegistry} from 'angular2/src/core/render/dom/schema/element_schema_registry';
|
||||||
|
import {
|
||||||
|
DomElementSchemaRegistry
|
||||||
|
} from 'angular2/src/core/render/dom/schema/dom_element_schema_registry';
|
||||||
|
|
||||||
export function compilerBindings(): Array<Type | Binding | any[]> {
|
export function compilerBindings(): Array<Type | Binding | any[]> {
|
||||||
return [
|
return [
|
||||||
|
@ -31,5 +37,9 @@ export function compilerBindings(): Array<Type | Binding | any[]> {
|
||||||
.toValue(
|
.toValue(
|
||||||
new ChangeDetectorGenConfig(assertionsEnabled(), assertionsEnabled(), false, true)),
|
new ChangeDetectorGenConfig(assertionsEnabled(), assertionsEnabled(), false, true)),
|
||||||
TemplateCompiler,
|
TemplateCompiler,
|
||||||
|
RuntimeCompiler,
|
||||||
|
bind(Compiler).toAlias(RuntimeCompiler),
|
||||||
|
DomElementSchemaRegistry,
|
||||||
|
bind(ElementSchemaRegistry).toAlias(DomElementSchemaRegistry)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,22 +24,27 @@ var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
|
||||||
export class CompileTypeMetadata {
|
export class CompileTypeMetadata {
|
||||||
runtime: Type;
|
runtime: Type;
|
||||||
name: string;
|
name: string;
|
||||||
moduleId: string;
|
moduleUrl: string;
|
||||||
constructor({runtime, name, moduleId}: {runtime?: Type, name?: string, moduleId?: string} = {}) {
|
isHost: boolean;
|
||||||
|
constructor({runtime, name, moduleUrl, isHost}:
|
||||||
|
{runtime?: Type, name?: string, moduleUrl?: string, isHost?: boolean} = {}) {
|
||||||
this.runtime = runtime;
|
this.runtime = runtime;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.moduleId = moduleId;
|
this.moduleUrl = moduleUrl;
|
||||||
|
this.isHost = normalizeBool(isHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(data: StringMap<string, any>): CompileTypeMetadata {
|
static fromJson(data: StringMap<string, any>): CompileTypeMetadata {
|
||||||
return new CompileTypeMetadata({name: data['name'], moduleId: data['moduleId']});
|
return new CompileTypeMetadata(
|
||||||
|
{name: data['name'], moduleUrl: data['moduleUrl'], isHost: data['isHost']});
|
||||||
}
|
}
|
||||||
|
|
||||||
toJson(): StringMap<string, any> {
|
toJson(): StringMap<string, any> {
|
||||||
return {
|
return {
|
||||||
// Note: Runtime type can't be serialized...
|
// Note: Runtime type can't be serialized...
|
||||||
'name': this.name,
|
'name': this.name,
|
||||||
'moduleId': this.moduleId
|
'moduleUrl': this.moduleUrl,
|
||||||
|
'isHost': this.isHost
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,8 +253,12 @@ export function createHostComponentMeta(componentType: CompileTypeMetadata,
|
||||||
componentSelector: string): CompileDirectiveMetadata {
|
componentSelector: string): CompileDirectiveMetadata {
|
||||||
var template = CssSelector.parse(componentSelector)[0].getMatchingElementTemplate();
|
var template = CssSelector.parse(componentSelector)[0].getMatchingElementTemplate();
|
||||||
return CompileDirectiveMetadata.create({
|
return CompileDirectiveMetadata.create({
|
||||||
type: new CompileTypeMetadata(
|
type: new CompileTypeMetadata({
|
||||||
{runtime: Object, name: `Host${componentType.name}`, moduleId: componentType.moduleId}),
|
runtime: Object,
|
||||||
|
name: `Host${componentType.name}`,
|
||||||
|
moduleUrl: componentType.moduleUrl,
|
||||||
|
isHost: true
|
||||||
|
}),
|
||||||
template: new CompileTemplateMetadata(
|
template: new CompileTemplateMetadata(
|
||||||
{template: template, templateUrl: '', styles: [], styleUrls: [], ngContentSelectors: []}),
|
{template: template, templateUrl: '', styles: [], styleUrls: [], ngContentSelectors: []}),
|
||||||
changeDetection: ChangeDetectionStrategy.Default,
|
changeDetection: ChangeDetectionStrategy.Default,
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import {Compiler, internalCreateProtoView} from 'angular2/src/core/compiler/compiler';
|
||||||
|
import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
|
||||||
|
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||||
|
import {TemplateCompiler} from './template_compiler';
|
||||||
|
|
||||||
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
|
import {Type} from 'angular2/src/core/facade/lang';
|
||||||
|
import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RuntimeCompiler extends Compiler {
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
constructor(_protoViewFactory: ProtoViewFactory, private _templateCompiler: TemplateCompiler) {
|
||||||
|
super(_protoViewFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
compileInHost(componentType: Type): Promise<ProtoViewRef> {
|
||||||
|
return this._templateCompiler.compileHostComponentRuntime(componentType)
|
||||||
|
.then(compiledHostTemplate => internalCreateProtoView(this, compiledHostTemplate));
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCache() {
|
||||||
|
super.clearCache();
|
||||||
|
this._templateCompiler.clearCache();
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ import {hasLifecycleHook} from 'angular2/src/core/compiler/directive_lifecycle_r
|
||||||
import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/compiler/interfaces';
|
import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/compiler/interfaces';
|
||||||
import {reflector} from 'angular2/src/core/reflection/reflection';
|
import {reflector} from 'angular2/src/core/reflection/reflection';
|
||||||
import {Injectable} from 'angular2/src/core/di';
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
|
import {MODULE_SUFFIX} from './util';
|
||||||
|
|
||||||
// group 1: "property" from "[property]"
|
// group 1: "property" from "[property]"
|
||||||
// group 2: "event" from "(event)"
|
// group 2: "event" from "(event)"
|
||||||
|
@ -33,7 +34,7 @@ export class RuntimeMetadataResolver {
|
||||||
var meta = this._cache.get(directiveType);
|
var meta = this._cache.get(directiveType);
|
||||||
if (isBlank(meta)) {
|
if (isBlank(meta)) {
|
||||||
var directiveAnnotation = this._directiveResolver.resolve(directiveType);
|
var directiveAnnotation = this._directiveResolver.resolve(directiveType);
|
||||||
var moduleId = calcModuleId(directiveType, directiveAnnotation);
|
var moduleUrl = calcModuleUrl(directiveType, directiveAnnotation);
|
||||||
var templateMeta = null;
|
var templateMeta = null;
|
||||||
var changeDetectionStrategy = null;
|
var changeDetectionStrategy = null;
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ export class RuntimeMetadataResolver {
|
||||||
isComponent: isPresent(templateMeta),
|
isComponent: isPresent(templateMeta),
|
||||||
dynamicLoadable: true,
|
dynamicLoadable: true,
|
||||||
type: new cpl.CompileTypeMetadata(
|
type: new cpl.CompileTypeMetadata(
|
||||||
{name: stringify(directiveType), moduleId: moduleId, runtime: directiveType}),
|
{name: stringify(directiveType), moduleUrl: moduleUrl, runtime: directiveType}),
|
||||||
template: templateMeta,
|
template: templateMeta,
|
||||||
changeDetection: changeDetectionStrategy,
|
changeDetection: changeDetectionStrategy,
|
||||||
inputs: directiveAnnotation.inputs,
|
inputs: directiveAnnotation.inputs,
|
||||||
|
@ -111,10 +112,10 @@ function isValidDirective(value: Type): boolean {
|
||||||
return isPresent(value) && (value instanceof Type);
|
return isPresent(value) && (value instanceof Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
function calcModuleId(type: Type, directiveAnnotation: dirAnn.DirectiveMetadata): string {
|
function calcModuleUrl(type: Type, directiveAnnotation: dirAnn.DirectiveMetadata): string {
|
||||||
if (isPresent(directiveAnnotation.moduleId)) {
|
if (isPresent(directiveAnnotation.moduleId)) {
|
||||||
return directiveAnnotation.moduleId;
|
return `package:${directiveAnnotation.moduleId}${MODULE_SUFFIX}`;
|
||||||
} else {
|
} else {
|
||||||
return reflector.moduleId(type);
|
return reflector.importUri(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,28 +2,28 @@ import {StringWrapper, isBlank} from 'angular2/src/core/facade/lang';
|
||||||
|
|
||||||
var MODULE_REGEXP = /#MODULE\[([^\]]*)\]/g;
|
var MODULE_REGEXP = /#MODULE\[([^\]]*)\]/g;
|
||||||
|
|
||||||
export function moduleRef(moduleId): string {
|
export function moduleRef(moduleUrl): string {
|
||||||
return `#MODULE[${moduleId}]`;
|
return `#MODULE[${moduleUrl}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SourceModule {
|
export class SourceModule {
|
||||||
constructor(public moduleId: string, public sourceWithModuleRefs: string) {}
|
constructor(public moduleUrl: string, public sourceWithModuleRefs: string) {}
|
||||||
|
|
||||||
getSourceWithImports(): SourceWithImports {
|
getSourceWithImports(): SourceWithImports {
|
||||||
var moduleAliases = {};
|
var moduleAliases = {};
|
||||||
var imports: string[][] = [];
|
var imports: string[][] = [];
|
||||||
var newSource =
|
var newSource =
|
||||||
StringWrapper.replaceAllMapped(this.sourceWithModuleRefs, MODULE_REGEXP, (match) => {
|
StringWrapper.replaceAllMapped(this.sourceWithModuleRefs, MODULE_REGEXP, (match) => {
|
||||||
var moduleId = match[1];
|
var moduleUrl = match[1];
|
||||||
var alias = moduleAliases[moduleId];
|
var alias = moduleAliases[moduleUrl];
|
||||||
if (isBlank(alias)) {
|
if (isBlank(alias)) {
|
||||||
if (moduleId == this.moduleId) {
|
if (moduleUrl == this.moduleUrl) {
|
||||||
alias = '';
|
alias = '';
|
||||||
} else {
|
} else {
|
||||||
alias = `import${imports.length}`;
|
alias = `import${imports.length}`;
|
||||||
imports.push([moduleId, alias]);
|
imports.push([moduleUrl, alias]);
|
||||||
}
|
}
|
||||||
moduleAliases[moduleId] = alias;
|
moduleAliases[moduleUrl] = alias;
|
||||||
}
|
}
|
||||||
return alias.length > 0 ? `${alias}.` : '';
|
return alias.length > 0 ? `${alias}.` : '';
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,7 +14,8 @@ import {
|
||||||
codeGenMapArray,
|
codeGenMapArray,
|
||||||
codeGenReplaceAll,
|
codeGenReplaceAll,
|
||||||
codeGenExportVariable,
|
codeGenExportVariable,
|
||||||
codeGenToString
|
codeGenToString,
|
||||||
|
MODULE_SUFFIX
|
||||||
} from './util';
|
} from './util';
|
||||||
import {Injectable} from 'angular2/src/core/di';
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
|
|
||||||
|
@ -56,13 +57,15 @@ export class StyleCompiler {
|
||||||
return this._styleCodeGen(template.styles, template.styleUrls, shim, suffix);
|
return this._styleCodeGen(template.styles, template.styleUrls, shim, suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileStylesheetCodeGen(moduleId: string, cssText: string): SourceModule[] {
|
compileStylesheetCodeGen(stylesheetUrl: string, cssText: string): SourceModule[] {
|
||||||
var styleWithImports = resolveStyleUrls(this._urlResolver, moduleId, cssText);
|
var styleWithImports = resolveStyleUrls(this._urlResolver, stylesheetUrl, cssText);
|
||||||
return [
|
return [
|
||||||
this._styleModule(moduleId, false, this._styleCodeGen([styleWithImports.style],
|
this._styleModule(
|
||||||
styleWithImports.styleUrls, false, '')),
|
stylesheetUrl, false,
|
||||||
this._styleModule(moduleId, true, this._styleCodeGen([styleWithImports.style],
|
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, false, '')),
|
||||||
styleWithImports.styleUrls, true, ''))
|
this._styleModule(
|
||||||
|
stylesheetUrl, true,
|
||||||
|
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, true, ''))
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,28 +99,28 @@ export class StyleCompiler {
|
||||||
expressionSource +=
|
expressionSource +=
|
||||||
`[${plainStyles.map( plainStyle => escapeSingleQuoteString(this._shimIfNeeded(plainStyle, shim)) ).join(',')}]`;
|
`[${plainStyles.map( plainStyle => escapeSingleQuoteString(this._shimIfNeeded(plainStyle, shim)) ).join(',')}]`;
|
||||||
for (var i = 0; i < absUrls.length; i++) {
|
for (var i = 0; i < absUrls.length; i++) {
|
||||||
var moduleId = this._shimModuleIdIfNeeded(absUrls[i], shim);
|
var moduleUrl = this._createModuleUrl(absUrls[i], shim);
|
||||||
expressionSource += codeGenConcatArray(`${moduleRef(moduleId)}STYLES`);
|
expressionSource += codeGenConcatArray(`${moduleRef(moduleUrl)}STYLES`);
|
||||||
}
|
}
|
||||||
expressionSource += `)${suffix}`;
|
expressionSource += `)${suffix}`;
|
||||||
return new SourceExpression([], expressionSource);
|
return new SourceExpression([], expressionSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _styleModule(moduleId: string, shim: boolean,
|
private _styleModule(stylesheetUrl: string, shim: boolean,
|
||||||
expression: SourceExpression): SourceModule {
|
expression: SourceExpression): SourceModule {
|
||||||
var moduleSource = `
|
var moduleSource = `
|
||||||
${expression.declarations.join('\n')}
|
${expression.declarations.join('\n')}
|
||||||
${codeGenExportVariable('STYLES')}${expression.expression};
|
${codeGenExportVariable('STYLES')}${expression.expression};
|
||||||
`;
|
`;
|
||||||
return new SourceModule(this._shimModuleIdIfNeeded(moduleId, shim), moduleSource);
|
return new SourceModule(this._createModuleUrl(stylesheetUrl, shim), moduleSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _shimIfNeeded(style: string, shim: boolean): string {
|
private _shimIfNeeded(style: string, shim: boolean): string {
|
||||||
return shim ? this._shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR) : style;
|
return shim ? this._shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR) : style;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _shimModuleIdIfNeeded(moduleId: string, shim: boolean): string {
|
private _createModuleUrl(stylesheetUrl: string, shim: boolean): string {
|
||||||
return shim ? `${moduleId}.shim` : moduleId;
|
return shim ? `${stylesheetUrl}.shim${MODULE_SUFFIX}` : `${stylesheetUrl}${MODULE_SUFFIX}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,13 @@ import {RuntimeMetadataResolver} from './runtime_metadata';
|
||||||
import {APP_ID} from 'angular2/src/core/render/dom/dom_tokens';
|
import {APP_ID} from 'angular2/src/core/render/dom/dom_tokens';
|
||||||
|
|
||||||
import {TEMPLATE_COMMANDS_MODULE_REF} from './command_compiler';
|
import {TEMPLATE_COMMANDS_MODULE_REF} from './command_compiler';
|
||||||
import {IS_DART, codeGenExportVariable, escapeSingleQuoteString, codeGenValueFn} from './util';
|
import {
|
||||||
|
IS_DART,
|
||||||
|
codeGenExportVariable,
|
||||||
|
escapeSingleQuoteString,
|
||||||
|
codeGenValueFn,
|
||||||
|
MODULE_SUFFIX
|
||||||
|
} from './util';
|
||||||
import {Inject} from 'angular2/src/core/di';
|
import {Inject} from 'angular2/src/core/di';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -164,51 +170,54 @@ export class TemplateCompiler {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
compileTemplatesCodeGen(moduleId: string,
|
compileTemplatesCodeGen(components: NormalizedComponentWithViewDirectives[]): SourceModule {
|
||||||
components: NormalizedComponentWithViewDirectives[]): SourceModule {
|
if (components.length === 0) {
|
||||||
|
throw new BaseException('No components given');
|
||||||
|
}
|
||||||
var declarations = [];
|
var declarations = [];
|
||||||
var templateArguments = [];
|
var templateArguments = [];
|
||||||
var componentMetas: CompileDirectiveMetadata[] = [];
|
var componentMetas: CompileDirectiveMetadata[] = [];
|
||||||
var isHost: boolean[] = [];
|
|
||||||
var templateIdVariable = 'templateId';
|
var templateIdVariable = 'templateId';
|
||||||
var appIdVariable = 'appId';
|
var appIdVariable = 'appId';
|
||||||
components.forEach(componentWithDirs => {
|
components.forEach(componentWithDirs => {
|
||||||
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
|
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
|
||||||
assertComponent(compMeta);
|
assertComponent(compMeta);
|
||||||
componentMetas.push(compMeta);
|
componentMetas.push(compMeta);
|
||||||
isHost.push(false);
|
|
||||||
this._processTemplateCodeGen(compMeta, appIdVariable, templateIdVariable,
|
this._processTemplateCodeGen(compMeta, appIdVariable, templateIdVariable,
|
||||||
<CompileDirectiveMetadata[]>componentWithDirs.directives,
|
<CompileDirectiveMetadata[]>componentWithDirs.directives,
|
||||||
declarations, templateArguments);
|
declarations, templateArguments);
|
||||||
if (compMeta.dynamicLoadable) {
|
if (compMeta.dynamicLoadable) {
|
||||||
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
|
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
|
||||||
componentMetas.push(hostMeta);
|
componentMetas.push(hostMeta);
|
||||||
isHost.push(true);
|
|
||||||
this._processTemplateCodeGen(hostMeta, appIdVariable, templateIdVariable, [compMeta],
|
this._processTemplateCodeGen(hostMeta, appIdVariable, templateIdVariable, [compMeta],
|
||||||
declarations, templateArguments);
|
declarations, templateArguments);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ListWrapper.forEachWithIndex(componentMetas, (compMeta: CompileDirectiveMetadata,
|
ListWrapper.forEachWithIndex(componentMetas, (compMeta: CompileDirectiveMetadata,
|
||||||
index: number) => {
|
index: number) => {
|
||||||
var templateDataFn = codeGenValueFn([templateIdVariable, appIdVariable],
|
var templateDataFn = codeGenValueFn([appIdVariable, templateIdVariable],
|
||||||
`[${(<any[]>templateArguments[index]).join(',')}]`);
|
`[${(<any[]>templateArguments[index]).join(',')}]`);
|
||||||
var compiledTemplateExpr =
|
var compiledTemplateExpr =
|
||||||
`new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${TEMPLATE_COMMANDS_MODULE_REF}nextTemplateId(),${templateDataFn})`;
|
`new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${TEMPLATE_COMMANDS_MODULE_REF}nextTemplateId(),${templateDataFn})`;
|
||||||
var variableValueExpr;
|
var variableValueExpr;
|
||||||
if (isHost[index]) {
|
if (compMeta.type.isHost) {
|
||||||
|
var factoryName = `_hostTemplateFactory${index}`;
|
||||||
|
declarations.push(`${codeGenValueFn([], compiledTemplateExpr, factoryName)};`);
|
||||||
|
var constructionKeyword = IS_DART ? 'const' : 'new';
|
||||||
variableValueExpr =
|
variableValueExpr =
|
||||||
`new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${codeGenValueFn([], compiledTemplateExpr)})`;
|
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${factoryName})`;
|
||||||
} else {
|
} else {
|
||||||
variableValueExpr = compiledTemplateExpr;
|
variableValueExpr = compiledTemplateExpr;
|
||||||
}
|
}
|
||||||
declarations.push(
|
declarations.push(
|
||||||
`${codeGenExportVariable(templateVariableName(compMeta.type))}${variableValueExpr};`);
|
`${codeGenExportVariable(templateVariableName(compMeta.type), compMeta.type.isHost)}${variableValueExpr};`);
|
||||||
});
|
});
|
||||||
return new SourceModule(`${templateModuleName(moduleId)}`, declarations.join('\n'));
|
var moduleUrl = components[0].component.type.moduleUrl;
|
||||||
|
return new SourceModule(`${templateModuleUrl(moduleUrl)}`, declarations.join('\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
compileStylesheetCodeGen(moduleId: string, cssText: string): SourceModule[] {
|
compileStylesheetCodeGen(stylesheetUrl: string, cssText: string): SourceModule[] {
|
||||||
return this._styleCompiler.compileStylesheetCodeGen(moduleId, cssText);
|
return this._styleCompiler.compileStylesheetCodeGen(stylesheetUrl, cssText);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata, appIdExpr: string,
|
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata, appIdExpr: string,
|
||||||
|
@ -248,8 +257,9 @@ function templateVariableName(type: CompileTypeMetadata): string {
|
||||||
return `${type.name}Template`;
|
return `${type.name}Template`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function templateModuleName(moduleId: string): string {
|
function templateModuleUrl(moduleUrl: string): string {
|
||||||
return `${moduleId}.template`;
|
var urlWithoutSuffix = moduleUrl.substring(0, moduleUrl.length - MODULE_SUFFIX.length);
|
||||||
|
return `${urlWithoutSuffix}.template${MODULE_SUFFIX}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAll(source: any[], target: any[]) {
|
function addAll(source: any[], target: any[]) {
|
||||||
|
@ -259,5 +269,5 @@ function addAll(source: any[], target: any[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string {
|
function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string {
|
||||||
return `${moduleRef(templateModuleName(nestedCompType.type.moduleId))}${templateVariableName(nestedCompType.type)}`;
|
return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateVariableName(nestedCompType.type)}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,9 @@ export class TemplateNormalizer {
|
||||||
template: CompileTemplateMetadata): Promise<CompileTemplateMetadata> {
|
template: CompileTemplateMetadata): Promise<CompileTemplateMetadata> {
|
||||||
if (isPresent(template.template)) {
|
if (isPresent(template.template)) {
|
||||||
return PromiseWrapper.resolve(this.normalizeLoadedTemplate(
|
return PromiseWrapper.resolve(this.normalizeLoadedTemplate(
|
||||||
directiveType, template, template.template, directiveType.moduleId));
|
directiveType, template, template.template, directiveType.moduleUrl));
|
||||||
} else if (isPresent(template.templateUrl)) {
|
} else if (isPresent(template.templateUrl)) {
|
||||||
var sourceAbsUrl = this._urlResolver.resolve(directiveType.moduleId, template.templateUrl);
|
var sourceAbsUrl = this._urlResolver.resolve(directiveType.moduleUrl, template.templateUrl);
|
||||||
return this._xhr.get(sourceAbsUrl)
|
return this._xhr.get(sourceAbsUrl)
|
||||||
.then(templateContent => this.normalizeLoadedTemplate(directiveType, template,
|
.then(templateContent => this.normalizeLoadedTemplate(directiveType, template,
|
||||||
templateContent, sourceAbsUrl));
|
templateContent, sourceAbsUrl));
|
||||||
|
@ -55,7 +55,7 @@ export class TemplateNormalizer {
|
||||||
var allStyleAbsUrls =
|
var allStyleAbsUrls =
|
||||||
visitor.styleUrls.map(url => this._urlResolver.resolve(templateAbsUrl, url))
|
visitor.styleUrls.map(url => this._urlResolver.resolve(templateAbsUrl, url))
|
||||||
.concat(templateMeta.styleUrls.map(
|
.concat(templateMeta.styleUrls.map(
|
||||||
url => this._urlResolver.resolve(directiveType.moduleId, url)));
|
url => this._urlResolver.resolve(directiveType.moduleUrl, url)));
|
||||||
|
|
||||||
var allResolvedStyles = allStyles.map(style => {
|
var allResolvedStyles = allStyles.map(style => {
|
||||||
var styleWithImports = resolveStyleUrls(this._urlResolver, templateAbsUrl, style);
|
var styleWithImports = resolveStyleUrls(this._urlResolver, templateAbsUrl, style);
|
||||||
|
|
|
@ -7,6 +7,8 @@ var DOUBLE_QUOTE_ESCAPE_STRING_RE = /"|\\|\n|\$/g;
|
||||||
|
|
||||||
export var IS_DART = !isJsObject({});
|
export var IS_DART = !isJsObject({});
|
||||||
|
|
||||||
|
export var MODULE_SUFFIX = IS_DART ? '.dart' : '.js';
|
||||||
|
|
||||||
export function camelCaseToDashCase(input: string): string {
|
export function camelCaseToDashCase(input: string): string {
|
||||||
return StringWrapper.replaceAllMapped(input, CAMEL_CASE_REGEXP,
|
return StringWrapper.replaceAllMapped(input, CAMEL_CASE_REGEXP,
|
||||||
(m) => { return '-' + m[1].toLowerCase(); });
|
(m) => { return '-' + m[1].toLowerCase(); });
|
||||||
|
@ -43,8 +45,9 @@ function escapeString(input: string, re: RegExp): string {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function codeGenExportVariable(name: string): string {
|
export function codeGenExportVariable(name: string, isConst: boolean = false): string {
|
||||||
return IS_DART ? `var ${name} = ` : `var ${name} = exports['${name}'] = `;
|
var declaration = isConst ? `const ${name}` : `var ${name}`;
|
||||||
|
return IS_DART ? `${declaration} = ` : `${declaration} = exports['${name}'] = `;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function codeGenConcatArray(expression: string): string {
|
export function codeGenConcatArray(expression: string): string {
|
||||||
|
@ -67,11 +70,11 @@ export function codeGenReplaceAll(pattern: string, expression: string): string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function codeGenValueFn(params: string[], value: string): string {
|
export function codeGenValueFn(params: string[], value: string, fnName: string = ''): string {
|
||||||
if (IS_DART) {
|
if (IS_DART) {
|
||||||
return `(${params.join(',')}) => ${value}`;
|
return `${fnName}(${params.join(',')}) => ${value}`;
|
||||||
} else {
|
} else {
|
||||||
return `function(${params.join(',')}) { return ${value}; }`;
|
return `function ${fnName}(${params.join(',')}) { return ${value}; }`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:angular2/src/core/reflection/reflection_capabilities.dart'
|
||||||
show ReflectionCapabilities;
|
show ReflectionCapabilities;
|
||||||
import 'application_common.dart';
|
import 'application_common.dart';
|
||||||
|
|
||||||
|
import 'package:angular2/src/compiler/compiler.dart';
|
||||||
import 'package:angular2/src/core/compiler/dynamic_component_loader.dart';
|
import 'package:angular2/src/core/compiler/dynamic_component_loader.dart';
|
||||||
export 'package:angular2/src/core/compiler/dynamic_component_loader.dart' show ComponentRef;
|
export 'package:angular2/src/core/compiler/dynamic_component_loader.dart' show ComponentRef;
|
||||||
|
|
||||||
|
@ -19,5 +20,9 @@ export 'package:angular2/src/core/compiler/dynamic_component_loader.dart' show C
|
||||||
Future<ComponentRef> bootstrap(Type appComponentType,
|
Future<ComponentRef> bootstrap(Type appComponentType,
|
||||||
[List componentInjectableBindings]) {
|
[List componentInjectableBindings]) {
|
||||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||||
return commonBootstrap(appComponentType, componentInjectableBindings);
|
var bindings = [compilerBindings()];
|
||||||
|
if (componentInjectableBindings != null) {
|
||||||
|
bindings.add(componentInjectableBindings);
|
||||||
|
}
|
||||||
|
return commonBootstrap(appComponentType, bindings);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
// Public API for Application
|
// Public API for Application
|
||||||
|
import {Binding} from './di';
|
||||||
|
import {Type, isPresent} from 'angular2/src/core/facade/lang';
|
||||||
|
import {Promise} from 'angular2/src/core/facade/async';
|
||||||
|
import {compilerBindings} from 'angular2/src/compiler/compiler';
|
||||||
|
import {commonBootstrap} from './application_common';
|
||||||
|
import {ComponentRef} from './compiler/dynamic_component_loader';
|
||||||
|
|
||||||
export {APP_COMPONENT} from './application_tokens';
|
export {APP_COMPONENT} from './application_tokens';
|
||||||
export {platform, commonBootstrap as bootstrap} from './application_common';
|
export {platform} from './application_common';
|
||||||
export {
|
export {
|
||||||
PlatformRef,
|
PlatformRef,
|
||||||
ApplicationRef,
|
ApplicationRef,
|
||||||
|
@ -9,3 +16,14 @@ export {
|
||||||
platformCommon,
|
platformCommon,
|
||||||
platformBindings
|
platformBindings
|
||||||
} from './application_ref';
|
} from './application_ref';
|
||||||
|
|
||||||
|
/// See [commonBootstrap] for detailed documentation.
|
||||||
|
export function bootstrap(appComponentType: /*Type*/ any,
|
||||||
|
appBindings: Array<Type | Binding | any[]> = null):
|
||||||
|
Promise<ComponentRef> {
|
||||||
|
var bindings = [compilerBindings()];
|
||||||
|
if (isPresent(appBindings)) {
|
||||||
|
bindings.push(appBindings);
|
||||||
|
}
|
||||||
|
return commonBootstrap(appComponentType, bindings);
|
||||||
|
}
|
|
@ -18,7 +18,6 @@ import {
|
||||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
import {internalView} from 'angular2/src/core/compiler/view_ref';
|
import {internalView} from 'angular2/src/core/compiler/view_ref';
|
||||||
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
|
||||||
import {
|
import {
|
||||||
Parser,
|
Parser,
|
||||||
Lexer,
|
Lexer,
|
||||||
|
@ -35,7 +34,7 @@ import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/vi
|
||||||
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||||
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
||||||
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
|
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
|
||||||
import {Compiler, CompilerCache} from './compiler/compiler';
|
import {ProtoViewFactory} from './compiler/proto_view_factory';
|
||||||
import {DEFAULT_PIPES} from 'angular2/src/core/pipes';
|
import {DEFAULT_PIPES} from 'angular2/src/core/pipes';
|
||||||
import {ViewResolver} from './compiler/view_resolver';
|
import {ViewResolver} from './compiler/view_resolver';
|
||||||
import {DirectiveResolver} from './compiler/directive_resolver';
|
import {DirectiveResolver} from './compiler/directive_resolver';
|
||||||
|
@ -43,7 +42,10 @@ import {PipeResolver} from './compiler/pipe_resolver';
|
||||||
import {StyleUrlResolver} from 'angular2/src/core/render/dom/compiler/style_url_resolver';
|
import {StyleUrlResolver} from 'angular2/src/core/render/dom/compiler/style_url_resolver';
|
||||||
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
|
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
|
||||||
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
|
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
|
||||||
import {compilerBindings} from 'angular2/src/compiler/compiler';
|
import {
|
||||||
|
APP_ID_RANDOM_BINDING,
|
||||||
|
} from 'angular2/src/core/render/render';
|
||||||
|
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the set of bindings meant for use at the platform level.
|
* Constructs the set of bindings meant for use at the platform level.
|
||||||
|
@ -95,15 +97,14 @@ export function applicationCommonBindings(): Array<Type | Binding | any[]> {
|
||||||
bestChangeDetection = new JitChangeDetection();
|
bestChangeDetection = new JitChangeDetection();
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
compilerBindings(),
|
Compiler,
|
||||||
ProtoViewFactory,
|
APP_ID_RANDOM_BINDING,
|
||||||
AppViewPool,
|
AppViewPool,
|
||||||
bind(APP_VIEW_POOL_CAPACITY).toValue(10000),
|
bind(APP_VIEW_POOL_CAPACITY).toValue(10000),
|
||||||
AppViewManager,
|
AppViewManager,
|
||||||
AppViewManagerUtils,
|
AppViewManagerUtils,
|
||||||
AppViewListener,
|
AppViewListener,
|
||||||
Compiler,
|
ProtoViewFactory,
|
||||||
CompilerCache,
|
|
||||||
ViewResolver,
|
ViewResolver,
|
||||||
DEFAULT_PIPES,
|
DEFAULT_PIPES,
|
||||||
bind(IterableDiffers).toValue(defaultIterableDiffers),
|
bind(IterableDiffers).toValue(defaultIterableDiffers),
|
||||||
|
|
|
@ -1,21 +1,3 @@
|
||||||
library angular2.src.core.bootstrap;
|
library angular2.src.core.bootstrap;
|
||||||
|
|
||||||
import 'dart:async';
|
export './application.dart' show bootstrap;
|
||||||
|
|
||||||
import 'package:angular2/src/core/compiler/dynamic_component_loader.dart' show ComponentRef;
|
|
||||||
import 'package:angular2/src/core/reflection/reflection.dart' show reflector;
|
|
||||||
import 'package:angular2/src/core/reflection/reflection_capabilities.dart'
|
|
||||||
show ReflectionCapabilities;
|
|
||||||
import 'application_common.dart';
|
|
||||||
|
|
||||||
/// Starts an application from a root component. This implementation uses
|
|
||||||
/// mirrors. Angular 2 transformer automatically replaces this method with a
|
|
||||||
/// static implementation (see `application_static.dart`) that does not use
|
|
||||||
/// mirrors and produces a faster and more compact JS code.
|
|
||||||
///
|
|
||||||
/// See [commonBootstrap] for detailed documentation.
|
|
||||||
Future<ComponentRef> bootstrap(Type appComponentType,
|
|
||||||
[List componentInjectableBindings]) {
|
|
||||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
|
||||||
return commonBootstrap(appComponentType, componentInjectableBindings);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Note: This file only exists so that Dart users can import
|
// Note: This file only exists so that Dart users can import
|
||||||
// bootstrap from angular2/bootstrap. JS users should import
|
// bootstrap from angular2/bootstrap. JS users should import
|
||||||
// from angular2/core.
|
// from angular2/core.
|
||||||
export {commonBootstrap as bootstrap} from './application_common';
|
export {bootstrap} from './application';
|
||||||
|
|
|
@ -1,95 +1,13 @@
|
||||||
import {Binding, resolveForwardRef, Injectable, Inject} from 'angular2/src/core/di';
|
import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
|
||||||
import {DEFAULT_PIPES_TOKEN} from 'angular2/src/core/pipes';
|
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||||
import {
|
|
||||||
Type,
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
isBlank,
|
import {Type, isBlank, stringify} from 'angular2/src/core/facade/lang';
|
||||||
isType,
|
|
||||||
isPresent,
|
|
||||||
normalizeBlank,
|
|
||||||
stringify,
|
|
||||||
isArray,
|
|
||||||
isPromise
|
|
||||||
} from 'angular2/src/core/facade/lang';
|
|
||||||
import {BaseException} from 'angular2/src/core/facade/exceptions';
|
import {BaseException} from 'angular2/src/core/facade/exceptions';
|
||||||
import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';
|
import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';
|
||||||
import {ListWrapper, Map, MapWrapper} from 'angular2/src/core/facade/collection';
|
import {reflector} from 'angular2/src/core/reflection/reflection';
|
||||||
|
import {CompiledHostTemplate} from 'angular2/src/core/compiler/template_commands';
|
||||||
|
|
||||||
import {DirectiveResolver} from './directive_resolver';
|
|
||||||
|
|
||||||
import {AppProtoView, AppProtoViewMergeMapping} from './view';
|
|
||||||
import {ProtoViewRef} from './view_ref';
|
|
||||||
import {DirectiveBinding} from './element_injector';
|
|
||||||
import {ViewResolver} from './view_resolver';
|
|
||||||
import {PipeResolver} from './pipe_resolver';
|
|
||||||
import {ViewMetadata} from 'angular2/src/core/metadata';
|
|
||||||
import {ComponentUrlMapper} from './component_url_mapper';
|
|
||||||
import {ProtoViewFactory} from './proto_view_factory';
|
|
||||||
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
|
|
||||||
import {AppRootUrl} from 'angular2/src/core/services/app_root_url';
|
|
||||||
import {ElementBinder} from './element_binder';
|
|
||||||
import {wtfStartTimeRange, wtfEndTimeRange} from '../profile/profile';
|
|
||||||
import {PipeBinding} from '../pipes/pipe_binding';
|
|
||||||
|
|
||||||
import {
|
|
||||||
RenderDirectiveMetadata,
|
|
||||||
ViewDefinition,
|
|
||||||
RenderCompiler,
|
|
||||||
ViewType,
|
|
||||||
RenderProtoViewMergeMapping,
|
|
||||||
RenderProtoViewRef
|
|
||||||
} from 'angular2/src/core/render/api';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache that stores the AppProtoView of the template of a component.
|
|
||||||
* Used to prevent duplicate work and resolve cyclic dependencies.
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class CompilerCache {
|
|
||||||
_cache = new Map<Type, AppProtoView>();
|
|
||||||
_hostCache = new Map<Type, AppProtoView>();
|
|
||||||
|
|
||||||
set(component: Type, protoView: AppProtoView): void { this._cache.set(component, protoView); }
|
|
||||||
|
|
||||||
get(component: Type): AppProtoView {
|
|
||||||
var result = this._cache.get(component);
|
|
||||||
return normalizeBlank(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
setHost(component: Type, protoView: AppProtoView): void {
|
|
||||||
this._hostCache.set(component, protoView);
|
|
||||||
}
|
|
||||||
|
|
||||||
getHost(component: Type): AppProtoView {
|
|
||||||
var result = this._hostCache.get(component);
|
|
||||||
return normalizeBlank(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
clear(): void {
|
|
||||||
this._cache.clear();
|
|
||||||
this._hostCache.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ## URL Resolution
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* var appRootUrl: AppRootUrl = ...;
|
|
||||||
* var componentUrlMapper: ComponentUrlMapper = ...;
|
|
||||||
* var urlResolver: UrlResolver = ...;
|
|
||||||
*
|
|
||||||
* var componentType: Type = ...;
|
|
||||||
* var componentAnnotation: ComponentAnnotation = ...;
|
|
||||||
* var viewAnnotation: ViewAnnotation = ...;
|
|
||||||
*
|
|
||||||
* // Resolving a URL
|
|
||||||
*
|
|
||||||
* var url = viewAnnotation.templateUrl;
|
|
||||||
* var componentUrl = componentUrlMapper.getUrl(componentType);
|
|
||||||
* var componentResolvedUrl = urlResolver.resolve(appRootUrl.value, componentUrl);
|
|
||||||
* var templateResolvedUrl = urlResolver.resolve(componentResolvedUrl, url);
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Low-level service for compiling {@link Component}s into {@link ProtoViewRef ProtoViews}s, which
|
* Low-level service for compiling {@link Component}s into {@link ProtoViewRef ProtoViews}s, which
|
||||||
* can later be used to create and render a Component instance.
|
* can later be used to create and render a Component instance.
|
||||||
|
@ -99,271 +17,36 @@ export class CompilerCache {
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class Compiler {
|
export class Compiler {
|
||||||
private _compiling = new Map<Type, Promise<AppProtoView>>();
|
|
||||||
private _appUrl: string;
|
|
||||||
private _defaultPipes: Type[];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
constructor(private _directiveResolver: DirectiveResolver, private _pipeResolver: PipeResolver,
|
constructor(private _protoViewFactory: ProtoViewFactory) {}
|
||||||
@Inject(DEFAULT_PIPES_TOKEN) _defaultPipes: Type[],
|
|
||||||
private _compilerCache: CompilerCache, private _viewResolver: ViewResolver,
|
|
||||||
private _componentUrlMapper: ComponentUrlMapper, private _urlResolver: UrlResolver,
|
|
||||||
private _render: RenderCompiler, private _protoViewFactory: ProtoViewFactory,
|
|
||||||
appUrl: AppRootUrl) {
|
|
||||||
this._defaultPipes = _defaultPipes;
|
|
||||||
this._appUrl = appUrl.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _bindDirective(directiveTypeOrBinding): DirectiveBinding {
|
|
||||||
if (directiveTypeOrBinding instanceof DirectiveBinding) {
|
|
||||||
return directiveTypeOrBinding;
|
|
||||||
} else if (directiveTypeOrBinding instanceof Binding) {
|
|
||||||
let annotation = this._directiveResolver.resolve(directiveTypeOrBinding.token);
|
|
||||||
return DirectiveBinding.createFromBinding(directiveTypeOrBinding, annotation);
|
|
||||||
} else {
|
|
||||||
let annotation = this._directiveResolver.resolve(directiveTypeOrBinding);
|
|
||||||
return DirectiveBinding.createFromType(directiveTypeOrBinding, annotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _bindPipe(typeOrBinding): PipeBinding {
|
|
||||||
let meta = this._pipeResolver.resolve(typeOrBinding);
|
|
||||||
return PipeBinding.createFromType(typeOrBinding, meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compiles a {@link Component} and returns a promise for this component's {@link ProtoViewRef}.
|
|
||||||
*
|
|
||||||
* Returns `ProtoViewRef` that can be later used to instantiate a component via
|
|
||||||
* {@link ViewContainerRef#createHostView} or {@link AppViewManager#createHostViewInContainer}.
|
|
||||||
*/
|
|
||||||
compileInHost(componentType: Type): Promise<ProtoViewRef> {
|
compileInHost(componentType: Type): Promise<ProtoViewRef> {
|
||||||
var r = wtfStartTimeRange('Compiler#compile()', stringify(componentType));
|
var metadatas = reflector.annotations(componentType);
|
||||||
|
var compiledHostTemplate = null;
|
||||||
var hostAppProtoView = this._compilerCache.getHost(componentType);
|
for (var i = 0; i < metadatas.length; i++) {
|
||||||
var hostPvPromise;
|
var metadata = metadatas[i];
|
||||||
if (isPresent(hostAppProtoView)) {
|
if (metadata instanceof CompiledHostTemplate) {
|
||||||
hostPvPromise = PromiseWrapper.resolve(hostAppProtoView);
|
compiledHostTemplate = metadata;
|
||||||
} else {
|
break;
|
||||||
var componentBinding: DirectiveBinding = this._bindDirective(componentType);
|
|
||||||
Compiler._assertTypeIsComponent(componentBinding);
|
|
||||||
|
|
||||||
var directiveMetadata = componentBinding.metadata;
|
|
||||||
hostPvPromise = this._render.compileHost(directiveMetadata)
|
|
||||||
.then((hostRenderPv) => {
|
|
||||||
var protoViews = this._protoViewFactory.createAppProtoViews(
|
|
||||||
componentBinding, hostRenderPv, [componentBinding], []);
|
|
||||||
return this._compileNestedProtoViews(protoViews, componentType,
|
|
||||||
new Map<Type, AppProtoView>());
|
|
||||||
})
|
|
||||||
.then((appProtoView) => {
|
|
||||||
this._compilerCache.setHost(componentType, appProtoView);
|
|
||||||
return appProtoView;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return hostPvPromise.then((hostAppProtoView) => {
|
|
||||||
wtfEndTimeRange(r);
|
|
||||||
return hostAppProtoView.ref;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (isBlank(compiledHostTemplate)) {
|
||||||
private _compile(componentBinding: DirectiveBinding,
|
|
||||||
componentPath: Map<Type, AppProtoView>): Promise<AppProtoView>|
|
|
||||||
AppProtoView {
|
|
||||||
var component = <Type>componentBinding.key.token;
|
|
||||||
var protoView = this._compilerCache.get(component);
|
|
||||||
if (isPresent(protoView)) {
|
|
||||||
// The component has already been compiled into an AppProtoView,
|
|
||||||
// returns a plain AppProtoView, not wrapped inside of a Promise, for performance reasons.
|
|
||||||
return protoView;
|
|
||||||
}
|
|
||||||
var resultPromise = this._compiling.get(component);
|
|
||||||
if (isPresent(resultPromise)) {
|
|
||||||
// The component is already being compiled, attach to the existing Promise
|
|
||||||
// instead of re-compiling the component.
|
|
||||||
// It happens when a template references a component multiple times.
|
|
||||||
return resultPromise;
|
|
||||||
}
|
|
||||||
var view = this._viewResolver.resolve(component);
|
|
||||||
|
|
||||||
var directives = this._flattenDirectives(view);
|
|
||||||
|
|
||||||
for (var i = 0; i < directives.length; i++) {
|
|
||||||
if (!Compiler._isValidDirective(directives[i])) {
|
|
||||||
throw new BaseException(
|
throw new BaseException(
|
||||||
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
|
`No precompiled template for component ${stringify(componentType)} found`);
|
||||||
}
|
}
|
||||||
|
return PromiseWrapper.resolve(this._createProtoView(compiledHostTemplate));
|
||||||
}
|
}
|
||||||
|
|
||||||
var boundDirectives = this._removeDuplicatedDirectives(
|
private _createProtoView(compiledHostTemplate: CompiledHostTemplate): ProtoViewRef {
|
||||||
directives.map(directive => this._bindDirective(directive)));
|
return this._protoViewFactory.createHost(compiledHostTemplate).ref;
|
||||||
|
|
||||||
var pipes = this._flattenPipes(view);
|
|
||||||
var boundPipes = pipes.map(pipe => this._bindPipe(pipe));
|
|
||||||
|
|
||||||
var renderTemplate = this._buildRenderTemplate(component, view, boundDirectives);
|
|
||||||
resultPromise =
|
|
||||||
this._render.compile(renderTemplate)
|
|
||||||
.then((renderPv) => {
|
|
||||||
var protoViews = this._protoViewFactory.createAppProtoViews(
|
|
||||||
componentBinding, renderPv, boundDirectives, boundPipes);
|
|
||||||
return this._compileNestedProtoViews(protoViews, component, componentPath);
|
|
||||||
})
|
|
||||||
.then((appProtoView) => {
|
|
||||||
this._compilerCache.set(component, appProtoView);
|
|
||||||
MapWrapper.delete(this._compiling, component);
|
|
||||||
return appProtoView;
|
|
||||||
});
|
|
||||||
this._compiling.set(component, resultPromise);
|
|
||||||
return resultPromise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _removeDuplicatedDirectives(directives: DirectiveBinding[]): DirectiveBinding[] {
|
clearCache() { this._protoViewFactory.clearCache(); }
|
||||||
var directivesMap = new Map<number, DirectiveBinding>();
|
|
||||||
directives.forEach((dirBinding) => { directivesMap.set(dirBinding.key.id, dirBinding); });
|
|
||||||
return MapWrapper.values(directivesMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _compileNestedProtoViews(appProtoViews: AppProtoView[], componentType: Type,
|
export function internalCreateProtoView(compiler: Compiler,
|
||||||
componentPath: Map<Type, AppProtoView>): Promise<AppProtoView> {
|
compiledHostTemplate: CompiledHostTemplate): ProtoViewRef {
|
||||||
var nestedPVPromises = [];
|
return (<any>compiler)._createProtoView(compiledHostTemplate);
|
||||||
componentPath = MapWrapper.clone(componentPath);
|
|
||||||
if (appProtoViews[0].type === ViewType.COMPONENT) {
|
|
||||||
componentPath.set(componentType, appProtoViews[0]);
|
|
||||||
}
|
|
||||||
appProtoViews.forEach(appProtoView => {
|
|
||||||
this._collectComponentElementBinders(appProtoView)
|
|
||||||
.forEach((elementBinder: ElementBinder) => {
|
|
||||||
var nestedComponent = elementBinder.componentDirective;
|
|
||||||
var nestedComponentType = <Type>nestedComponent.key.token;
|
|
||||||
var elementBinderDone =
|
|
||||||
(nestedPv: AppProtoView) => { elementBinder.nestedProtoView = nestedPv; };
|
|
||||||
if (componentPath.has(nestedComponentType)) {
|
|
||||||
// cycle...
|
|
||||||
if (appProtoView.isEmbeddedFragment) {
|
|
||||||
throw new BaseException(
|
|
||||||
`<ng-content> is used within the recursive path of ${stringify(nestedComponentType)}`);
|
|
||||||
} else if (appProtoView.type === ViewType.COMPONENT) {
|
|
||||||
throw new BaseException(
|
|
||||||
`Unconditional component cycle in ${stringify(nestedComponentType)}`);
|
|
||||||
} else {
|
|
||||||
elementBinderDone(componentPath.get(nestedComponentType));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var nestedCall = this._compile(nestedComponent, componentPath);
|
|
||||||
if (isPromise(nestedCall)) {
|
|
||||||
nestedPVPromises.push((<Promise<AppProtoView>>nestedCall).then(elementBinderDone));
|
|
||||||
} else {
|
|
||||||
elementBinderDone(<AppProtoView>nestedCall);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return PromiseWrapper.all(nestedPVPromises)
|
|
||||||
.then(_ => PromiseWrapper.all(
|
|
||||||
appProtoViews.map(appProtoView => this._mergeProtoView(appProtoView))))
|
|
||||||
.then(_ => appProtoViews[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _mergeProtoView(appProtoView: AppProtoView): Promise<any> {
|
|
||||||
if (appProtoView.type !== ViewType.HOST && appProtoView.type !== ViewType.EMBEDDED) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this._render.mergeProtoViewsRecursively(this._collectMergeRenderProtoViews(appProtoView))
|
|
||||||
.then((mergeResult: RenderProtoViewMergeMapping) => {
|
|
||||||
appProtoView.mergeMapping = new AppProtoViewMergeMapping(mergeResult);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _collectMergeRenderProtoViews(appProtoView:
|
|
||||||
AppProtoView): Array<RenderProtoViewRef | any[]> {
|
|
||||||
var result = [appProtoView.render];
|
|
||||||
for (var i = 0; i < appProtoView.elementBinders.length; i++) {
|
|
||||||
var binder = appProtoView.elementBinders[i];
|
|
||||||
if (isPresent(binder.nestedProtoView)) {
|
|
||||||
if (binder.hasStaticComponent() ||
|
|
||||||
(binder.hasEmbeddedProtoView() && binder.nestedProtoView.isEmbeddedFragment)) {
|
|
||||||
result.push(this._collectMergeRenderProtoViews(binder.nestedProtoView));
|
|
||||||
} else {
|
|
||||||
result.push(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _collectComponentElementBinders(appProtoView: AppProtoView): ElementBinder[] {
|
|
||||||
var componentElementBinders = [];
|
|
||||||
appProtoView.elementBinders.forEach((elementBinder) => {
|
|
||||||
if (isPresent(elementBinder.componentDirective)) {
|
|
||||||
componentElementBinders.push(elementBinder);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return componentElementBinders;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _buildRenderTemplate(component, view, directives): ViewDefinition {
|
|
||||||
var componentUrl =
|
|
||||||
this._urlResolver.resolve(this._appUrl, this._componentUrlMapper.getUrl(component));
|
|
||||||
var templateAbsUrl = null;
|
|
||||||
var styleAbsUrls = null;
|
|
||||||
if (isPresent(view.templateUrl) && view.templateUrl.trim().length > 0) {
|
|
||||||
templateAbsUrl = this._urlResolver.resolve(componentUrl, view.templateUrl);
|
|
||||||
} else if (isPresent(view.template)) {
|
|
||||||
// Note: If we have an inline template, we also need to send
|
|
||||||
// the url for the component to the render so that it
|
|
||||||
// is able to resolve urls in stylesheets.
|
|
||||||
templateAbsUrl = componentUrl;
|
|
||||||
}
|
|
||||||
if (isPresent(view.styleUrls)) {
|
|
||||||
styleAbsUrls =
|
|
||||||
ListWrapper.map(view.styleUrls, url => this._urlResolver.resolve(componentUrl, url));
|
|
||||||
}
|
|
||||||
return new ViewDefinition({
|
|
||||||
componentId: stringify(component),
|
|
||||||
templateAbsUrl: templateAbsUrl, template: view.template,
|
|
||||||
styleAbsUrls: styleAbsUrls,
|
|
||||||
styles: view.styles,
|
|
||||||
directives: ListWrapper.map(directives, directiveBinding => directiveBinding.metadata),
|
|
||||||
encapsulation: view.encapsulation
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _flattenPipes(view: ViewMetadata): any[] {
|
|
||||||
if (isBlank(view.pipes)) return this._defaultPipes;
|
|
||||||
var pipes = ListWrapper.clone(this._defaultPipes);
|
|
||||||
this._flattenList(view.pipes, pipes);
|
|
||||||
return pipes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _flattenDirectives(view: ViewMetadata): Type[] {
|
|
||||||
if (isBlank(view.directives)) return [];
|
|
||||||
var directives = [];
|
|
||||||
this._flattenList(view.directives, directives);
|
|
||||||
return directives;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _flattenList(tree: any[], out: Array<Type | Binding | any[]>): void {
|
|
||||||
for (var i = 0; i < tree.length; i++) {
|
|
||||||
var item = resolveForwardRef(tree[i]);
|
|
||||||
if (isArray(item)) {
|
|
||||||
this._flattenList(item, out);
|
|
||||||
} else {
|
|
||||||
out.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static _isValidDirective(value: Type | Binding): boolean {
|
|
||||||
return isPresent(value) && (value instanceof Type || value instanceof Binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static _assertTypeIsComponent(directiveBinding: DirectiveBinding): void {
|
|
||||||
if (directiveBinding.metadata.type !== RenderDirectiveMetadata.COMPONENT_TYPE) {
|
|
||||||
throw new BaseException(
|
|
||||||
`Could not load '${stringify(directiveBinding.key.token)}' because it is not a component.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -119,7 +119,6 @@ export class DirectiveResolver {
|
||||||
bindings: dm.bindings,
|
bindings: dm.bindings,
|
||||||
exportAs: dm.exportAs,
|
exportAs: dm.exportAs,
|
||||||
moduleId: dm.moduleId,
|
moduleId: dm.moduleId,
|
||||||
compileChildren: dm.compileChildren,
|
|
||||||
queries: mergedQueries,
|
queries: mergedQueries,
|
||||||
changeDetection: dm.changeDetection,
|
changeDetection: dm.changeDetection,
|
||||||
viewBindings: dm.viewBindings
|
viewBindings: dm.viewBindings
|
||||||
|
@ -134,7 +133,6 @@ export class DirectiveResolver {
|
||||||
bindings: dm.bindings,
|
bindings: dm.bindings,
|
||||||
exportAs: dm.exportAs,
|
exportAs: dm.exportAs,
|
||||||
moduleId: dm.moduleId,
|
moduleId: dm.moduleId,
|
||||||
compileChildren: dm.compileChildren,
|
|
||||||
queries: mergedQueries
|
queries: mergedQueries
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,16 @@
|
||||||
import {isBlank, isPresent} from 'angular2/src/core/facade/lang';
|
import {isBlank} from 'angular2/src/core/facade/lang';
|
||||||
import {BaseException} from 'angular2/src/core/facade/exceptions';
|
import {BaseException} from 'angular2/src/core/facade/exceptions';
|
||||||
import * as eiModule from './element_injector';
|
import * as eiModule from './element_injector';
|
||||||
import {DirectiveBinding} from './element_injector';
|
import {DirectiveBinding} from './element_injector';
|
||||||
import * as viewModule from './view';
|
import * as viewModule from './view';
|
||||||
|
|
||||||
export class ElementBinder {
|
export class ElementBinder {
|
||||||
// updated later, so we are able to resolve cycles
|
|
||||||
nestedProtoView: viewModule.AppProtoView = null;
|
|
||||||
|
|
||||||
constructor(public index: number, public parent: ElementBinder, public distanceToParent: number,
|
constructor(public index: number, public parent: ElementBinder, public distanceToParent: number,
|
||||||
public protoElementInjector: eiModule.ProtoElementInjector,
|
public protoElementInjector: eiModule.ProtoElementInjector,
|
||||||
public componentDirective: DirectiveBinding) {
|
public componentDirective: DirectiveBinding,
|
||||||
|
public nestedProtoView: viewModule.AppProtoView) {
|
||||||
if (isBlank(index)) {
|
if (isBlank(index)) {
|
||||||
throw new BaseException('null index not allowed.');
|
throw new BaseException('null index not allowed.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasStaticComponent(): boolean {
|
|
||||||
return isPresent(this.componentDirective) && isPresent(this.nestedProtoView);
|
|
||||||
}
|
|
||||||
|
|
||||||
hasEmbeddedProtoView(): boolean {
|
|
||||||
return !isPresent(this.componentDirective) && isPresent(this.nestedProtoView);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ export class DirectiveBinding extends ResolvedBinding {
|
||||||
type: meta instanceof ComponentMetadata ? RenderDirectiveMetadata.COMPONENT_TYPE :
|
type: meta instanceof ComponentMetadata ? RenderDirectiveMetadata.COMPONENT_TYPE :
|
||||||
RenderDirectiveMetadata.DIRECTIVE_TYPE,
|
RenderDirectiveMetadata.DIRECTIVE_TYPE,
|
||||||
selector: meta.selector,
|
selector: meta.selector,
|
||||||
compileChildren: meta.compileChildren,
|
compileChildren: true,
|
||||||
outputs: meta.outputs,
|
outputs: meta.outputs,
|
||||||
host: isPresent(meta.host) ? MapWrapper.createFromStringMap(meta.host) : null,
|
host: isPresent(meta.host) ? MapWrapper.createFromStringMap(meta.host) : null,
|
||||||
inputs: meta.inputs,
|
inputs: meta.inputs,
|
||||||
|
@ -214,6 +214,7 @@ export class DirectiveBinding extends ResolvedBinding {
|
||||||
|
|
||||||
// TODO(rado): benchmark and consider rolling in as ElementInjector fields.
|
// TODO(rado): benchmark and consider rolling in as ElementInjector fields.
|
||||||
export class PreBuiltObjects {
|
export class PreBuiltObjects {
|
||||||
|
nestedView: viewModule.AppView = null;
|
||||||
constructor(public viewManager: avmModule.AppViewManager, public view: viewModule.AppView,
|
constructor(public viewManager: avmModule.AppViewManager, public view: viewModule.AppView,
|
||||||
public elementRef: ElementRef, public templateRef: TemplateRef) {}
|
public elementRef: ElementRef, public templateRef: TemplateRef) {}
|
||||||
}
|
}
|
||||||
|
@ -474,6 +475,8 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
|
||||||
return new ViewContainerRef(this._preBuiltObjects.viewManager, this.getElementRef());
|
return new ViewContainerRef(this._preBuiltObjects.viewManager, this.getElementRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNestedView(): viewModule.AppView { return this._preBuiltObjects.nestedView; }
|
||||||
|
|
||||||
getView(): viewModule.AppView { return this._preBuiltObjects.view; }
|
getView(): viewModule.AppView { return this._preBuiltObjects.view; }
|
||||||
|
|
||||||
directParent(): ElementInjector { return this._proto.distanceToParent < 2 ? this.parent : null; }
|
directParent(): ElementInjector { return this._proto.distanceToParent < 2 ? this.parent : null; }
|
||||||
|
|
|
@ -33,6 +33,7 @@ export class ElementRef implements RenderElementRef {
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*
|
*
|
||||||
|
* TODO(tbosch): remove this when the new compiler lands
|
||||||
* Index of the element inside the `RenderViewRef`.
|
* Index of the element inside the `RenderViewRef`.
|
||||||
*
|
*
|
||||||
* This is used internally by the Angular framework to locate elements.
|
* This is used internally by the Angular framework to locate elements.
|
||||||
|
@ -42,11 +43,10 @@ export class ElementRef implements RenderElementRef {
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
constructor(parentView: ViewRef, boundElementIndex: number, renderBoundElementIndex: number,
|
constructor(parentView: ViewRef, boundElementIndex: number, private _renderer: Renderer) {
|
||||||
private _renderer: Renderer) {
|
|
||||||
this.parentView = parentView;
|
this.parentView = parentView;
|
||||||
this.boundElementIndex = boundElementIndex;
|
this.boundElementIndex = boundElementIndex;
|
||||||
this.renderBoundElementIndex = renderBoundElementIndex;
|
this.renderBoundElementIndex = boundElementIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
import {Injectable} from 'angular2/src/core/di';
|
|
||||||
|
|
||||||
import {ListWrapper, MapWrapper} from 'angular2/src/core/facade/collection';
|
import {ListWrapper, MapWrapper} from 'angular2/src/core/facade/collection';
|
||||||
import {StringWrapper, isPresent, isBlank, assertionsEnabled} from 'angular2/src/core/facade/lang';
|
import {isPresent, isBlank, Type, isArray, isNumber} from 'angular2/src/core/facade/lang';
|
||||||
import {BaseException} from 'angular2/src/core/facade/exceptions';
|
|
||||||
import {reflector} from 'angular2/src/core/reflection/reflection';
|
import {reflector} from 'angular2/src/core/reflection/reflection';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -17,23 +14,340 @@ import {
|
||||||
ASTWithSource
|
ASTWithSource
|
||||||
} from 'angular2/src/core/change_detection/change_detection';
|
} from 'angular2/src/core/change_detection/change_detection';
|
||||||
|
|
||||||
import {PipeBinding} from 'angular2/src/core/pipes/pipe_binding';
|
|
||||||
import {ProtoPipes} from 'angular2/src/core/pipes/pipes';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
RenderDirectiveMetadata,
|
RenderDirectiveMetadata,
|
||||||
RenderElementBinder,
|
RenderElementBinder,
|
||||||
PropertyBindingType,
|
PropertyBindingType,
|
||||||
DirectiveBinder,
|
DirectiveBinder,
|
||||||
ProtoViewDto,
|
ProtoViewDto,
|
||||||
ViewType
|
ViewType,
|
||||||
|
RenderProtoViewRef
|
||||||
} from 'angular2/src/core/render/api';
|
} from 'angular2/src/core/render/api';
|
||||||
import {AppProtoView} from './view';
|
|
||||||
|
import {Injectable, Binding, resolveForwardRef, Inject} from 'angular2/src/core/di';
|
||||||
|
|
||||||
|
import {PipeBinding} from '../pipes/pipe_binding';
|
||||||
|
import {ProtoPipes} from '../pipes/pipes';
|
||||||
|
|
||||||
|
import {AppProtoView, AppProtoViewMergeInfo} from './view';
|
||||||
import {ElementBinder} from './element_binder';
|
import {ElementBinder} from './element_binder';
|
||||||
import {ProtoElementInjector, DirectiveBinding} from './element_injector';
|
import {ProtoElementInjector, DirectiveBinding} from './element_injector';
|
||||||
|
import {DirectiveResolver} from './directive_resolver';
|
||||||
|
import {ViewResolver} from './view_resolver';
|
||||||
|
import {PipeResolver} from './pipe_resolver';
|
||||||
|
import {ViewMetadata} from '../metadata/view';
|
||||||
|
import {DEFAULT_PIPES_TOKEN} from 'angular2/src/core/pipes';
|
||||||
|
|
||||||
|
import {
|
||||||
|
visitAllCommands,
|
||||||
|
CompiledTemplate,
|
||||||
|
CompiledHostTemplate,
|
||||||
|
TemplateCmd,
|
||||||
|
CommandVisitor,
|
||||||
|
EmbeddedTemplateCmd,
|
||||||
|
BeginComponentCmd,
|
||||||
|
BeginElementCmd,
|
||||||
|
IBeginElementCmd,
|
||||||
|
TextCmd,
|
||||||
|
NgContentCmd
|
||||||
|
} from './template_commands';
|
||||||
|
|
||||||
|
import {Renderer} from 'angular2/render';
|
||||||
|
import {APP_ID} from 'angular2/src/core/render/dom/dom_tokens';
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ProtoViewFactory {
|
||||||
|
private _cache: Map<number, AppProtoView> = new Map<number, AppProtoView>();
|
||||||
|
private _defaultPipes: Type[];
|
||||||
|
private _appId: string;
|
||||||
|
|
||||||
|
constructor(private _renderer: Renderer, @Inject(DEFAULT_PIPES_TOKEN) defaultPipes: Type[],
|
||||||
|
private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver,
|
||||||
|
private _pipeResolver: PipeResolver, @Inject(APP_ID) appId: string) {
|
||||||
|
this._defaultPipes = defaultPipes;
|
||||||
|
this._appId = appId;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCache() { this._cache.clear(); }
|
||||||
|
|
||||||
|
createHost(compiledHostTemplate: CompiledHostTemplate): AppProtoView {
|
||||||
|
var compiledTemplate = compiledHostTemplate.getTemplate();
|
||||||
|
var result = this._cache.get(compiledTemplate.id);
|
||||||
|
if (isBlank(result)) {
|
||||||
|
var templateData = compiledTemplate.getData(this._appId);
|
||||||
|
result =
|
||||||
|
new AppProtoView(templateData.commands, ViewType.HOST, true,
|
||||||
|
templateData.changeDetectorFactory, null, new ProtoPipes(new Map()));
|
||||||
|
this._cache.set(compiledTemplate.id, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createComponent(cmd: BeginComponentCmd): AppProtoView {
|
||||||
|
var nestedProtoView = this._cache.get(cmd.templateId);
|
||||||
|
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);
|
||||||
|
var boundPipes = this._flattenPipes(view).map(pipe => this._bindPipe(pipe));
|
||||||
|
|
||||||
|
nestedProtoView = new AppProtoView(compiledTemplateData.commands, ViewType.COMPONENT, true,
|
||||||
|
compiledTemplateData.changeDetectorFactory, null,
|
||||||
|
ProtoPipes.fromBindings(boundPipes));
|
||||||
|
// Note: The cache is updated before recursing
|
||||||
|
// to be able to resolve cycles
|
||||||
|
this._cache.set(cmd.template.id, nestedProtoView);
|
||||||
|
this._initializeProtoView(nestedProtoView, null);
|
||||||
|
}
|
||||||
|
return nestedProtoView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createEmbeddedTemplate(cmd: EmbeddedTemplateCmd, parent: AppProtoView): AppProtoView {
|
||||||
|
var nestedProtoView = new AppProtoView(
|
||||||
|
cmd.children, ViewType.EMBEDDED, cmd.isMerged, cmd.changeDetectorFactory,
|
||||||
|
arrayToMap(cmd.variableNameAndValues, true), new ProtoPipes(parent.pipes.config));
|
||||||
|
if (cmd.isMerged) {
|
||||||
|
this.initializeProtoViewIfNeeded(nestedProtoView);
|
||||||
|
}
|
||||||
|
return nestedProtoView;
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeProtoViewIfNeeded(protoView: AppProtoView) {
|
||||||
|
if (!protoView.isInitialized()) {
|
||||||
|
var render = this._renderer.createProtoView(protoView.templateCmds);
|
||||||
|
this._initializeProtoView(protoView, render);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _initializeProtoView(protoView: AppProtoView, render: RenderProtoViewRef) {
|
||||||
|
var initializer = new _ProtoViewInitializer(protoView, this._directiveResolver, this);
|
||||||
|
visitAllCommands(initializer, protoView.templateCmds);
|
||||||
|
var mergeInfo =
|
||||||
|
new AppProtoViewMergeInfo(initializer.mergeEmbeddedViewCount, initializer.mergeElementCount,
|
||||||
|
initializer.mergeViewCount);
|
||||||
|
protoView.init(render, initializer.elementBinders, initializer.boundTextCount, mergeInfo,
|
||||||
|
initializer.variableLocations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _bindPipe(typeOrBinding): PipeBinding {
|
||||||
|
let meta = this._pipeResolver.resolve(typeOrBinding);
|
||||||
|
return PipeBinding.createFromType(typeOrBinding, meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _flattenPipes(view: ViewMetadata): any[] {
|
||||||
|
if (isBlank(view.pipes)) return this._defaultPipes;
|
||||||
|
var pipes = ListWrapper.clone(this._defaultPipes);
|
||||||
|
_flattenList(view.pipes, pipes);
|
||||||
|
return pipes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createComponent(protoViewFactory: ProtoViewFactory, cmd: BeginComponentCmd): AppProtoView {
|
||||||
|
return (<any>protoViewFactory)._createComponent(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEmbeddedTemplate(protoViewFactory: ProtoViewFactory, cmd: EmbeddedTemplateCmd,
|
||||||
|
parent: AppProtoView): AppProtoView {
|
||||||
|
return (<any>protoViewFactory)._createEmbeddedTemplate(cmd, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ProtoViewInitializer implements CommandVisitor {
|
||||||
|
variableLocations: Map<string, number> = new Map<string, number>();
|
||||||
|
boundTextCount: number = 0;
|
||||||
|
boundElementIndex: number = 0;
|
||||||
|
elementBinderStack: ElementBinder[] = [];
|
||||||
|
distanceToParentElementBinder: number = 0;
|
||||||
|
distanceToParentProtoElementInjector: number = 0;
|
||||||
|
elementBinders: ElementBinder[] = [];
|
||||||
|
mergeEmbeddedViewCount: number = 0;
|
||||||
|
mergeElementCount: number = 0;
|
||||||
|
mergeViewCount: number = 1;
|
||||||
|
|
||||||
|
constructor(private _protoView: AppProtoView, private _directiveResolver: DirectiveResolver,
|
||||||
|
private _protoViewFactory: ProtoViewFactory) {}
|
||||||
|
|
||||||
|
visitText(cmd: TextCmd, context: any): any {
|
||||||
|
if (cmd.isBound) {
|
||||||
|
this.boundTextCount++;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
visitNgContent(cmd: NgContentCmd, context: any): any { return null; }
|
||||||
|
visitBeginElement(cmd: BeginElementCmd, context: any): any {
|
||||||
|
if (cmd.isBound) {
|
||||||
|
this._visitBeginBoundElement(cmd, null);
|
||||||
|
} else {
|
||||||
|
this._visitBeginElement(cmd, null, null);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
visitEndElement(context: any): any { return this._visitEndElement(); }
|
||||||
|
visitBeginComponent(cmd: BeginComponentCmd, context: any): any {
|
||||||
|
var nestedProtoView = createComponent(this._protoViewFactory, cmd);
|
||||||
|
return this._visitBeginBoundElement(cmd, nestedProtoView);
|
||||||
|
}
|
||||||
|
visitEndComponent(context: any): any { return this._visitEndElement(); }
|
||||||
|
visitEmbeddedTemplate(cmd: EmbeddedTemplateCmd, context: any): any {
|
||||||
|
var nestedProtoView = createEmbeddedTemplate(this._protoViewFactory, cmd, this._protoView);
|
||||||
|
if (cmd.isMerged) {
|
||||||
|
this.mergeEmbeddedViewCount++;
|
||||||
|
}
|
||||||
|
this._visitBeginBoundElement(cmd, nestedProtoView);
|
||||||
|
return this._visitEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _visitBeginBoundElement(cmd: IBeginElementCmd, nestedProtoView: AppProtoView): any {
|
||||||
|
if (isPresent(nestedProtoView) && nestedProtoView.isMergable) {
|
||||||
|
this.mergeElementCount += nestedProtoView.mergeInfo.elementCount;
|
||||||
|
this.mergeViewCount += nestedProtoView.mergeInfo.viewCount;
|
||||||
|
this.mergeEmbeddedViewCount += nestedProtoView.mergeInfo.embeddedViewCount;
|
||||||
|
}
|
||||||
|
var elementBinder = _createElementBinder(
|
||||||
|
this._directiveResolver, nestedProtoView, this.elementBinderStack, this.boundElementIndex,
|
||||||
|
this.distanceToParentElementBinder, this.distanceToParentProtoElementInjector, cmd);
|
||||||
|
this.elementBinders.push(elementBinder);
|
||||||
|
var protoElementInjector = elementBinder.protoElementInjector;
|
||||||
|
for (var i = 0; i < cmd.variableNameAndValues.length; i += 2) {
|
||||||
|
this.variableLocations.set(<string>cmd.variableNameAndValues[i], this.boundElementIndex);
|
||||||
|
}
|
||||||
|
this.boundElementIndex++;
|
||||||
|
this.mergeElementCount++;
|
||||||
|
return this._visitBeginElement(cmd, elementBinder, protoElementInjector);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _visitBeginElement(cmd: IBeginElementCmd, elementBinder: ElementBinder,
|
||||||
|
protoElementInjector: ProtoElementInjector): any {
|
||||||
|
this.distanceToParentElementBinder =
|
||||||
|
isPresent(elementBinder) ? 1 : this.distanceToParentElementBinder + 1;
|
||||||
|
this.distanceToParentProtoElementInjector =
|
||||||
|
isPresent(protoElementInjector) ? 1 : this.distanceToParentProtoElementInjector + 1;
|
||||||
|
this.elementBinderStack.push(elementBinder);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _visitEndElement(): any {
|
||||||
|
var parentElementBinder = this.elementBinderStack.pop();
|
||||||
|
var parentProtoElementInjector =
|
||||||
|
isPresent(parentElementBinder) ? parentElementBinder.protoElementInjector : null;
|
||||||
|
this.distanceToParentElementBinder = isPresent(parentElementBinder) ?
|
||||||
|
parentElementBinder.distanceToParent :
|
||||||
|
this.distanceToParentElementBinder - 1;
|
||||||
|
this.distanceToParentProtoElementInjector = isPresent(parentProtoElementInjector) ?
|
||||||
|
parentProtoElementInjector.distanceToParent :
|
||||||
|
this.distanceToParentProtoElementInjector - 1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _createElementBinder(directiveResolver: DirectiveResolver, nestedProtoView: AppProtoView,
|
||||||
|
elementBinderStack: ElementBinder[], boundElementIndex: number,
|
||||||
|
distanceToParentBinder: number, distanceToParentPei: number,
|
||||||
|
beginElementCmd: IBeginElementCmd): ElementBinder {
|
||||||
|
var parentElementBinder: ElementBinder = null;
|
||||||
|
var parentProtoElementInjector: ProtoElementInjector = null;
|
||||||
|
if (distanceToParentBinder > 0) {
|
||||||
|
parentElementBinder = elementBinderStack[elementBinderStack.length - distanceToParentBinder];
|
||||||
|
}
|
||||||
|
if (isBlank(parentElementBinder)) {
|
||||||
|
distanceToParentBinder = -1;
|
||||||
|
}
|
||||||
|
if (distanceToParentPei > 0) {
|
||||||
|
var peiBinder = elementBinderStack[elementBinderStack.length - distanceToParentPei];
|
||||||
|
if (isPresent(peiBinder)) {
|
||||||
|
parentProtoElementInjector = peiBinder.protoElementInjector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isBlank(parentProtoElementInjector)) {
|
||||||
|
distanceToParentPei = -1;
|
||||||
|
}
|
||||||
|
var componentDirectiveBinding: DirectiveBinding = null;
|
||||||
|
var isEmbeddedTemplate = false;
|
||||||
|
var directiveBindings: DirectiveBinding[] =
|
||||||
|
beginElementCmd.directives.map(type => bindDirective(directiveResolver, type));
|
||||||
|
if (beginElementCmd instanceof BeginComponentCmd) {
|
||||||
|
componentDirectiveBinding = directiveBindings[0];
|
||||||
|
} else if (beginElementCmd instanceof EmbeddedTemplateCmd) {
|
||||||
|
isEmbeddedTemplate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var protoElementInjector = null;
|
||||||
|
// Create a protoElementInjector for any element that either has bindings *or* has one
|
||||||
|
// or more var- defined *or* for <template> elements:
|
||||||
|
// - Elements with a var- defined need a their own element injector
|
||||||
|
// so that, when hydrating, $implicit can be set to the element.
|
||||||
|
// - <template> elements need their own ElementInjector so that we can query their TemplateRef
|
||||||
|
var hasVariables = beginElementCmd.variableNameAndValues.length > 0;
|
||||||
|
if (directiveBindings.length > 0 || hasVariables || isEmbeddedTemplate) {
|
||||||
|
var directiveVariableBindings = new Map<string, number>();
|
||||||
|
if (!isEmbeddedTemplate) {
|
||||||
|
directiveVariableBindings =
|
||||||
|
createDirectiveVariableBindings(beginElementCmd.variableNameAndValues, directiveBindings);
|
||||||
|
}
|
||||||
|
protoElementInjector = ProtoElementInjector.create(
|
||||||
|
parentProtoElementInjector, boundElementIndex, directiveBindings,
|
||||||
|
isPresent(componentDirectiveBinding), distanceToParentPei, directiveVariableBindings);
|
||||||
|
protoElementInjector.attributes = arrayToMap(beginElementCmd.attrNameAndValues, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ElementBinder(boundElementIndex, parentElementBinder, distanceToParentBinder,
|
||||||
|
protoElementInjector, componentDirectiveBinding, nestedProtoView);
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindDirective(directiveResolver: DirectiveResolver, type: Type): DirectiveBinding {
|
||||||
|
let annotation = directiveResolver.resolve(type);
|
||||||
|
return DirectiveBinding.createFromType(type, annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createDirectiveVariableBindings(variableNameAndValues: Array<string | number>,
|
||||||
|
directiveBindings: DirectiveBinding[]):
|
||||||
|
Map<string, number> {
|
||||||
|
var directiveVariableBindings = new Map<string, number>();
|
||||||
|
for (var i = 0; i < variableNameAndValues.length; i += 2) {
|
||||||
|
var templateName = <string>variableNameAndValues[i];
|
||||||
|
var dirIndex = <number>variableNameAndValues[i + 1];
|
||||||
|
if (isNumber(dirIndex)) {
|
||||||
|
directiveVariableBindings.set(templateName, dirIndex);
|
||||||
|
} else {
|
||||||
|
// a variable without a directive index -> reference the element
|
||||||
|
directiveVariableBindings.set(templateName, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return directiveVariableBindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function arrayToMap(arr: string[], inverse: boolean): Map<string, string> {
|
||||||
|
var result = new Map<string, string>();
|
||||||
|
for (var i = 0; i < arr.length; i += 2) {
|
||||||
|
if (inverse) {
|
||||||
|
result.set(arr[i + 1], arr[i]);
|
||||||
|
} else {
|
||||||
|
result.set(arr[i], arr[i + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _flattenList(tree: any[], out: Array<Type | Binding | any[]>): void {
|
||||||
|
for (var i = 0; i < tree.length; i++) {
|
||||||
|
var item = resolveForwardRef(tree[i]);
|
||||||
|
if (isArray(item)) {
|
||||||
|
_flattenList(item, out);
|
||||||
|
} else {
|
||||||
|
out.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class BindingRecordsCreator {
|
export class BindingRecordsCreator {
|
||||||
_directiveRecordsMap = new Map<number, DirectiveRecord>();
|
_directiveRecordsMap: Map<number, DirectiveRecord> = new Map<number, DirectiveRecord>();
|
||||||
|
|
||||||
getEventBindingRecords(elementBinders: RenderElementBinder[],
|
getEventBindingRecords(elementBinders: RenderElementBinder[],
|
||||||
allDirectiveMetadatas: RenderDirectiveMetadata[]): BindingRecord[] {
|
allDirectiveMetadatas: RenderDirectiveMetadata[]): BindingRecord[] {
|
||||||
|
@ -199,58 +513,6 @@ export class BindingRecordsCreator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class ProtoViewFactory {
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
constructor(public _changeDetection: ChangeDetection) {}
|
|
||||||
|
|
||||||
createAppProtoViews(hostComponentBinding: DirectiveBinding, rootRenderProtoView: ProtoViewDto,
|
|
||||||
allDirectives: DirectiveBinding[], pipes: PipeBinding[]): AppProtoView[] {
|
|
||||||
var allRenderDirectiveMetadata =
|
|
||||||
ListWrapper.map(allDirectives, directiveBinding => directiveBinding.metadata);
|
|
||||||
var nestedPvsWithIndex = _collectNestedProtoViews(rootRenderProtoView);
|
|
||||||
var nestedPvVariableBindings = _collectNestedProtoViewsVariableBindings(nestedPvsWithIndex);
|
|
||||||
var nestedPvVariableNames = _collectNestedProtoViewsVariableNames(nestedPvsWithIndex);
|
|
||||||
|
|
||||||
var protoChangeDetectors =
|
|
||||||
this._getProtoChangeDetectors(hostComponentBinding, nestedPvsWithIndex,
|
|
||||||
nestedPvVariableNames, allRenderDirectiveMetadata);
|
|
||||||
|
|
||||||
var appProtoViews = ListWrapper.createFixedSize(nestedPvsWithIndex.length);
|
|
||||||
ListWrapper.forEach(nestedPvsWithIndex, (pvWithIndex: RenderProtoViewWithIndex) => {
|
|
||||||
var appProtoView =
|
|
||||||
_createAppProtoView(pvWithIndex.renderProtoView, protoChangeDetectors[pvWithIndex.index],
|
|
||||||
nestedPvVariableBindings[pvWithIndex.index], allDirectives, pipes);
|
|
||||||
if (isPresent(pvWithIndex.parentIndex)) {
|
|
||||||
var parentView = appProtoViews[pvWithIndex.parentIndex];
|
|
||||||
parentView.elementBinders[pvWithIndex.boundElementIndex].nestedProtoView = appProtoView;
|
|
||||||
}
|
|
||||||
appProtoViews[pvWithIndex.index] = appProtoView;
|
|
||||||
});
|
|
||||||
return appProtoViews;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _getProtoChangeDetectors(hostComponentBinding: DirectiveBinding,
|
|
||||||
nestedPvsWithIndex: RenderProtoViewWithIndex[],
|
|
||||||
nestedPvVariableNames: string[][],
|
|
||||||
allRenderDirectiveMetadata: any[]): ProtoChangeDetector[] {
|
|
||||||
if (this._changeDetection.generateDetectors) {
|
|
||||||
var changeDetectorDefs = _getChangeDetectorDefinitions(
|
|
||||||
hostComponentBinding.metadata, nestedPvsWithIndex, nestedPvVariableNames,
|
|
||||||
allRenderDirectiveMetadata, this._changeDetection.genConfig);
|
|
||||||
return changeDetectorDefs.map(changeDetectorDef =>
|
|
||||||
this._changeDetection.getProtoChangeDetector(
|
|
||||||
changeDetectorDef.id, changeDetectorDef));
|
|
||||||
} else {
|
|
||||||
var changeDetectorIds =
|
|
||||||
_getChangeDetectorDefinitionIds(hostComponentBinding.metadata, nestedPvsWithIndex);
|
|
||||||
return changeDetectorIds.map(id => this._changeDetection.getProtoChangeDetector(id, null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the data needed to create ChangeDetectors
|
* Returns the data needed to create ChangeDetectors
|
||||||
* for the given ProtoView and all nested ProtoViews.
|
* for the given ProtoView and all nested ProtoViews.
|
||||||
|
@ -311,11 +573,6 @@ function _getChangeDetectorDefinitions(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getChangeDetectorDefinitionIds(hostComponentMetadata: RenderDirectiveMetadata,
|
|
||||||
nestedPvsWithIndex: RenderProtoViewWithIndex[]): string[] {
|
|
||||||
return nestedPvsWithIndex.map(pvWithIndex => _protoViewId(hostComponentMetadata, pvWithIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
function _protoViewId(hostComponentMetadata: RenderDirectiveMetadata,
|
function _protoViewId(hostComponentMetadata: RenderDirectiveMetadata,
|
||||||
pvWithIndex: RenderProtoViewWithIndex): string {
|
pvWithIndex: RenderProtoViewWithIndex): string {
|
||||||
var typeString;
|
var typeString;
|
||||||
|
@ -329,36 +586,6 @@ function _protoViewId(hostComponentMetadata: RenderDirectiveMetadata,
|
||||||
return `${hostComponentMetadata.id}_${typeString}_${pvWithIndex.index}`;
|
return `${hostComponentMetadata.id}_${typeString}_${pvWithIndex.index}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _createAppProtoView(
|
|
||||||
renderProtoView: ProtoViewDto, protoChangeDetector: ProtoChangeDetector,
|
|
||||||
variableBindings: Map<string, string>, allDirectives: DirectiveBinding[], pipes: PipeBinding[]):
|
|
||||||
AppProtoView {
|
|
||||||
var elementBinders = renderProtoView.elementBinders;
|
|
||||||
// Embedded ProtoViews that contain `<ng-content>` will be merged into their parents and use
|
|
||||||
// a RenderFragmentRef. I.e. renderProtoView.transitiveNgContentCount > 0.
|
|
||||||
var protoPipes = new ProtoPipes(pipes);
|
|
||||||
var protoView = new AppProtoView(
|
|
||||||
renderProtoView.type, renderProtoView.transitiveNgContentCount > 0, renderProtoView.render,
|
|
||||||
protoChangeDetector, variableBindings, createVariableLocations(elementBinders),
|
|
||||||
renderProtoView.textBindings.length, protoPipes);
|
|
||||||
_createElementBinders(protoView, elementBinders, allDirectives);
|
|
||||||
return protoView;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _collectNestedProtoViewsVariableBindings(nestedPvsWithIndex: RenderProtoViewWithIndex[]):
|
|
||||||
Array<Map<string, string>> {
|
|
||||||
return ListWrapper.map(nestedPvsWithIndex, (pvWithIndex) => {
|
|
||||||
return _createVariableBindings(pvWithIndex.renderProtoView);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function _createVariableBindings(renderProtoView): Map<string, string> {
|
|
||||||
var variableBindings = new Map<string, string>();
|
|
||||||
MapWrapper.forEach(renderProtoView.variableBindings,
|
|
||||||
(mappedName, varName) => { variableBindings.set(varName, mappedName); });
|
|
||||||
return variableBindings;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _collectNestedProtoViewsVariableNames(nestedPvsWithIndex: RenderProtoViewWithIndex[]):
|
function _collectNestedProtoViewsVariableNames(nestedPvsWithIndex: RenderProtoViewWithIndex[]):
|
||||||
string[][] {
|
string[][] {
|
||||||
var nestedPvVariableNames = ListWrapper.createFixedSize(nestedPvsWithIndex.length);
|
var nestedPvVariableNames = ListWrapper.createFixedSize(nestedPvsWithIndex.length);
|
||||||
|
@ -382,150 +609,7 @@ function _createVariableNames(parentVariableNames: string[], renderProtoView): s
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createVariableLocations(elementBinders: RenderElementBinder[]):
|
|
||||||
Map<string, number> {
|
|
||||||
var variableLocations = new Map<string, number>();
|
|
||||||
for (var i = 0; i < elementBinders.length; i++) {
|
|
||||||
var binder = elementBinders[i];
|
|
||||||
MapWrapper.forEach(binder.variableBindings,
|
|
||||||
(mappedName, varName) => { variableLocations.set(mappedName, i); });
|
|
||||||
}
|
|
||||||
return variableLocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _createElementBinders(protoView, elementBinders, allDirectiveBindings) {
|
|
||||||
for (var i = 0; i < elementBinders.length; i++) {
|
|
||||||
var renderElementBinder = elementBinders[i];
|
|
||||||
var dirs = elementBinders[i].directives;
|
|
||||||
|
|
||||||
var parentPeiWithDistance =
|
|
||||||
_findParentProtoElementInjectorWithDistance(i, protoView.elementBinders, elementBinders);
|
|
||||||
var directiveBindings =
|
|
||||||
ListWrapper.map(dirs, (dir) => allDirectiveBindings[dir.directiveIndex]);
|
|
||||||
var componentDirectiveBinding = null;
|
|
||||||
if (directiveBindings.length > 0) {
|
|
||||||
if (directiveBindings[0].metadata.type === RenderDirectiveMetadata.COMPONENT_TYPE) {
|
|
||||||
componentDirectiveBinding = directiveBindings[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var protoElementInjector =
|
|
||||||
_createProtoElementInjector(i, parentPeiWithDistance, renderElementBinder,
|
|
||||||
componentDirectiveBinding, directiveBindings);
|
|
||||||
|
|
||||||
_createElementBinder(protoView, i, renderElementBinder, protoElementInjector,
|
|
||||||
componentDirectiveBinding, directiveBindings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function _findParentProtoElementInjectorWithDistance(
|
|
||||||
binderIndex, elementBinders, renderElementBinders): ParentProtoElementInjectorWithDistance {
|
|
||||||
var distance = 0;
|
|
||||||
do {
|
|
||||||
var renderElementBinder = renderElementBinders[binderIndex];
|
|
||||||
binderIndex = renderElementBinder.parentIndex;
|
|
||||||
if (binderIndex !== -1) {
|
|
||||||
distance += renderElementBinder.distanceToParent;
|
|
||||||
var elementBinder = elementBinders[binderIndex];
|
|
||||||
if (isPresent(elementBinder.protoElementInjector)) {
|
|
||||||
return new ParentProtoElementInjectorWithDistance(elementBinder.protoElementInjector,
|
|
||||||
distance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (binderIndex !== -1);
|
|
||||||
return new ParentProtoElementInjectorWithDistance(null, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _createProtoElementInjector(binderIndex, parentPeiWithDistance, renderElementBinder,
|
|
||||||
componentDirectiveBinding, directiveBindings) {
|
|
||||||
var protoElementInjector = null;
|
|
||||||
// Create a protoElementInjector for any element that either has bindings *or* has one
|
|
||||||
// or more var- defined *or* for <template> elements:
|
|
||||||
// - Elements with a var- defined need a their own element injector
|
|
||||||
// so that, when hydrating, $implicit can be set to the element.
|
|
||||||
// - <template> elements need their own ElementInjector so that we can query their TemplateRef
|
|
||||||
var hasVariables = MapWrapper.size(renderElementBinder.variableBindings) > 0;
|
|
||||||
if (directiveBindings.length > 0 || hasVariables ||
|
|
||||||
isPresent(renderElementBinder.nestedProtoView)) {
|
|
||||||
var directiveVariableBindings =
|
|
||||||
createDirectiveVariableBindings(renderElementBinder, directiveBindings);
|
|
||||||
protoElementInjector =
|
|
||||||
ProtoElementInjector.create(parentPeiWithDistance.protoElementInjector, binderIndex,
|
|
||||||
directiveBindings, isPresent(componentDirectiveBinding),
|
|
||||||
parentPeiWithDistance.distance, directiveVariableBindings);
|
|
||||||
protoElementInjector.attributes = renderElementBinder.readAttributes;
|
|
||||||
}
|
|
||||||
return protoElementInjector;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _createElementBinder(protoView: AppProtoView, boundElementIndex, renderElementBinder,
|
|
||||||
protoElementInjector, componentDirectiveBinding, directiveBindings):
|
|
||||||
ElementBinder {
|
|
||||||
var parent = null;
|
|
||||||
if (renderElementBinder.parentIndex !== -1) {
|
|
||||||
parent = protoView.elementBinders[renderElementBinder.parentIndex];
|
|
||||||
}
|
|
||||||
var elBinder = protoView.bindElement(parent, renderElementBinder.distanceToParent,
|
|
||||||
protoElementInjector, componentDirectiveBinding);
|
|
||||||
// The view's locals needs to have a full set of variable names at construction time
|
|
||||||
// in order to prevent new variables from being set later in the lifecycle. Since we don't want
|
|
||||||
// to actually create variable bindings for the $implicit bindings, add to the
|
|
||||||
// protoLocals manually.
|
|
||||||
MapWrapper.forEach(renderElementBinder.variableBindings,
|
|
||||||
(mappedName, varName) => { protoView.protoLocals.set(mappedName, null); });
|
|
||||||
return elBinder;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createDirectiveVariableBindings(renderElementBinder: RenderElementBinder,
|
|
||||||
directiveBindings: DirectiveBinding[]):
|
|
||||||
Map<string, number> {
|
|
||||||
var directiveVariableBindings = new Map<string, number>();
|
|
||||||
MapWrapper.forEach(renderElementBinder.variableBindings, (templateName, exportAs) => {
|
|
||||||
var dirIndex = _findDirectiveIndexByExportAs(renderElementBinder, directiveBindings, exportAs);
|
|
||||||
directiveVariableBindings.set(templateName, dirIndex);
|
|
||||||
});
|
|
||||||
return directiveVariableBindings;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _findDirectiveIndexByExportAs(renderElementBinder, directiveBindings, exportAs) {
|
|
||||||
var matchedDirectiveIndex = null;
|
|
||||||
var matchedDirective;
|
|
||||||
|
|
||||||
for (var i = 0; i < directiveBindings.length; ++i) {
|
|
||||||
var directive = directiveBindings[i];
|
|
||||||
|
|
||||||
if (_directiveExportAs(directive) == exportAs) {
|
|
||||||
if (isPresent(matchedDirective)) {
|
|
||||||
throw new BaseException(
|
|
||||||
`More than one directive have exportAs = '${exportAs}'. Directives: [${matchedDirective.displayName}, ${directive.displayName}]`);
|
|
||||||
}
|
|
||||||
|
|
||||||
matchedDirectiveIndex = i;
|
|
||||||
matchedDirective = directive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBlank(matchedDirective) && !StringWrapper.equals(exportAs, "$implicit")) {
|
|
||||||
throw new BaseException(`Cannot find directive with exportAs = '${exportAs}'`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return matchedDirectiveIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _directiveExportAs(directive): string {
|
|
||||||
var directiveExportAs = directive.metadata.exportAs;
|
|
||||||
if (isBlank(directiveExportAs) &&
|
|
||||||
directive.metadata.type === RenderDirectiveMetadata.COMPONENT_TYPE) {
|
|
||||||
return "$implicit";
|
|
||||||
} else {
|
|
||||||
return directiveExportAs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RenderProtoViewWithIndex {
|
class RenderProtoViewWithIndex {
|
||||||
constructor(public renderProtoView: ProtoViewDto, public index: number,
|
constructor(public renderProtoView: ProtoViewDto, public index: number,
|
||||||
public parentIndex: number, public boundElementIndex: number) {}
|
public parentIndex: number, public boundElementIndex: number) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ParentProtoElementInjectorWithDistance {
|
|
||||||
constructor(public protoElementInjector: ProtoElementInjector, public distance: number) {}
|
|
||||||
}
|
|
||||||
|
|
|
@ -52,5 +52,7 @@ export class TemplateRef {
|
||||||
/**
|
/**
|
||||||
* Allows you to check if this Embedded Template defines Local Variable with name matching `name`.
|
* Allows you to check if this Embedded Template defines Local Variable with name matching `name`.
|
||||||
*/
|
*/
|
||||||
hasLocal(name: string): boolean { return this._getProtoView().variableBindings.has(name); }
|
hasLocal(name: string): boolean {
|
||||||
|
return this._getProtoView().templateVariableBindings.has(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,45 +33,12 @@ import {ViewRef, ProtoViewRef, internalView} from './view_ref';
|
||||||
import {ElementRef} from './element_ref';
|
import {ElementRef} from './element_ref';
|
||||||
import {ProtoPipes} from 'angular2/src/core/pipes/pipes';
|
import {ProtoPipes} from 'angular2/src/core/pipes/pipes';
|
||||||
import {camelCaseToDashCase} from 'angular2/src/core/render/dom/util';
|
import {camelCaseToDashCase} from 'angular2/src/core/render/dom/util';
|
||||||
|
import {TemplateCmd} from './template_commands';
|
||||||
|
|
||||||
export {DebugContext} from 'angular2/src/core/change_detection/interfaces';
|
export {DebugContext} from 'angular2/src/core/change_detection/interfaces';
|
||||||
|
|
||||||
const REFLECT_PREFIX: string = 'ng-reflect-';
|
const REFLECT_PREFIX: string = 'ng-reflect-';
|
||||||
|
|
||||||
export class AppProtoViewMergeMapping {
|
|
||||||
renderProtoViewRef: renderApi.RenderProtoViewRef;
|
|
||||||
renderFragmentCount: number;
|
|
||||||
renderElementIndices: number[];
|
|
||||||
renderInverseElementIndices: number[];
|
|
||||||
renderTextIndices: number[];
|
|
||||||
nestedViewIndicesByElementIndex: number[];
|
|
||||||
hostElementIndicesByViewIndex: number[];
|
|
||||||
nestedViewCountByViewIndex: number[];
|
|
||||||
constructor(renderProtoViewMergeMapping: renderApi.RenderProtoViewMergeMapping) {
|
|
||||||
this.renderProtoViewRef = renderProtoViewMergeMapping.mergedProtoViewRef;
|
|
||||||
this.renderFragmentCount = renderProtoViewMergeMapping.fragmentCount;
|
|
||||||
this.renderElementIndices = renderProtoViewMergeMapping.mappedElementIndices;
|
|
||||||
this.renderInverseElementIndices = inverseIndexMapping(
|
|
||||||
this.renderElementIndices, renderProtoViewMergeMapping.mappedElementCount);
|
|
||||||
this.renderTextIndices = renderProtoViewMergeMapping.mappedTextIndices;
|
|
||||||
this.hostElementIndicesByViewIndex = renderProtoViewMergeMapping.hostElementIndicesByViewIndex;
|
|
||||||
this.nestedViewIndicesByElementIndex =
|
|
||||||
inverseIndexMapping(this.hostElementIndicesByViewIndex, this.renderElementIndices.length);
|
|
||||||
this.nestedViewCountByViewIndex = renderProtoViewMergeMapping.nestedViewCountByViewIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function inverseIndexMapping(input: number[], resultLength: number): number[] {
|
|
||||||
var result = ListWrapper.createGrowableSize(resultLength);
|
|
||||||
for (var i = 0; i < input.length; i++) {
|
|
||||||
var value = input[i];
|
|
||||||
if (isPresent(value)) {
|
|
||||||
result[input[i]] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AppViewContainer {
|
export class AppViewContainer {
|
||||||
// The order in this list matches the DOM order.
|
// The order in this list matches the DOM order.
|
||||||
views: AppView[] = [];
|
views: AppView[] = [];
|
||||||
|
@ -109,7 +76,6 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
|
||||||
ref: ViewRef;
|
ref: ViewRef;
|
||||||
changeDetector: ChangeDetector = null;
|
changeDetector: ChangeDetector = null;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The context against which data-binding expressions in this view are evaluated against.
|
* The context against which data-binding expressions in this view are evaluated against.
|
||||||
* This is always a component instance.
|
* This is always a component instance.
|
||||||
|
@ -125,10 +91,10 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
|
||||||
locals: Locals;
|
locals: Locals;
|
||||||
|
|
||||||
constructor(public renderer: renderApi.Renderer, public proto: AppProtoView,
|
constructor(public renderer: renderApi.Renderer, public proto: AppProtoView,
|
||||||
public mainMergeMapping: AppProtoViewMergeMapping, public viewOffset: number,
|
public viewOffset: number, public elementOffset: number, public textOffset: number,
|
||||||
public elementOffset: number, public textOffset: number,
|
|
||||||
protoLocals: Map<string, any>, public render: renderApi.RenderViewRef,
|
protoLocals: Map<string, any>, public render: renderApi.RenderViewRef,
|
||||||
public renderFragment: renderApi.RenderFragmentRef) {
|
public renderFragment: renderApi.RenderFragmentRef,
|
||||||
|
public containerElementInjector: ElementInjector) {
|
||||||
this.ref = new ViewRef(this);
|
this.ref = new ViewRef(this);
|
||||||
|
|
||||||
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); // TODO optimize this
|
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); // TODO optimize this
|
||||||
|
@ -148,10 +114,10 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
|
||||||
|
|
||||||
setLocal(contextName: string, value: any): void {
|
setLocal(contextName: string, value: any): void {
|
||||||
if (!this.hydrated()) throw new BaseException('Cannot set locals on dehydrated view.');
|
if (!this.hydrated()) throw new BaseException('Cannot set locals on dehydrated view.');
|
||||||
if (!this.proto.variableBindings.has(contextName)) {
|
if (!this.proto.templateVariableBindings.has(contextName)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var templateName = this.proto.variableBindings.get(contextName);
|
var templateName = this.proto.templateVariableBindings.get(contextName);
|
||||||
this.locals.set(templateName, value);
|
this.locals.set(templateName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,9 +141,7 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
|
||||||
// dispatch to element injector or text nodes based on context
|
// dispatch to element injector or text nodes based on context
|
||||||
notifyOnBinding(b: BindingTarget, currentValue: any): void {
|
notifyOnBinding(b: BindingTarget, currentValue: any): void {
|
||||||
if (b.isTextNode()) {
|
if (b.isTextNode()) {
|
||||||
this.renderer.setText(
|
this.renderer.setText(this.render, b.elementIndex + this.textOffset, currentValue);
|
||||||
this.render, this.mainMergeMapping.renderTextIndices[b.elementIndex + this.textOffset],
|
|
||||||
currentValue);
|
|
||||||
} else {
|
} else {
|
||||||
var elementRef = this.elementRefs[this.elementOffset + b.elementIndex];
|
var elementRef = this.elementRefs[this.elementOffset + b.elementIndex];
|
||||||
if (b.isElementProperty()) {
|
if (b.isElementProperty()) {
|
||||||
|
@ -226,13 +190,14 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
getNestedView(boundElementIndex: number): AppView {
|
getNestedView(boundElementIndex: number): AppView {
|
||||||
var viewIndex = this.mainMergeMapping.nestedViewIndicesByElementIndex[boundElementIndex];
|
var eli = this.elementInjectors[boundElementIndex];
|
||||||
return isPresent(viewIndex) ? this.views[viewIndex] : null;
|
return isPresent(eli) ? eli.getNestedView() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHostElement(): ElementRef {
|
getContainerElement(): ElementRef {
|
||||||
var boundElementIndex = this.mainMergeMapping.hostElementIndicesByViewIndex[this.viewOffset];
|
return isPresent(this.containerElementInjector) ?
|
||||||
return isPresent(boundElementIndex) ? this.elementRefs[boundElementIndex] : null;
|
this.containerElementInjector.getElementRef() :
|
||||||
|
null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDebugContext(elementIndex: number, directiveIndex: DirectiveIndex): DebugContext {
|
getDebugContext(elementIndex: number, directiveIndex: DirectiveIndex): DebugContext {
|
||||||
|
@ -241,11 +206,11 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
|
||||||
var hasRefForIndex = offsettedIndex < this.elementRefs.length;
|
var hasRefForIndex = offsettedIndex < this.elementRefs.length;
|
||||||
|
|
||||||
var elementRef = hasRefForIndex ? this.elementRefs[this.elementOffset + elementIndex] : null;
|
var elementRef = hasRefForIndex ? this.elementRefs[this.elementOffset + elementIndex] : null;
|
||||||
var host = this.getHostElement();
|
var container = this.getContainerElement();
|
||||||
var ei = hasRefForIndex ? this.elementInjectors[this.elementOffset + elementIndex] : null;
|
var ei = hasRefForIndex ? this.elementInjectors[this.elementOffset + elementIndex] : null;
|
||||||
|
|
||||||
var element = isPresent(elementRef) ? elementRef.nativeElement : null;
|
var element = isPresent(elementRef) ? elementRef.nativeElement : null;
|
||||||
var componentElement = isPresent(host) ? host.nativeElement : null;
|
var componentElement = isPresent(container) ? container.nativeElement : null;
|
||||||
var directive = isPresent(directiveIndex) ? this.getDirectiveFor(directiveIndex) : null;
|
var directive = isPresent(directiveIndex) ? this.getDirectiveFor(directiveIndex) : null;
|
||||||
var injector = isPresent(ei) ? ei.getInjector() : null;
|
var injector = isPresent(ei) ? ei.getInjector() : null;
|
||||||
|
|
||||||
|
@ -269,10 +234,9 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
// implementation of RenderEventDispatcher#dispatchRenderEvent
|
// implementation of RenderEventDispatcher#dispatchRenderEvent
|
||||||
dispatchRenderEvent(renderElementIndex: number, eventName: string,
|
dispatchRenderEvent(boundElementIndex: number, eventName: string,
|
||||||
locals: Map<string, any>): boolean {
|
locals: Map<string, any>): boolean {
|
||||||
var elementRef =
|
var elementRef = this.elementRefs[boundElementIndex];
|
||||||
this.elementRefs[this.mainMergeMapping.renderInverseElementIndices[renderElementIndex]];
|
|
||||||
var view = internalView(elementRef.parentView);
|
var view = internalView(elementRef.parentView);
|
||||||
return view.dispatchEvent(elementRef.boundElementIndex, eventName, locals);
|
return view.dispatchEvent(elementRef.boundElementIndex, eventName, locals);
|
||||||
}
|
}
|
||||||
|
@ -326,36 +290,53 @@ class EventEvaluationError extends WrappedException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class AppProtoViewMergeInfo {
|
||||||
|
constructor(public embeddedViewCount: number, public elementCount: number,
|
||||||
|
public viewCount: number) {}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export class AppProtoView {
|
export class AppProtoView {
|
||||||
elementBinders: ElementBinder[] = [];
|
|
||||||
protoLocals = new Map<string, any>();
|
|
||||||
mergeMapping: AppProtoViewMergeMapping;
|
|
||||||
ref: ProtoViewRef;
|
ref: ProtoViewRef;
|
||||||
|
protoLocals: Map<string, any>;
|
||||||
|
|
||||||
constructor(public type: renderApi.ViewType, public isEmbeddedFragment: boolean,
|
elementBinders: ElementBinder[] = null;
|
||||||
public render: renderApi.RenderProtoViewRef,
|
mergeInfo: AppProtoViewMergeInfo = null;
|
||||||
public protoChangeDetector: ProtoChangeDetector,
|
variableLocations: Map<string, number> = null;
|
||||||
public variableBindings: Map<string, string>,
|
textBindingCount = null;
|
||||||
public variableLocations: Map<string, number>, public textBindingCount: number,
|
render: renderApi.RenderProtoViewRef = null;
|
||||||
public pipes: ProtoPipes) {
|
|
||||||
|
constructor(public templateCmds: TemplateCmd[], public type: renderApi.ViewType,
|
||||||
|
public isMergable: boolean, public changeDetectorFactory: Function,
|
||||||
|
public templateVariableBindings: Map<string, string>, public pipes: ProtoPipes) {
|
||||||
this.ref = new ProtoViewRef(this);
|
this.ref = new ProtoViewRef(this);
|
||||||
if (isPresent(variableBindings)) {
|
}
|
||||||
MapWrapper.forEach(variableBindings,
|
|
||||||
|
init(render: renderApi.RenderProtoViewRef, elementBinders: ElementBinder[],
|
||||||
|
textBindingCount: number, mergeInfo: AppProtoViewMergeInfo,
|
||||||
|
variableLocations: Map<string, number>) {
|
||||||
|
this.render = render;
|
||||||
|
this.elementBinders = elementBinders;
|
||||||
|
this.textBindingCount = textBindingCount;
|
||||||
|
this.mergeInfo = mergeInfo;
|
||||||
|
this.variableLocations = variableLocations;
|
||||||
|
this.protoLocals = new Map<string, any>();
|
||||||
|
if (isPresent(this.templateVariableBindings)) {
|
||||||
|
MapWrapper.forEach(this.templateVariableBindings,
|
||||||
(templateName, _) => { this.protoLocals.set(templateName, null); });
|
(templateName, _) => { this.protoLocals.set(templateName, null); });
|
||||||
}
|
}
|
||||||
|
if (isPresent(variableLocations)) {
|
||||||
|
// The view's locals needs to have a full set of variable names at construction time
|
||||||
|
// in order to prevent new variables from being set later in the lifecycle. Since we don't
|
||||||
|
// want
|
||||||
|
// to actually create variable bindings for the $implicit bindings, add to the
|
||||||
|
// protoLocals manually.
|
||||||
|
MapWrapper.forEach(variableLocations,
|
||||||
|
(_, templateName) => { this.protoLocals.set(templateName, null); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bindElement(parent: ElementBinder, distanceToParent: number,
|
isInitialized(): boolean { return isPresent(this.elementBinders); }
|
||||||
protoElementInjector: ProtoElementInjector,
|
|
||||||
componentDirective: DirectiveBinding = null): ElementBinder {
|
|
||||||
var elBinder = new ElementBinder(this.elementBinders.length, parent, distanceToParent,
|
|
||||||
protoElementInjector, componentDirective);
|
|
||||||
|
|
||||||
this.elementBinders.push(elBinder);
|
|
||||||
return elBinder;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,4 +1,11 @@
|
||||||
import {Injector, Binding, Injectable, ResolvedBinding} from 'angular2/src/core/di';
|
import {
|
||||||
|
Injector,
|
||||||
|
Inject,
|
||||||
|
Binding,
|
||||||
|
Injectable,
|
||||||
|
ResolvedBinding,
|
||||||
|
forwardRef
|
||||||
|
} from 'angular2/src/core/di';
|
||||||
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
|
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
|
||||||
import {BaseException} from 'angular2/src/core/facade/exceptions';
|
import {BaseException} from 'angular2/src/core/facade/exceptions';
|
||||||
import * as viewModule from './view';
|
import * as viewModule from './view';
|
||||||
|
@ -17,6 +24,7 @@ import {AppViewManagerUtils} from './view_manager_utils';
|
||||||
import {AppViewPool} from './view_pool';
|
import {AppViewPool} from './view_pool';
|
||||||
import {AppViewListener} from './view_listener';
|
import {AppViewListener} from './view_listener';
|
||||||
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
|
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
|
||||||
|
import {ProtoViewFactory} from './proto_view_factory';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service exposing low level API for creating, moving and destroying Views.
|
* Service exposing low level API for creating, moving and destroying Views.
|
||||||
|
@ -26,11 +34,15 @@ import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AppViewManager {
|
export class AppViewManager {
|
||||||
|
private _protoViewFactory: ProtoViewFactory;
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
constructor(private _viewPool: AppViewPool, private _viewListener: AppViewListener,
|
constructor(private _viewPool: AppViewPool, private _viewListener: AppViewListener,
|
||||||
private _utils: AppViewManagerUtils, private _renderer: Renderer) {}
|
private _utils: AppViewManagerUtils, private _renderer: Renderer,
|
||||||
|
@Inject(forwardRef(() => ProtoViewFactory)) _protoViewFactory) {
|
||||||
|
this._protoViewFactory = _protoViewFactory;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link ViewContainerRef} of the View Container at the specified location.
|
* Returns a {@link ViewContainerRef} of the View Container at the specified location.
|
||||||
|
@ -138,13 +150,13 @@ export class AppViewManager {
|
||||||
injector: Injector): HostViewRef {
|
injector: Injector): HostViewRef {
|
||||||
var s = this._createRootHostViewScope();
|
var s = this._createRootHostViewScope();
|
||||||
var hostProtoView: viewModule.AppProtoView = internalProtoView(hostProtoViewRef);
|
var hostProtoView: viewModule.AppProtoView = internalProtoView(hostProtoViewRef);
|
||||||
|
this._protoViewFactory.initializeProtoViewIfNeeded(hostProtoView);
|
||||||
var hostElementSelector = overrideSelector;
|
var hostElementSelector = overrideSelector;
|
||||||
if (isBlank(hostElementSelector)) {
|
if (isBlank(hostElementSelector)) {
|
||||||
hostElementSelector = hostProtoView.elementBinders[0].componentDirective.metadata.selector;
|
hostElementSelector = hostProtoView.elementBinders[0].componentDirective.metadata.selector;
|
||||||
}
|
}
|
||||||
var renderViewWithFragments = this._renderer.createRootHostView(
|
var renderViewWithFragments = this._renderer.createRootHostView(
|
||||||
hostProtoView.mergeMapping.renderProtoViewRef,
|
hostProtoView.render, hostProtoView.mergeInfo.embeddedViewCount + 1, hostElementSelector);
|
||||||
hostProtoView.mergeMapping.renderFragmentCount, hostElementSelector);
|
|
||||||
var hostView = this._createMainView(hostProtoView, renderViewWithFragments);
|
var hostView = this._createMainView(hostProtoView, renderViewWithFragments);
|
||||||
|
|
||||||
this._renderer.hydrateView(hostView.render);
|
this._renderer.hydrateView(hostView.render);
|
||||||
|
@ -196,6 +208,7 @@ export class AppViewManager {
|
||||||
if (protoView.type !== ViewType.EMBEDDED) {
|
if (protoView.type !== ViewType.EMBEDDED) {
|
||||||
throw new BaseException('This method can only be called with embedded ProtoViews!');
|
throw new BaseException('This method can only be called with embedded ProtoViews!');
|
||||||
}
|
}
|
||||||
|
this._protoViewFactory.initializeProtoViewIfNeeded(protoView);
|
||||||
return wtfLeave(s, this._createViewInContainer(viewContainerLocation, index, protoView,
|
return wtfLeave(s, this._createViewInContainer(viewContainerLocation, index, protoView,
|
||||||
templateRef.elementRef, null));
|
templateRef.elementRef, null));
|
||||||
}
|
}
|
||||||
|
@ -226,6 +239,7 @@ export class AppViewManager {
|
||||||
if (protoView.type !== ViewType.HOST) {
|
if (protoView.type !== ViewType.HOST) {
|
||||||
throw new BaseException('This method can only be called with host ProtoViews!');
|
throw new BaseException('This method can only be called with host ProtoViews!');
|
||||||
}
|
}
|
||||||
|
this._protoViewFactory.initializeProtoViewIfNeeded(protoView);
|
||||||
return wtfLeave(
|
return wtfLeave(
|
||||||
s, this._createViewInContainer(viewContainerLocation, index, protoView,
|
s, this._createViewInContainer(viewContainerLocation, index, protoView,
|
||||||
viewContainerLocation, imperativelyCreatedInjector));
|
viewContainerLocation, imperativelyCreatedInjector));
|
||||||
|
@ -345,8 +359,8 @@ export class AppViewManager {
|
||||||
var view = this._viewPool.getView(protoView);
|
var view = this._viewPool.getView(protoView);
|
||||||
if (isBlank(view)) {
|
if (isBlank(view)) {
|
||||||
view = this._createMainView(
|
view = this._createMainView(
|
||||||
protoView, this._renderer.createView(protoView.mergeMapping.renderProtoViewRef,
|
protoView,
|
||||||
protoView.mergeMapping.renderFragmentCount));
|
this._renderer.createView(protoView.render, protoView.mergeInfo.embeddedViewCount + 1));
|
||||||
}
|
}
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
@ -385,8 +399,7 @@ export class AppViewManager {
|
||||||
}
|
}
|
||||||
var viewContainers = view.viewContainers;
|
var viewContainers = view.viewContainers;
|
||||||
var startViewOffset = view.viewOffset;
|
var startViewOffset = view.viewOffset;
|
||||||
var endViewOffset =
|
var endViewOffset = view.viewOffset + view.proto.mergeInfo.viewCount - 1;
|
||||||
view.viewOffset + view.mainMergeMapping.nestedViewCountByViewIndex[view.viewOffset];
|
|
||||||
var elementOffset = view.elementOffset;
|
var elementOffset = view.elementOffset;
|
||||||
for (var viewIdx = startViewOffset; viewIdx <= endViewOffset; viewIdx++) {
|
for (var viewIdx = startViewOffset; viewIdx <= endViewOffset; viewIdx++) {
|
||||||
var currView = view.views[viewIdx];
|
var currView = view.views[viewIdx];
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {ListWrapper, MapWrapper, Map, StringMapWrapper} from 'angular2/src/core/
|
||||||
import * as eli from './element_injector';
|
import * as eli from './element_injector';
|
||||||
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
|
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
|
||||||
import * as viewModule from './view';
|
import * as viewModule from './view';
|
||||||
import {internalView} from './view_ref';
|
|
||||||
import * as avmModule from './view_manager';
|
import * as avmModule from './view_manager';
|
||||||
import {ElementRef} from './element_ref';
|
import {ElementRef} from './element_ref';
|
||||||
import {TemplateRef} from './template_ref';
|
import {TemplateRef} from './template_ref';
|
||||||
|
@ -27,42 +26,52 @@ export class AppViewManagerUtils {
|
||||||
var renderFragments = renderViewWithFragments.fragmentRefs;
|
var renderFragments = renderViewWithFragments.fragmentRefs;
|
||||||
var renderView = renderViewWithFragments.viewRef;
|
var renderView = renderViewWithFragments.viewRef;
|
||||||
|
|
||||||
var elementCount = mergedParentViewProto.mergeMapping.renderElementIndices.length;
|
var elementCount = mergedParentViewProto.mergeInfo.elementCount;
|
||||||
var viewCount = mergedParentViewProto.mergeMapping.nestedViewCountByViewIndex[0] + 1;
|
var viewCount = mergedParentViewProto.mergeInfo.viewCount;
|
||||||
var elementRefs: ElementRef[] = ListWrapper.createFixedSize(elementCount);
|
var elementRefs: ElementRef[] = ListWrapper.createFixedSize(elementCount);
|
||||||
var viewContainers = ListWrapper.createFixedSize(elementCount);
|
var viewContainers = ListWrapper.createFixedSize(elementCount);
|
||||||
var preBuiltObjects: eli.PreBuiltObjects[] = ListWrapper.createFixedSize(elementCount);
|
var preBuiltObjects: eli.PreBuiltObjects[] = ListWrapper.createFixedSize(elementCount);
|
||||||
var elementInjectors = ListWrapper.createFixedSize(elementCount);
|
var elementInjectors: eli.ElementInjector[] = ListWrapper.createFixedSize(elementCount);
|
||||||
var views = ListWrapper.createFixedSize(viewCount);
|
var views = ListWrapper.createFixedSize(viewCount);
|
||||||
|
|
||||||
var elementOffset = 0;
|
var elementOffset = 0;
|
||||||
var textOffset = 0;
|
var textOffset = 0;
|
||||||
var fragmentIdx = 0;
|
var fragmentIdx = 0;
|
||||||
|
var containerElementIndicesByViewIndex: number[] = ListWrapper.createFixedSize(viewCount);
|
||||||
for (var viewOffset = 0; viewOffset < viewCount; viewOffset++) {
|
for (var viewOffset = 0; viewOffset < viewCount; viewOffset++) {
|
||||||
var hostElementIndex =
|
var containerElementIndex = containerElementIndicesByViewIndex[viewOffset];
|
||||||
mergedParentViewProto.mergeMapping.hostElementIndicesByViewIndex[viewOffset];
|
var containerElementInjector =
|
||||||
var parentView = isPresent(hostElementIndex) ?
|
isPresent(containerElementIndex) ? elementInjectors[containerElementIndex] : null;
|
||||||
internalView(elementRefs[hostElementIndex].parentView) :
|
var parentView =
|
||||||
null;
|
isPresent(containerElementInjector) ? preBuiltObjects[containerElementIndex].view : null;
|
||||||
var protoView =
|
var protoView =
|
||||||
isPresent(hostElementIndex) ?
|
isPresent(containerElementIndex) ?
|
||||||
parentView.proto.elementBinders[hostElementIndex - parentView.elementOffset]
|
parentView.proto.elementBinders[containerElementIndex - parentView.elementOffset]
|
||||||
.nestedProtoView :
|
.nestedProtoView :
|
||||||
mergedParentViewProto;
|
mergedParentViewProto;
|
||||||
var renderFragment = null;
|
var renderFragment = null;
|
||||||
if (viewOffset === 0 || protoView.type === ViewType.EMBEDDED) {
|
if (viewOffset === 0 || protoView.type === ViewType.EMBEDDED) {
|
||||||
renderFragment = renderFragments[fragmentIdx++];
|
renderFragment = renderFragments[fragmentIdx++];
|
||||||
}
|
}
|
||||||
var currentView = new viewModule.AppView(
|
var currentView = new viewModule.AppView(renderer, protoView, viewOffset, elementOffset,
|
||||||
renderer, protoView, mergedParentViewProto.mergeMapping, viewOffset, elementOffset,
|
textOffset, protoView.protoLocals, renderView,
|
||||||
textOffset, protoView.protoLocals, renderView, renderFragment);
|
renderFragment, containerElementInjector);
|
||||||
views[viewOffset] = currentView;
|
views[viewOffset] = currentView;
|
||||||
|
if (isPresent(containerElementIndex)) {
|
||||||
|
preBuiltObjects[containerElementIndex].nestedView = currentView;
|
||||||
|
}
|
||||||
var rootElementInjectors = [];
|
var rootElementInjectors = [];
|
||||||
|
var nestedViewOffset = viewOffset + 1;
|
||||||
for (var binderIdx = 0; binderIdx < protoView.elementBinders.length; binderIdx++) {
|
for (var binderIdx = 0; binderIdx < protoView.elementBinders.length; binderIdx++) {
|
||||||
var binder = protoView.elementBinders[binderIdx];
|
var binder = protoView.elementBinders[binderIdx];
|
||||||
var boundElementIndex = elementOffset + binderIdx;
|
var boundElementIndex = elementOffset + binderIdx;
|
||||||
var elementInjector = null;
|
var elementInjector = null;
|
||||||
|
|
||||||
|
if (isPresent(binder.nestedProtoView) && binder.nestedProtoView.isMergable) {
|
||||||
|
containerElementIndicesByViewIndex[nestedViewOffset] = boundElementIndex;
|
||||||
|
nestedViewOffset += binder.nestedProtoView.mergeInfo.viewCount;
|
||||||
|
}
|
||||||
|
|
||||||
// elementInjectors and rootElementInjectors
|
// elementInjectors and rootElementInjectors
|
||||||
var protoElementInjector = binder.protoElementInjector;
|
var protoElementInjector = binder.protoElementInjector;
|
||||||
if (isPresent(protoElementInjector)) {
|
if (isPresent(protoElementInjector)) {
|
||||||
|
@ -78,19 +87,20 @@ export class AppViewManagerUtils {
|
||||||
elementInjectors[boundElementIndex] = elementInjector;
|
elementInjectors[boundElementIndex] = elementInjector;
|
||||||
|
|
||||||
// elementRefs
|
// elementRefs
|
||||||
var el = new ElementRef(
|
var el = new ElementRef(currentView.ref, boundElementIndex, renderer);
|
||||||
currentView.ref, boundElementIndex,
|
|
||||||
mergedParentViewProto.mergeMapping.renderElementIndices[boundElementIndex], renderer);
|
|
||||||
elementRefs[el.boundElementIndex] = el;
|
elementRefs[el.boundElementIndex] = el;
|
||||||
|
|
||||||
// preBuiltObjects
|
// preBuiltObjects
|
||||||
if (isPresent(elementInjector)) {
|
if (isPresent(elementInjector)) {
|
||||||
var templateRef = binder.hasEmbeddedProtoView() ? new TemplateRef(el) : null;
|
var templateRef = isPresent(binder.nestedProtoView) &&
|
||||||
|
binder.nestedProtoView.type === ViewType.EMBEDDED ?
|
||||||
|
new TemplateRef(el) :
|
||||||
|
null;
|
||||||
preBuiltObjects[boundElementIndex] =
|
preBuiltObjects[boundElementIndex] =
|
||||||
new eli.PreBuiltObjects(viewManager, currentView, el, templateRef);
|
new eli.PreBuiltObjects(viewManager, currentView, el, templateRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentView.init(protoView.protoChangeDetector.instantiate(currentView), elementInjectors,
|
currentView.init(protoView.changeDetectorFactory(currentView), elementInjectors,
|
||||||
rootElementInjectors, preBuiltObjects, views, elementRefs, viewContainers);
|
rootElementInjectors, preBuiltObjects, views, elementRefs, viewContainers);
|
||||||
if (isPresent(parentView) && protoView.type === ViewType.COMPONENT) {
|
if (isPresent(parentView) && protoView.type === ViewType.COMPONENT) {
|
||||||
parentView.changeDetector.addShadowDomChild(currentView.changeDetector);
|
parentView.changeDetector.addShadowDomChild(currentView.changeDetector);
|
||||||
|
@ -166,20 +176,19 @@ export class AppViewManagerUtils {
|
||||||
_hydrateView(initView: viewModule.AppView, imperativelyCreatedInjector: Injector,
|
_hydrateView(initView: viewModule.AppView, imperativelyCreatedInjector: Injector,
|
||||||
hostElementInjector: eli.ElementInjector, context: Object, parentLocals: Locals) {
|
hostElementInjector: eli.ElementInjector, context: Object, parentLocals: Locals) {
|
||||||
var viewIdx = initView.viewOffset;
|
var viewIdx = initView.viewOffset;
|
||||||
var endViewOffset = viewIdx + initView.mainMergeMapping.nestedViewCountByViewIndex[viewIdx];
|
var endViewOffset = viewIdx + initView.proto.mergeInfo.viewCount - 1;
|
||||||
while (viewIdx <= endViewOffset) {
|
while (viewIdx <= endViewOffset) {
|
||||||
var currView = initView.views[viewIdx];
|
var currView = initView.views[viewIdx];
|
||||||
var currProtoView = currView.proto;
|
var currProtoView = currView.proto;
|
||||||
if (currView !== initView && currView.proto.type === ViewType.EMBEDDED) {
|
if (currView !== initView && currView.proto.type === ViewType.EMBEDDED) {
|
||||||
// Don't hydrate components of embedded fragment views.
|
// Don't hydrate components of embedded fragment views.
|
||||||
viewIdx += initView.mainMergeMapping.nestedViewCountByViewIndex[viewIdx] + 1;
|
viewIdx += currView.proto.mergeInfo.viewCount;
|
||||||
} else {
|
} else {
|
||||||
if (currView !== initView) {
|
if (currView !== initView) {
|
||||||
// hydrate a nested component view
|
// hydrate a nested component view
|
||||||
imperativelyCreatedInjector = null;
|
imperativelyCreatedInjector = null;
|
||||||
parentLocals = null;
|
parentLocals = null;
|
||||||
var hostElementIndex = initView.mainMergeMapping.hostElementIndicesByViewIndex[viewIdx];
|
hostElementInjector = currView.containerElementInjector;
|
||||||
hostElementInjector = initView.elementInjectors[hostElementIndex];
|
|
||||||
context = hostElementInjector.getComponent();
|
context = hostElementInjector.getComponent();
|
||||||
}
|
}
|
||||||
currView.context = context;
|
currView.context = context;
|
||||||
|
@ -233,8 +242,7 @@ export class AppViewManagerUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
dehydrateView(initView: viewModule.AppView) {
|
dehydrateView(initView: viewModule.AppView) {
|
||||||
var endViewOffset = initView.viewOffset +
|
var endViewOffset = initView.viewOffset + initView.proto.mergeInfo.viewCount - 1;
|
||||||
initView.mainMergeMapping.nestedViewCountByViewIndex[initView.viewOffset];
|
|
||||||
for (var viewIdx = initView.viewOffset; viewIdx <= endViewOffset; viewIdx++) {
|
for (var viewIdx = initView.viewOffset; viewIdx <= endViewOffset; viewIdx++) {
|
||||||
var currView = initView.views[viewIdx];
|
var currView = initView.views[viewIdx];
|
||||||
if (currView.hydrated()) {
|
if (currView.hydrated()) {
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
library angular2.di_transformer_dart;
|
|
||||||
|
|
||||||
export '../../transform/di_transformer.dart';
|
|
|
@ -8,19 +8,16 @@ import {CONST_EXPR, Type} from './facade/lang';
|
||||||
import {NgClass} from './directives/ng_class';
|
import {NgClass} from './directives/ng_class';
|
||||||
import {NgFor} from './directives/ng_for';
|
import {NgFor} from './directives/ng_for';
|
||||||
import {NgIf} from './directives/ng_if';
|
import {NgIf} from './directives/ng_if';
|
||||||
import {NgNonBindable} from './directives/ng_non_bindable';
|
|
||||||
import {NgStyle} from './directives/ng_style';
|
import {NgStyle} from './directives/ng_style';
|
||||||
import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
|
import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
|
||||||
|
|
||||||
export {NgClass} from './directives/ng_class';
|
export {NgClass} from './directives/ng_class';
|
||||||
export {NgFor} from './directives/ng_for';
|
export {NgFor} from './directives/ng_for';
|
||||||
export {NgIf} from './directives/ng_if';
|
export {NgIf} from './directives/ng_if';
|
||||||
export {NgNonBindable} from './directives/ng_non_bindable';
|
|
||||||
export {NgStyle} from './directives/ng_style';
|
export {NgStyle} from './directives/ng_style';
|
||||||
export {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
|
export {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
|
||||||
export * from './directives/observable_list_diff';
|
export * from './directives/observable_list_diff';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of Angular core directives that are likely to be used in each and every Angular
|
* A collection of Angular core directives that are likely to be used in each and every Angular
|
||||||
* application.
|
* application.
|
||||||
|
@ -65,5 +62,5 @@ export * from './directives/observable_list_diff';
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export const CORE_DIRECTIVES: Type[] = CONST_EXPR(
|
export const CORE_DIRECTIVES: Type[] =
|
||||||
[NgClass, NgFor, NgIf, NgNonBindable, NgStyle, NgSwitch, NgSwitchWhen, NgSwitchDefault]);
|
CONST_EXPR([NgClass, NgFor, NgIf, NgStyle, NgSwitch, NgSwitchWhen, NgSwitchDefault]);
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
import {Directive} from 'angular2/src/core/metadata';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `NgNonBindable` directive tells Angular not to compile or bind the contents of the current
|
|
||||||
* DOM element. This is useful if the element contains what appears to be Angular directives and
|
|
||||||
* bindings but which should be ignored by Angular. This could be the case if you have a site that
|
|
||||||
* displays snippets of code, for instance.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* <div>Normal: {{1 + 2}}</div> // output "Normal: 3"
|
|
||||||
* <div ng-non-bindable>Ignored: {{1 + 2}}</div> // output "Ignored: {{1 + 2}}"
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
@Directive({selector: '[ng-non-bindable]', compileChildren: false})
|
|
||||||
export class NgNonBindable {
|
|
||||||
}
|
|
|
@ -6,6 +6,12 @@ import 'package:html/dom.dart';
|
||||||
import 'dom_adapter.dart';
|
import 'dom_adapter.dart';
|
||||||
import 'emulated_css.dart';
|
import 'emulated_css.dart';
|
||||||
|
|
||||||
|
const _attrToPropMap = const {
|
||||||
|
'innerHtml': 'innerHTML',
|
||||||
|
'readonly': 'readOnly',
|
||||||
|
'tabindex': 'tabIndex',
|
||||||
|
};
|
||||||
|
|
||||||
abstract class AbstractHtml5LibAdapter implements DomAdapter {
|
abstract class AbstractHtml5LibAdapter implements DomAdapter {
|
||||||
hasProperty(element, String name) {
|
hasProperty(element, String name) {
|
||||||
// This is needed for serverside compile to generate the right getters/setters.
|
// This is needed for serverside compile to generate the right getters/setters.
|
||||||
|
@ -23,12 +29,9 @@ abstract class AbstractHtml5LibAdapter implements DomAdapter {
|
||||||
throw 'not implemented';
|
throw 'not implemented';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final attrToPropMap = const {
|
get attrToPropMap => _attrToPropMap;
|
||||||
'innerHtml': 'innerHTML',
|
|
||||||
'readonly': 'readOnly',
|
|
||||||
'tabindex': 'tabIndex',
|
|
||||||
};
|
|
||||||
|
|
||||||
|
@override
|
||||||
set attrToPropMap(value) {
|
set attrToPropMap(value) {
|
||||||
throw 'readonly';
|
throw 'readonly';
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,6 +117,7 @@ export abstract class DomAdapter {
|
||||||
abstract cssToRules(css: string): any[];
|
abstract cssToRules(css: string): any[];
|
||||||
abstract supportsDOMEvents(): boolean;
|
abstract supportsDOMEvents(): boolean;
|
||||||
abstract supportsNativeShadowDOM(): boolean;
|
abstract supportsNativeShadowDOM(): boolean;
|
||||||
|
abstract supportsUnprefixedCssAnimation(): boolean;
|
||||||
abstract getGlobalEventTarget(target: string): any;
|
abstract getGlobalEventTarget(target: string): any;
|
||||||
abstract getHistory(): History;
|
abstract getHistory(): History;
|
||||||
abstract getLocation(): Location;
|
abstract getLocation(): Location;
|
||||||
|
|
|
@ -70,6 +70,10 @@ export abstract class GenericBrowserDomAdapter extends DomAdapter {
|
||||||
supportsNativeShadowDOM(): boolean {
|
supportsNativeShadowDOM(): boolean {
|
||||||
return isFunction((<any>this.defaultDoc().body).createShadowRoot);
|
return isFunction((<any>this.defaultDoc().body).createShadowRoot);
|
||||||
}
|
}
|
||||||
|
supportsUnprefixedCssAnimation(): boolean {
|
||||||
|
return isPresent(this.defaultDoc().body.style) &&
|
||||||
|
isPresent(this.defaultDoc().body.style.animationName);
|
||||||
|
}
|
||||||
getAnimationPrefix(): string {
|
getAnimationPrefix(): string {
|
||||||
return isPresent(this._animationPrefix) ? this._animationPrefix : "";
|
return isPresent(this._animationPrefix) ? this._animationPrefix : "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,452 +1,25 @@
|
||||||
library angular2.dom.htmlAdapter;
|
library angular2.dom.htmlAdapter;
|
||||||
|
|
||||||
|
import 'abstract_html_adapter.dart';
|
||||||
import 'dom_adapter.dart';
|
import 'dom_adapter.dart';
|
||||||
import 'package:html/parser.dart' as parser;
|
|
||||||
import 'package:html/dom.dart';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
class Html5LibDomAdapter implements DomAdapter {
|
class Html5LibDomAdapter extends AbstractHtml5LibAdapter {
|
||||||
static void makeCurrent() {
|
static void makeCurrent() {
|
||||||
setRootDomAdapter(new Html5LibDomAdapter());
|
setRootDomAdapter(new Html5LibDomAdapter());
|
||||||
}
|
}
|
||||||
|
|
||||||
hasProperty(element, String name) {
|
logError(errorMessage) {
|
||||||
// This is needed for serverside compile to generate the right getters/setters.
|
stderr.writeln('${errorMessage}');
|
||||||
// TODO: change this once we have property schema support.
|
|
||||||
// Attention: Keep this in sync with browser_adapter.dart!
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setProperty(Element element, String name, Object value) =>
|
log(message) {
|
||||||
throw 'not implemented';
|
stdout.writeln('${message}');
|
||||||
|
|
||||||
getProperty(Element element, String name) => throw 'not implemented';
|
|
||||||
|
|
||||||
invoke(Element element, String methodName, List args) =>
|
|
||||||
throw 'not implemented';
|
|
||||||
|
|
||||||
logError(error) {
|
|
||||||
stderr.writeln('${error}');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log(error) {
|
logGroup(message) {
|
||||||
stdout.writeln('${error}');
|
stdout.writeln('${message}');
|
||||||
}
|
|
||||||
|
|
||||||
logGroup(error) {
|
|
||||||
stdout.writeln('${error}');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logGroupEnd() {}
|
logGroupEnd() {}
|
||||||
|
|
||||||
@override
|
|
||||||
final attrToPropMap = const {
|
|
||||||
'innerHtml': 'innerHTML',
|
|
||||||
'readonly': 'readOnly',
|
|
||||||
'tabindex': 'tabIndex',
|
|
||||||
};
|
|
||||||
|
|
||||||
set attrToPropMap(value) {
|
|
||||||
throw 'readonly';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
getGlobalEventTarget(String target) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
getTitle() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
setTitle(String newTitle) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getEventKey(event) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void replaceChild(el, newNode, oldNode) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
dynamic getBoundingClientRect(el) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
Element parse(String templateHtml) => parser.parse(templateHtml).firstChild;
|
|
||||||
query(selector) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
querySelector(el, String selector) {
|
|
||||||
return el.querySelector(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
List querySelectorAll(el, String selector) {
|
|
||||||
return el.querySelectorAll(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
on(el, evt, listener) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
Function onAndCancel(el, evt, listener) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatchEvent(el, evt) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
createMouseEvent(eventType) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
createEvent(eventType) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
preventDefault(evt) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
isPrevented(evt) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
getInnerHTML(el) {
|
|
||||||
return el.innerHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
getOuterHTML(el) {
|
|
||||||
return el.outerHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
String nodeName(node) {
|
|
||||||
switch (node.nodeType) {
|
|
||||||
case Node.ELEMENT_NODE:
|
|
||||||
return (node as Element).localName;
|
|
||||||
case Node.TEXT_NODE:
|
|
||||||
return '#text';
|
|
||||||
default:
|
|
||||||
throw 'not implemented for type ${node.nodeType}. '
|
|
||||||
'See http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1950641247'
|
|
||||||
' for node types definitions.';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String nodeValue(node) => node.data;
|
|
||||||
String type(node) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
content(node) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstChild(el) => el is NodeList ? el.first : el.firstChild;
|
|
||||||
|
|
||||||
nextSibling(el) {
|
|
||||||
final parentNode = el.parentNode;
|
|
||||||
if (parentNode == null) return null;
|
|
||||||
final siblings = parentNode.nodes;
|
|
||||||
final index = siblings.indexOf(el);
|
|
||||||
if (index < siblings.length - 1) {
|
|
||||||
return siblings[index + 1];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
parentElement(el) {
|
|
||||||
return el.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
List childNodes(el) => el.nodes;
|
|
||||||
List childNodesAsList(el) => el.nodes;
|
|
||||||
clearNodes(el) {
|
|
||||||
el.nodes.forEach((e) => e.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
appendChild(el, node) => el.append(node.remove());
|
|
||||||
removeChild(el, node) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(el) => el.remove();
|
|
||||||
insertBefore(el, node) {
|
|
||||||
if (el.parent == null) throw '$el must have a parent';
|
|
||||||
el.parent.insertBefore(node, el);
|
|
||||||
}
|
|
||||||
|
|
||||||
insertAllBefore(el, nodes) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
insertAfter(el, node) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
setInnerHTML(el, value) {
|
|
||||||
el.innerHtml = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
getText(el) {
|
|
||||||
return el.text;
|
|
||||||
}
|
|
||||||
|
|
||||||
setText(el, String value) => el.text = value;
|
|
||||||
|
|
||||||
getValue(el) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue(el, String value) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
getChecked(el) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
setChecked(el, bool value) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
createComment(String text) => new Comment(text);
|
|
||||||
createTemplate(String html) => createElement('template')..innerHtml = html;
|
|
||||||
createElement(tagName, [doc]) {
|
|
||||||
return new Element.tag(tagName);
|
|
||||||
}
|
|
||||||
|
|
||||||
createTextNode(String text, [doc]) => new Text(text);
|
|
||||||
|
|
||||||
createScriptTag(String attrName, String attrValue, [doc]) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
createStyleElement(String css, [doc]) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
createShadowRoot(el) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
getShadowRoot(el) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
getHost(el) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
clone(node) => node.clone(true);
|
|
||||||
getElementsByClassName(element, String name) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
getElementsByTagName(element, String name) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
List classList(element) => element.classes.toList();
|
|
||||||
|
|
||||||
addClass(element, String classname) {
|
|
||||||
element.classes.add(classname);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeClass(element, String classname) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
hasClass(element, String classname) => element.classes.contains(classname);
|
|
||||||
|
|
||||||
setStyle(element, String stylename, String stylevalue) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
removeStyle(element, String stylename) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
getStyle(element, String stylename) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
String tagName(element) => element.localName;
|
|
||||||
|
|
||||||
attributeMap(element) {
|
|
||||||
// `attributes` keys can be {@link AttributeName}s.
|
|
||||||
var map = <String, String>{};
|
|
||||||
element.attributes.forEach((key, value) {
|
|
||||||
map['$key'] = value;
|
|
||||||
});
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasAttribute(element, String attribute) {
|
|
||||||
// `attributes` keys can be {@link AttributeName}s.
|
|
||||||
return element.attributes.keys.any((key) => '$key' == attribute);
|
|
||||||
}
|
|
||||||
|
|
||||||
getAttribute(element, String attribute) {
|
|
||||||
// `attributes` keys can be {@link AttributeName}s.
|
|
||||||
var key = element.attributes.keys.firstWhere((key) => '$key' == attribute,
|
|
||||||
orElse: () {});
|
|
||||||
return element.attributes[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
setAttribute(element, String name, String value) {
|
|
||||||
element.attributes[name] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeAttribute(element, String attribute) {
|
|
||||||
element.attributes.remove(attribute);
|
|
||||||
}
|
|
||||||
|
|
||||||
templateAwareRoot(el) => el;
|
|
||||||
|
|
||||||
createHtmlDocument() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultDoc() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool elementMatches(n, String selector) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isTemplateElement(Element el) {
|
|
||||||
return el != null && el.localName.toLowerCase() == 'template';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isTextNode(node) => node.nodeType == Node.TEXT_NODE;
|
|
||||||
bool isCommentNode(node) => node.nodeType == Node.COMMENT_NODE;
|
|
||||||
|
|
||||||
bool isElementNode(node) => node.nodeType == Node.ELEMENT_NODE;
|
|
||||||
|
|
||||||
bool hasShadowRoot(node) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isShadowRoot(node) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
importIntoDoc(node) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
adoptNode(node) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isPageRule(rule) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isStyleRule(rule) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isMediaRule(rule) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isKeyframesRule(rule) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
String getHref(element) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
void resolveAndSetHref(element, baseUrl, href) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
List cssToRules(String css) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
List getDistributedNodes(Node) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool supportsDOMEvents() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool supportsNativeShadowDOM() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getHistory() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
getLocation() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
getBaseHref() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
resetBaseElement() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
String getUserAgent() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
void setData(Element element, String name, String value) {
|
|
||||||
this.setAttribute(element, 'data-${name}', value);
|
|
||||||
}
|
|
||||||
|
|
||||||
getComputedStyle(element) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
String getData(Element element, String name) {
|
|
||||||
return this.getAttribute(element, 'data-${name}');
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(tbosch): move this into a separate environment class once we have it
|
|
||||||
setGlobalVar(String name, value) {
|
|
||||||
// noop on the server
|
|
||||||
}
|
|
||||||
|
|
||||||
requestAnimationFrame(callback) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
cancelAnimationFrame(id) {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
performanceNow() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
getAnimationPrefix() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
getTransitionEnd() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsAnimation() {
|
|
||||||
throw 'not implemented';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
var parse5 = require('parse5');
|
var parse5 = require('parse5/index');
|
||||||
var parser = new parse5.Parser(parse5.TreeAdapters.htmlparser2);
|
var parser = new parse5.Parser(parse5.TreeAdapters.htmlparser2);
|
||||||
var serializer = new parse5.Serializer(parse5.TreeAdapters.htmlparser2);
|
var serializer = new parse5.Serializer(parse5.TreeAdapters.htmlparser2);
|
||||||
var treeAdapter = parser.treeAdapter;
|
var treeAdapter = parser.treeAdapter;
|
||||||
|
|
||||||
var cssParse = require('css').parse;
|
var cssParse = require('css/lib/parse/index');
|
||||||
|
|
||||||
var url = require('url');
|
|
||||||
|
|
||||||
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
||||||
import {DomAdapter, setRootDomAdapter} from './dom_adapter';
|
import {DomAdapter, setRootDomAdapter} from './dom_adapter';
|
||||||
|
@ -487,7 +485,7 @@ export class Parse5DomAdapter extends DomAdapter {
|
||||||
if (href == null) {
|
if (href == null) {
|
||||||
el.href = baseUrl;
|
el.href = baseUrl;
|
||||||
} else {
|
} else {
|
||||||
el.href = url.resolve(baseUrl, href);
|
el.href = baseUrl + '/../' + href;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_buildRules(parsedRules, css?) {
|
_buildRules(parsedRules, css?) {
|
||||||
|
@ -546,6 +544,12 @@ export class Parse5DomAdapter extends DomAdapter {
|
||||||
return this.defaultDoc().body;
|
return this.defaultDoc().body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
supportsUnprefixedCssAnimation(): boolean {
|
||||||
|
// Currently during offline code transformation we do not know
|
||||||
|
// what browsers we are targetting. To play it safe, we assume
|
||||||
|
// unprefixed animations are not supported.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
getBaseHref(): string { throw 'not implemented'; }
|
getBaseHref(): string { throw 'not implemented'; }
|
||||||
resetBaseElement(): void { throw 'not implemented'; }
|
resetBaseElement(): void { throw 'not implemented'; }
|
||||||
getHistory(): History { throw 'not implemented'; }
|
getHistory(): History { throw 'not implemented'; }
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
library angular2.dom.webWorkerAdapter;
|
||||||
|
|
||||||
|
import 'abstract_html_adapter.dart';
|
||||||
|
import 'dom_adapter.dart';
|
||||||
|
|
||||||
|
class WebWorkerDomAdapter extends AbstractHtml5LibAdapter {
|
||||||
|
static void makeCurrent() {
|
||||||
|
setRootDomAdapter(new WebWorkerDomAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
|
logError(error) {
|
||||||
|
print('${error}');
|
||||||
|
}
|
||||||
|
|
||||||
|
log(error) {
|
||||||
|
print('${error}');
|
||||||
|
}
|
||||||
|
|
||||||
|
logGroup(error) {
|
||||||
|
print('${error}');
|
||||||
|
}
|
||||||
|
|
||||||
|
logGroupEnd() {}
|
||||||
|
}
|
|
@ -17,8 +17,7 @@ class Directive extends DirectiveMetadata {
|
||||||
const Directive({String selector, List<String> inputs,
|
const Directive({String selector, List<String> inputs,
|
||||||
List<String> outputs, Map<String, String> host,
|
List<String> outputs, Map<String, String> host,
|
||||||
List bindings, String exportAs, String moduleId,
|
List bindings, String exportAs, String moduleId,
|
||||||
Map<String, dynamic> queries,
|
Map<String, dynamic> queries})
|
||||||
bool compileChildren: true})
|
|
||||||
: super(
|
: super(
|
||||||
selector: selector,
|
selector: selector,
|
||||||
inputs: inputs,
|
inputs: inputs,
|
||||||
|
@ -27,8 +26,7 @@ class Directive extends DirectiveMetadata {
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
exportAs: exportAs,
|
exportAs: exportAs,
|
||||||
moduleId: moduleId,
|
moduleId: moduleId,
|
||||||
queries: queries,
|
queries: queries);
|
||||||
compileChildren: compileChildren);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,7 +37,7 @@ class Component extends ComponentMetadata {
|
||||||
List<String> outputs, Map<String, String> host,
|
List<String> outputs, Map<String, String> host,
|
||||||
List bindings, String exportAs, String moduleId,
|
List bindings, String exportAs, String moduleId,
|
||||||
Map<String, dynamic> queries,
|
Map<String, dynamic> queries,
|
||||||
bool compileChildren, List viewBindings, ChangeDetectionStrategy changeDetection})
|
List viewBindings, ChangeDetectionStrategy changeDetection})
|
||||||
: super(
|
: super(
|
||||||
selector: selector,
|
selector: selector,
|
||||||
inputs: inputs,
|
inputs: inputs,
|
||||||
|
@ -48,7 +46,6 @@ class Component extends ComponentMetadata {
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
exportAs: exportAs,
|
exportAs: exportAs,
|
||||||
moduleId: moduleId,
|
moduleId: moduleId,
|
||||||
compileChildren: compileChildren,
|
|
||||||
viewBindings: viewBindings,
|
viewBindings: viewBindings,
|
||||||
queries: queries,
|
queries: queries,
|
||||||
changeDetection: changeDetection);
|
changeDetection: changeDetection);
|
||||||
|
|
|
@ -153,7 +153,6 @@ export interface DirectiveFactory {
|
||||||
bindings?: any[],
|
bindings?: any[],
|
||||||
exportAs?: string,
|
exportAs?: string,
|
||||||
moduleId?: string,
|
moduleId?: string,
|
||||||
compileChildren?: boolean,
|
|
||||||
queries?: StringMap<string, any>
|
queries?: StringMap<string, any>
|
||||||
}): DirectiveDecorator;
|
}): DirectiveDecorator;
|
||||||
new (obj: {
|
new (obj: {
|
||||||
|
@ -164,7 +163,6 @@ export interface DirectiveFactory {
|
||||||
bindings?: any[],
|
bindings?: any[],
|
||||||
exportAs?: string,
|
exportAs?: string,
|
||||||
moduleId?: string,
|
moduleId?: string,
|
||||||
compileChildren?: boolean,
|
|
||||||
queries?: StringMap<string, any>
|
queries?: StringMap<string, any>
|
||||||
}): DirectiveMetadata;
|
}): DirectiveMetadata;
|
||||||
}
|
}
|
||||||
|
@ -221,7 +219,6 @@ export interface ComponentFactory {
|
||||||
bindings?: any[],
|
bindings?: any[],
|
||||||
exportAs?: string,
|
exportAs?: string,
|
||||||
moduleId?: string,
|
moduleId?: string,
|
||||||
compileChildren?: boolean,
|
|
||||||
queries?: StringMap<string, any>,
|
queries?: StringMap<string, any>,
|
||||||
viewBindings?: any[],
|
viewBindings?: any[],
|
||||||
changeDetection?: ChangeDetectionStrategy,
|
changeDetection?: ChangeDetectionStrategy,
|
||||||
|
@ -234,7 +231,6 @@ export interface ComponentFactory {
|
||||||
bindings?: any[],
|
bindings?: any[],
|
||||||
exportAs?: string,
|
exportAs?: string,
|
||||||
moduleId?: string,
|
moduleId?: string,
|
||||||
compileChildren?: boolean,
|
|
||||||
queries?: StringMap<string, any>,
|
queries?: StringMap<string, any>,
|
||||||
viewBindings?: any[],
|
viewBindings?: any[],
|
||||||
changeDetection?: ChangeDetectionStrategy,
|
changeDetection?: ChangeDetectionStrategy,
|
||||||
|
|
|
@ -622,12 +622,6 @@ export class DirectiveMetadata extends InjectableMetadata {
|
||||||
*/
|
*/
|
||||||
host: StringMap<string, string>;
|
host: StringMap<string, string>;
|
||||||
|
|
||||||
/**
|
|
||||||
* If set to false the compiler does not compile the children of this directive.
|
|
||||||
*/
|
|
||||||
// TODO(vsavkin): This would better fall under the Macro directive concept.
|
|
||||||
compileChildren: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the set of injectable objects that are visible to a Directive and its light DOM
|
* Defines the set of injectable objects that are visible to a Directive and its light DOM
|
||||||
* children.
|
* children.
|
||||||
|
@ -744,10 +738,7 @@ export class DirectiveMetadata extends InjectableMetadata {
|
||||||
*/
|
*/
|
||||||
queries: StringMap<string, any>;
|
queries: StringMap<string, any>;
|
||||||
|
|
||||||
constructor({
|
constructor({selector, inputs, outputs, host, bindings, exportAs, moduleId, queries}: {
|
||||||
selector, inputs, outputs, host, bindings, exportAs, moduleId, queries,
|
|
||||||
compileChildren = true,
|
|
||||||
}: {
|
|
||||||
selector?: string,
|
selector?: string,
|
||||||
inputs?: string[],
|
inputs?: string[],
|
||||||
outputs?: string[],
|
outputs?: string[],
|
||||||
|
@ -755,8 +746,7 @@ export class DirectiveMetadata extends InjectableMetadata {
|
||||||
bindings?: any[],
|
bindings?: any[],
|
||||||
exportAs?: string,
|
exportAs?: string,
|
||||||
moduleId?: string,
|
moduleId?: string,
|
||||||
queries?: StringMap<string, any>,
|
queries?: StringMap<string, any>
|
||||||
compileChildren?: boolean,
|
|
||||||
} = {}) {
|
} = {}) {
|
||||||
super();
|
super();
|
||||||
this.selector = selector;
|
this.selector = selector;
|
||||||
|
@ -766,7 +756,6 @@ export class DirectiveMetadata extends InjectableMetadata {
|
||||||
this.exportAs = exportAs;
|
this.exportAs = exportAs;
|
||||||
this.moduleId = moduleId;
|
this.moduleId = moduleId;
|
||||||
this.queries = queries;
|
this.queries = queries;
|
||||||
this.compileChildren = compileChildren;
|
|
||||||
this.bindings = bindings;
|
this.bindings = bindings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -868,8 +857,7 @@ export class ComponentMetadata extends DirectiveMetadata {
|
||||||
viewBindings: any[];
|
viewBindings: any[];
|
||||||
|
|
||||||
constructor({selector, inputs, outputs, host, exportAs, moduleId, bindings, viewBindings,
|
constructor({selector, inputs, outputs, host, exportAs, moduleId, bindings, viewBindings,
|
||||||
changeDetection = ChangeDetectionStrategy.Default, queries, compileChildren = true}:
|
changeDetection = ChangeDetectionStrategy.Default, queries}: {
|
||||||
{
|
|
||||||
selector?: string,
|
selector?: string,
|
||||||
inputs?: string[],
|
inputs?: string[],
|
||||||
outputs?: string[],
|
outputs?: string[],
|
||||||
|
@ -877,7 +865,6 @@ export class ComponentMetadata extends DirectiveMetadata {
|
||||||
bindings?: any[],
|
bindings?: any[],
|
||||||
exportAs?: string,
|
exportAs?: string,
|
||||||
moduleId?: string,
|
moduleId?: string,
|
||||||
compileChildren?: boolean,
|
|
||||||
viewBindings?: any[],
|
viewBindings?: any[],
|
||||||
queries?: StringMap<string, any>,
|
queries?: StringMap<string, any>,
|
||||||
changeDetection?: ChangeDetectionStrategy,
|
changeDetection?: ChangeDetectionStrategy,
|
||||||
|
@ -890,8 +877,7 @@ export class ComponentMetadata extends DirectiveMetadata {
|
||||||
exportAs: exportAs,
|
exportAs: exportAs,
|
||||||
moduleId: moduleId,
|
moduleId: moduleId,
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
queries: queries,
|
queries: queries
|
||||||
compileChildren: compileChildren
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.changeDetection = changeDetection;
|
this.changeDetection = changeDetection;
|
||||||
|
|
|
@ -13,12 +13,19 @@ import {PipeBinding} from './pipe_binding';
|
||||||
import * as cd from 'angular2/src/core/change_detection/pipes';
|
import * as cd from 'angular2/src/core/change_detection/pipes';
|
||||||
|
|
||||||
export class ProtoPipes {
|
export class ProtoPipes {
|
||||||
|
static fromBindings(bindings: PipeBinding[]): ProtoPipes {
|
||||||
|
var config = {};
|
||||||
|
bindings.forEach(b => config[b.name] = b);
|
||||||
|
return new ProtoPipes(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
/**
|
/**
|
||||||
* Map of {@link PipeMetadata} names to {@link PipeMetadata} implementations.
|
* Map of {@link PipeMetadata} names to {@link PipeMetadata} implementations.
|
||||||
*/
|
*/
|
||||||
config: StringMap<string, PipeBinding> = {};
|
public config: StringMap<string, PipeBinding>) {
|
||||||
|
this.config = config;
|
||||||
constructor(bindings: PipeBinding[]) { bindings.forEach(b => this.config[b.name] = b); }
|
}
|
||||||
|
|
||||||
get(name: string): PipeBinding {
|
get(name: string): PipeBinding {
|
||||||
var binding = this.config[name];
|
var binding = this.config[name];
|
||||||
|
|
|
@ -11,8 +11,5 @@ export interface PlatformReflectionCapabilities {
|
||||||
getter(name: string): GetterFn;
|
getter(name: string): GetterFn;
|
||||||
setter(name: string): SetterFn;
|
setter(name: string): SetterFn;
|
||||||
method(name: string): MethodFn;
|
method(name: string): MethodFn;
|
||||||
// TODO(tbosch): remove this method after the new compiler is done
|
|
||||||
// (and ComponentUrlMapper as well).
|
|
||||||
importUri(type: Type): string;
|
importUri(type: Type): string;
|
||||||
moduleId(type: Type): string;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -322,11 +322,4 @@ class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||||
String importUri(Type type) {
|
String importUri(Type type) {
|
||||||
return '${(reflectClass(type).owner as LibraryMirror).uri}';
|
return '${(reflectClass(type).owner as LibraryMirror).uri}';
|
||||||
}
|
}
|
||||||
|
|
||||||
String moduleId(Type type) {
|
|
||||||
var rootUri = currentMirrorSystem().isolate.rootLibrary.uri;
|
|
||||||
var moduleUri = (reflectClass(type).owner as LibraryMirror).uri;
|
|
||||||
var relativeUri = new Uri(pathSegments:moduleUri.pathSegments.sublist(rootUri.pathSegments.length-1)).toString();
|
|
||||||
return relativeUri.substring(0, relativeUri.lastIndexOf('.'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,6 +168,4 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||||
|
|
||||||
// There is not a concept of import uri in Js, but this is useful in developing Dart applications.
|
// There is not a concept of import uri in Js, but this is useful in developing Dart applications.
|
||||||
importUri(type: Type): string { return './'; }
|
importUri(type: Type): string { return './'; }
|
||||||
|
|
||||||
moduleId(type: Type): string { return './'; }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,8 +152,6 @@ export class Reflector {
|
||||||
_containsReflectionInfo(typeOrFunc) { return this._injectableInfo.has(typeOrFunc); }
|
_containsReflectionInfo(typeOrFunc) { return this._injectableInfo.has(typeOrFunc); }
|
||||||
|
|
||||||
importUri(type: Type): string { return this.reflectionCapabilities.importUri(type); }
|
importUri(type: Type): string { return this.reflectionCapabilities.importUri(type); }
|
||||||
|
|
||||||
moduleId(type: Type): string { return this.reflectionCapabilities.moduleId(type); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _mergeMaps(target: Map<any, any>, config: StringMap<string, Function>): void {
|
function _mergeMaps(target: Map<any, any>, config: StringMap<string, Function>): void {
|
||||||
|
|
|
@ -11,5 +11,13 @@ export {
|
||||||
ViewDefinition,
|
ViewDefinition,
|
||||||
DOCUMENT,
|
DOCUMENT,
|
||||||
APP_ID,
|
APP_ID,
|
||||||
MAX_IN_MEMORY_ELEMENTS_PER_TEMPLATE
|
MAX_IN_MEMORY_ELEMENTS_PER_TEMPLATE,
|
||||||
|
RenderTemplateCmd,
|
||||||
|
RenderCommandVisitor,
|
||||||
|
RenderTextCmd,
|
||||||
|
RenderNgContentCmd,
|
||||||
|
RenderBeginElementCmd,
|
||||||
|
RenderBeginComponentCmd,
|
||||||
|
RenderEmbeddedTemplateCmd,
|
||||||
|
RenderBeginCmd
|
||||||
} from './render/render';
|
} from './render/render';
|
||||||
|
|
|
@ -453,6 +453,16 @@ export interface RenderElementRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Renderer {
|
export class Renderer {
|
||||||
|
/**
|
||||||
|
* Registers the template of a component
|
||||||
|
*/
|
||||||
|
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[]) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new RenderProtoViewRef gfrom RenderTemplateCmds.
|
||||||
|
*/
|
||||||
|
createProtoView(cmds: RenderTemplateCmd[]): RenderProtoViewRef { return null; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a root host view that includes the given element.
|
* Creates a root host view that includes the given element.
|
||||||
* Note that the fragmentCount needs to be passed in so that we can create a result
|
* Note that the fragmentCount needs to be passed in so that we can create a result
|
||||||
|
|
|
@ -1,22 +1,19 @@
|
||||||
import {Inject, Injectable, OpaqueToken} from 'angular2/src/core/di';
|
import {Inject, Injectable, OpaqueToken} from 'angular2/src/core/di';
|
||||||
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
||||||
import {isPresent, isBlank, RegExpWrapper, CONST_EXPR} from 'angular2/src/core/facade/lang';
|
import {
|
||||||
|
isPresent,
|
||||||
|
isBlank,
|
||||||
|
RegExpWrapper,
|
||||||
|
CONST_EXPR,
|
||||||
|
stringify
|
||||||
|
} from 'angular2/src/core/facade/lang';
|
||||||
import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions';
|
import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions';
|
||||||
|
|
||||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
|
|
||||||
import {EventManager} from './events/event_manager';
|
import {EventManager} from './events/event_manager';
|
||||||
|
|
||||||
import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './view/proto_view';
|
|
||||||
import {DomView, DomViewRef, resolveInternalDomView} from './view/view';
|
|
||||||
import {DomFragmentRef, resolveInternalDomFragment} from './view/fragment';
|
|
||||||
import {DomSharedStylesHost} from './view/shared_styles_host';
|
import {DomSharedStylesHost} from './view/shared_styles_host';
|
||||||
import {
|
|
||||||
NG_BINDING_CLASS_SELECTOR,
|
|
||||||
NG_BINDING_CLASS,
|
|
||||||
cloneAndQueryProtoView,
|
|
||||||
camelCaseToDashCase
|
|
||||||
} from './util';
|
|
||||||
import {WtfScopeFn, wtfLeave, wtfCreateScope} from '../../profile/profile';
|
import {WtfScopeFn, wtfLeave, wtfCreateScope} from '../../profile/profile';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -25,65 +22,80 @@ import {
|
||||||
RenderViewRef,
|
RenderViewRef,
|
||||||
RenderElementRef,
|
RenderElementRef,
|
||||||
RenderFragmentRef,
|
RenderFragmentRef,
|
||||||
RenderViewWithFragments
|
RenderViewWithFragments,
|
||||||
|
RenderTemplateCmd,
|
||||||
|
RenderEventDispatcher
|
||||||
} from '../api';
|
} from '../api';
|
||||||
|
|
||||||
import {TemplateCloner} from './template_cloner';
|
|
||||||
|
|
||||||
import {DOCUMENT} from './dom_tokens';
|
import {DOCUMENT} from './dom_tokens';
|
||||||
|
import {createRenderView, NodeFactory} from '../view_factory';
|
||||||
const REFLECT_PREFIX: string = 'ng-reflect-';
|
import {DefaultRenderView, DefaultRenderFragmentRef, DefaultProtoViewRef} from '../view';
|
||||||
|
import {camelCaseToDashCase} from './util';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DomRenderer extends Renderer {
|
export class DomRenderer implements Renderer, NodeFactory<Node> {
|
||||||
_document;
|
private _componentCmds: Map<number, RenderTemplateCmd[]> = new Map<number, RenderTemplateCmd[]>();
|
||||||
|
private _document;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
constructor(private _eventManager: EventManager,
|
constructor(private _eventManager: EventManager,
|
||||||
private _domSharedStylesHost: DomSharedStylesHost, private _animate: AnimationBuilder,
|
private _domSharedStylesHost: DomSharedStylesHost, private _animate: AnimationBuilder,
|
||||||
private _templateCloner: TemplateCloner, @Inject(DOCUMENT) document) {
|
@Inject(DOCUMENT) document) {
|
||||||
super();
|
|
||||||
this._document = document;
|
this._document = document;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[]) {
|
||||||
|
this._componentCmds.set(templateId, commands);
|
||||||
|
this._domSharedStylesHost.addStyles(styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveComponentTemplate(templateId: number): RenderTemplateCmd[] {
|
||||||
|
return this._componentCmds.get(templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
createProtoView(cmds: RenderTemplateCmd[]): RenderProtoViewRef {
|
||||||
|
return new DefaultProtoViewRef(cmds);
|
||||||
|
}
|
||||||
|
|
||||||
_createRootHostViewScope: WtfScopeFn = wtfCreateScope('DomRenderer#createRootHostView()');
|
_createRootHostViewScope: WtfScopeFn = wtfCreateScope('DomRenderer#createRootHostView()');
|
||||||
createRootHostView(hostProtoViewRef: RenderProtoViewRef, fragmentCount: number,
|
createRootHostView(hostProtoViewRef: RenderProtoViewRef, fragmentCount: number,
|
||||||
hostElementSelector: string): RenderViewWithFragments {
|
hostElementSelector: string): RenderViewWithFragments {
|
||||||
var s = this._createRootHostViewScope();
|
var s = this._createRootHostViewScope();
|
||||||
var hostProtoView = resolveInternalDomProtoView(hostProtoViewRef);
|
|
||||||
var element = DOM.querySelector(this._document, hostElementSelector);
|
var element = DOM.querySelector(this._document, hostElementSelector);
|
||||||
if (isBlank(element)) {
|
if (isBlank(element)) {
|
||||||
wtfLeave(s);
|
wtfLeave(s);
|
||||||
throw new BaseException(`The selector "${hostElementSelector}" did not match any elements`);
|
throw new BaseException(`The selector "${hostElementSelector}" did not match any elements`);
|
||||||
}
|
}
|
||||||
return wtfLeave(s, this._createView(hostProtoView, element));
|
return wtfLeave(s, this._createView(hostProtoViewRef, element));
|
||||||
}
|
}
|
||||||
|
|
||||||
_createViewScope = wtfCreateScope('DomRenderer#createView()');
|
_createViewScope = wtfCreateScope('DomRenderer#createView()');
|
||||||
createView(protoViewRef: RenderProtoViewRef, fragmentCount: number): RenderViewWithFragments {
|
createView(protoViewRef: RenderProtoViewRef, fragmentCount: number): RenderViewWithFragments {
|
||||||
var s = this._createViewScope();
|
var s = this._createViewScope();
|
||||||
var protoView = resolveInternalDomProtoView(protoViewRef);
|
return wtfLeave(s, this._createView(protoViewRef, null));
|
||||||
return wtfLeave(s, this._createView(protoView, null));
|
}
|
||||||
|
|
||||||
|
private _createView(protoViewRef: RenderProtoViewRef,
|
||||||
|
inplaceElement: HTMLElement): RenderViewWithFragments {
|
||||||
|
var view = createRenderView((<DefaultProtoViewRef>protoViewRef).cmds, inplaceElement, this);
|
||||||
|
var sdRoots = view.nativeShadowRoots;
|
||||||
|
for (var i = 0; i < sdRoots.length; i++) {
|
||||||
|
this._domSharedStylesHost.addHost(sdRoots[i]);
|
||||||
|
}
|
||||||
|
return new RenderViewWithFragments(view, view.fragments);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyView(viewRef: RenderViewRef) {
|
destroyView(viewRef: RenderViewRef) {
|
||||||
var view = resolveInternalDomView(viewRef);
|
var view = <DefaultRenderView<Node>>viewRef;
|
||||||
var elementBinders = view.proto.elementBinders;
|
var sdRoots = view.nativeShadowRoots;
|
||||||
for (var i = 0; i < elementBinders.length; i++) {
|
for (var i = 0; i < sdRoots.length; i++) {
|
||||||
var binder = elementBinders[i];
|
this._domSharedStylesHost.removeHost(sdRoots[i]);
|
||||||
if (binder.hasNativeShadowRoot) {
|
|
||||||
this._domSharedStylesHost.removeHost(DOM.getShadowRoot(view.boundElements[i]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getNativeElementSync(location: RenderElementRef): any {
|
getNativeElementSync(location: RenderElementRef): any {
|
||||||
if (isBlank(location.renderBoundElementIndex)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return resolveInternalDomView(location.renderView)
|
return resolveInternalDomView(location.renderView)
|
||||||
.boundElements[location.renderBoundElementIndex];
|
.boundElements[location.renderBoundElementIndex];
|
||||||
}
|
}
|
||||||
|
@ -144,9 +156,6 @@ export class DomRenderer extends Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
attachFragmentAfterElement(elementRef: RenderElementRef, fragmentRef: RenderFragmentRef) {
|
attachFragmentAfterElement(elementRef: RenderElementRef, fragmentRef: RenderFragmentRef) {
|
||||||
if (isBlank(elementRef.renderBoundElementIndex)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var parentView = resolveInternalDomView(elementRef.renderView);
|
var parentView = resolveInternalDomView(elementRef.renderView);
|
||||||
var element = parentView.boundElements[elementRef.renderBoundElementIndex];
|
var element = parentView.boundElements[elementRef.renderBoundElementIndex];
|
||||||
var nodes = resolveInternalDomFragment(fragmentRef);
|
var nodes = resolveInternalDomFragment(fragmentRef);
|
||||||
|
@ -164,153 +173,100 @@ export class DomRenderer extends Renderer {
|
||||||
wtfLeave(s);
|
wtfLeave(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
hydrateView(viewRef: RenderViewRef) {
|
hydrateView(viewRef: RenderViewRef) { resolveInternalDomView(viewRef).hydrate(); }
|
||||||
var view = resolveInternalDomView(viewRef);
|
|
||||||
if (view.hydrated) throw new BaseException('The view is already hydrated.');
|
|
||||||
view.hydrated = true;
|
|
||||||
|
|
||||||
// add global events
|
dehydrateView(viewRef: RenderViewRef) { resolveInternalDomView(viewRef).dehydrate(); }
|
||||||
view.eventHandlerRemovers = [];
|
|
||||||
var binders = view.proto.elementBinders;
|
|
||||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
|
||||||
var binder = binders[binderIdx];
|
|
||||||
if (isPresent(binder.globalEvents)) {
|
|
||||||
for (var i = 0; i < binder.globalEvents.length; i++) {
|
|
||||||
var globalEvent = binder.globalEvents[i];
|
|
||||||
var remover = this._createGlobalEventListener(view, binderIdx, globalEvent.name,
|
|
||||||
globalEvent.target, globalEvent.fullName);
|
|
||||||
view.eventHandlerRemovers.push(remover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dehydrateView(viewRef: RenderViewRef) {
|
createTemplateAnchor(attrNameAndValues: string[]): Node {
|
||||||
var view = resolveInternalDomView(viewRef);
|
return this.createElement('script', attrNameAndValues);
|
||||||
|
|
||||||
// remove global events
|
|
||||||
for (var i = 0; i < view.eventHandlerRemovers.length; i++) {
|
|
||||||
view.eventHandlerRemovers[i]();
|
|
||||||
}
|
}
|
||||||
|
createElement(name: string, attrNameAndValues: string[]): Node {
|
||||||
view.eventHandlerRemovers = null;
|
var el = DOM.createElement(name);
|
||||||
view.hydrated = false;
|
this._setAttributes(el, attrNameAndValues);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
mergeElement(existing: Node, attrNameAndValues: string[]) {
|
||||||
|
DOM.clearNodes(existing);
|
||||||
|
this._setAttributes(existing, attrNameAndValues);
|
||||||
|
}
|
||||||
|
private _setAttributes(node: Node, attrNameAndValues: string[]) {
|
||||||
|
for (var attrIdx = 0; attrIdx < attrNameAndValues.length; attrIdx += 2) {
|
||||||
|
DOM.setAttribute(node, attrNameAndValues[attrIdx], attrNameAndValues[attrIdx + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createShadowRoot(host: Node): Node { return DOM.createShadowRoot(host); }
|
||||||
|
createText(value: string): Node { return DOM.createTextNode(isPresent(value) ? value : ''); }
|
||||||
|
appendChild(parent: Node, child: Node) { DOM.appendChild(parent, child); }
|
||||||
|
on(element: Node, eventName: string, callback: Function) {
|
||||||
|
this._eventManager.addEventListener(<HTMLElement>element, eventName,
|
||||||
|
decoratePreventDefault(callback));
|
||||||
|
}
|
||||||
|
globalOn(target: string, eventName: string, callback: Function): Function {
|
||||||
|
return this._eventManager.addGlobalEventListener(target, eventName,
|
||||||
|
decoratePreventDefault(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
setElementProperty(location: RenderElementRef, propertyName: string, propertyValue: any): void {
|
setElementProperty(location: RenderElementRef, propertyName: string, propertyValue: any): void {
|
||||||
if (isBlank(location.renderBoundElementIndex)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var view = resolveInternalDomView(location.renderView);
|
var view = resolveInternalDomView(location.renderView);
|
||||||
view.setElementProperty(location.renderBoundElementIndex, propertyName, propertyValue);
|
DOM.setProperty(<Element>view.boundElements[location.renderBoundElementIndex], propertyName,
|
||||||
|
propertyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
setElementAttribute(location: RenderElementRef, attributeName: string, attributeValue: string):
|
setElementAttribute(location: RenderElementRef, attributeName: string, attributeValue: string):
|
||||||
void {
|
void {
|
||||||
if (isBlank(location.renderBoundElementIndex)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var view = resolveInternalDomView(location.renderView);
|
var view = resolveInternalDomView(location.renderView);
|
||||||
view.setElementAttribute(location.renderBoundElementIndex, attributeName, attributeValue);
|
var element = view.boundElements[location.renderBoundElementIndex];
|
||||||
|
var dashCasedAttributeName = camelCaseToDashCase(attributeName);
|
||||||
|
if (isPresent(attributeValue)) {
|
||||||
|
DOM.setAttribute(element, dashCasedAttributeName, stringify(attributeValue));
|
||||||
|
} else {
|
||||||
|
DOM.removeAttribute(element, dashCasedAttributeName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setElementClass(location: RenderElementRef, className: string, isAdd: boolean): void {
|
setElementClass(location: RenderElementRef, className: string, isAdd: boolean): void {
|
||||||
if (isBlank(location.renderBoundElementIndex)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var view = resolveInternalDomView(location.renderView);
|
var view = resolveInternalDomView(location.renderView);
|
||||||
view.setElementClass(location.renderBoundElementIndex, className, isAdd);
|
var element = view.boundElements[location.renderBoundElementIndex];
|
||||||
|
if (isAdd) {
|
||||||
|
DOM.addClass(element, className);
|
||||||
|
} else {
|
||||||
|
DOM.removeClass(element, className);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setElementStyle(location: RenderElementRef, styleName: string, styleValue: string): void {
|
setElementStyle(location: RenderElementRef, styleName: string, styleValue: string): void {
|
||||||
if (isBlank(location.renderBoundElementIndex)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var view = resolveInternalDomView(location.renderView);
|
var view = resolveInternalDomView(location.renderView);
|
||||||
view.setElementStyle(location.renderBoundElementIndex, styleName, styleValue);
|
var element = view.boundElements[location.renderBoundElementIndex];
|
||||||
|
var dashCasedStyleName = camelCaseToDashCase(styleName);
|
||||||
|
if (isPresent(styleValue)) {
|
||||||
|
DOM.setStyle(element, dashCasedStyleName, stringify(styleValue));
|
||||||
|
} else {
|
||||||
|
DOM.removeStyle(element, dashCasedStyleName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeElementMethod(location: RenderElementRef, methodName: string, args: any[]): void {
|
invokeElementMethod(location: RenderElementRef, methodName: string, args: any[]): void {
|
||||||
if (isBlank(location.renderBoundElementIndex)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var view = resolveInternalDomView(location.renderView);
|
var view = resolveInternalDomView(location.renderView);
|
||||||
view.invokeElementMethod(location.renderBoundElementIndex, methodName, args);
|
var element = <Element>view.boundElements[location.renderBoundElementIndex];
|
||||||
|
DOM.invoke(element, methodName, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
setText(viewRef: RenderViewRef, textNodeIndex: number, text: string): void {
|
setText(viewRef: RenderViewRef, textNodeIndex: number, text: string): void {
|
||||||
if (isBlank(textNodeIndex)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var view = resolveInternalDomView(viewRef);
|
var view = resolveInternalDomView(viewRef);
|
||||||
DOM.setText(view.boundTextNodes[textNodeIndex], text);
|
DOM.setText(view.boundTextNodes[textNodeIndex], text);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setEventDispatcherScope = wtfCreateScope('DomRenderer#setEventDispatcher()');
|
setEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher): void {
|
||||||
setEventDispatcher(viewRef: RenderViewRef, dispatcher: any /*api.EventDispatcher*/): void {
|
resolveInternalDomView(viewRef).setEventDispatcher(dispatcher);
|
||||||
var s = this._setEventDispatcherScope();
|
|
||||||
var view = resolveInternalDomView(viewRef);
|
|
||||||
view.eventDispatcher = dispatcher;
|
|
||||||
wtfLeave(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
_createView(protoView: DomProtoView, inplaceElement: HTMLElement): RenderViewWithFragments {
|
|
||||||
var clonedProtoView = cloneAndQueryProtoView(this._templateCloner, protoView, true);
|
|
||||||
|
|
||||||
var boundElements = clonedProtoView.boundElements;
|
|
||||||
|
|
||||||
// adopt inplaceElement
|
|
||||||
if (isPresent(inplaceElement)) {
|
|
||||||
if (protoView.fragmentsRootNodeCount[0] !== 1) {
|
|
||||||
throw new BaseException('Root proto views can only contain one element!');
|
|
||||||
}
|
|
||||||
DOM.clearNodes(inplaceElement);
|
|
||||||
var tempRoot = clonedProtoView.fragments[0][0];
|
|
||||||
moveChildNodes(tempRoot, inplaceElement);
|
|
||||||
if (boundElements.length > 0 && boundElements[0] === tempRoot) {
|
|
||||||
boundElements[0] = inplaceElement;
|
|
||||||
}
|
|
||||||
clonedProtoView.fragments[0][0] = inplaceElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
var view = new DomView(protoView, clonedProtoView.boundTextNodes, boundElements);
|
|
||||||
|
|
||||||
var binders = protoView.elementBinders;
|
|
||||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
|
||||||
var binder = binders[binderIdx];
|
|
||||||
var element = boundElements[binderIdx];
|
|
||||||
|
|
||||||
// native shadow DOM
|
|
||||||
if (binder.hasNativeShadowRoot) {
|
|
||||||
var shadowRootWrapper = DOM.firstChild(element);
|
|
||||||
var shadowRoot = DOM.createShadowRoot(element);
|
|
||||||
this._domSharedStylesHost.addHost(shadowRoot);
|
|
||||||
moveChildNodes(shadowRootWrapper, shadowRoot);
|
|
||||||
DOM.remove(shadowRootWrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
// events
|
|
||||||
if (isPresent(binder.eventLocals) && isPresent(binder.localEvents)) {
|
|
||||||
for (var i = 0; i < binder.localEvents.length; i++) {
|
|
||||||
this._createEventListener(view, element, binderIdx, binder.localEvents[i].name,
|
|
||||||
binder.eventLocals);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RenderViewWithFragments(
|
function resolveInternalDomView(viewRef: RenderViewRef): DefaultRenderView<Node> {
|
||||||
new DomViewRef(view), clonedProtoView.fragments.map(nodes => new DomFragmentRef(nodes)));
|
return <DefaultRenderView<Node>>viewRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
_createEventListener(view, element, elementIndex, eventName, eventLocals) {
|
function resolveInternalDomFragment(fragmentRef: RenderFragmentRef): Node[] {
|
||||||
this._eventManager.addEventListener(
|
return (<DefaultRenderFragmentRef<Node>>fragmentRef).nodes;
|
||||||
element, eventName, (event) => { view.dispatchEvent(elementIndex, eventName, event); });
|
|
||||||
}
|
|
||||||
|
|
||||||
_createGlobalEventListener(view, elementIndex, eventName, eventTarget, fullName): Function {
|
|
||||||
return this._eventManager.addGlobalEventListener(
|
|
||||||
eventTarget, eventName, (event) => { view.dispatchEvent(elementIndex, fullName, event); });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveNodesAfterSibling(sibling, nodes) {
|
function moveNodesAfterSibling(sibling, nodes) {
|
||||||
|
@ -318,7 +274,7 @@ function moveNodesAfterSibling(sibling, nodes) {
|
||||||
for (var i = 0; i < nodes.length; i++) {
|
for (var i = 0; i < nodes.length; i++) {
|
||||||
DOM.insertBefore(sibling, nodes[i]);
|
DOM.insertBefore(sibling, nodes[i]);
|
||||||
}
|
}
|
||||||
DOM.insertBefore(nodes[nodes.length - 1], sibling);
|
DOM.insertBefore(nodes[0], sibling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,3 +286,13 @@ function moveChildNodes(source: Node, target: Node) {
|
||||||
currChild = nextChild;
|
currChild = nextChild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function decoratePreventDefault(eventHandler: Function): Function {
|
||||||
|
return (event) => {
|
||||||
|
var allowDefaultBehavior = eventHandler(event);
|
||||||
|
if (!allowDefaultBehavior) {
|
||||||
|
// TODO(tbosch): move preventDefault into event plugins...
|
||||||
|
DOM.preventDefault(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
|
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
|
||||||
import {StringMapWrapper} from 'angular2/src/core/facade/collection';
|
import {StringMapWrapper} from 'angular2/src/core/facade/collection';
|
||||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
|
|
||||||
import {ElementSchemaRegistry} from './element_schema_registry';
|
import {ElementSchemaRegistry} from './element_schema_registry';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
export class DomElementSchemaRegistry extends ElementSchemaRegistry {
|
export class DomElementSchemaRegistry extends ElementSchemaRegistry {
|
||||||
private _protoElements = new Map<string, Element>();
|
private _protoElements = new Map<string, Element>();
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,13 @@ import 'package:angular2/src/core/di.dart' show Injectable;
|
||||||
class UrlResolver {
|
class UrlResolver {
|
||||||
/// This will be the location where 'package:' Urls will resolve. Default is
|
/// This will be the location where 'package:' Urls will resolve. Default is
|
||||||
/// '/packages'
|
/// '/packages'
|
||||||
final String packagePrefix;
|
final String _packagePrefix;
|
||||||
|
|
||||||
const UrlResolver() : packagePrefix = '/packages';
|
const UrlResolver() : _packagePrefix = '/packages';
|
||||||
|
|
||||||
/// Creates a UrlResolver that will resolve 'package:' Urls to a different
|
/// Creates a UrlResolver that will resolve 'package:' Urls to a different
|
||||||
/// prefixed location.
|
/// prefixed location.
|
||||||
const UrlResolver.withUrlPrefix(this.packagePrefix);
|
const UrlResolver.withUrlPrefix(this._packagePrefix);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the `url` given the `baseUrl`:
|
* Resolves the `url` given the `baseUrl`:
|
||||||
|
@ -30,7 +30,7 @@ class UrlResolver {
|
||||||
Uri uri = Uri.parse(url);
|
Uri uri = Uri.parse(url);
|
||||||
|
|
||||||
if (uri.scheme == 'package') {
|
if (uri.scheme == 'package') {
|
||||||
return '$packagePrefix/${uri.path}';
|
return '$_packagePrefix/${uri.path}';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri.isAbsolute) return uri.toString();
|
if (uri.isAbsolute) return uri.toString();
|
||||||
|
|
|
@ -32,7 +32,6 @@ export class MockDirectiveResolver extends DirectiveResolver {
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
exportAs: dm.exportAs,
|
exportAs: dm.exportAs,
|
||||||
moduleId: dm.moduleId,
|
moduleId: dm.moduleId,
|
||||||
compileChildren: dm.compileChildren,
|
|
||||||
queries: dm.queries,
|
queries: dm.queries,
|
||||||
changeDetection: dm.changeDetection,
|
changeDetection: dm.changeDetection,
|
||||||
viewBindings: viewBindings
|
viewBindings: viewBindings
|
||||||
|
@ -47,7 +46,6 @@ export class MockDirectiveResolver extends DirectiveResolver {
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
exportAs: dm.exportAs,
|
exportAs: dm.exportAs,
|
||||||
moduleId: dm.moduleId,
|
moduleId: dm.moduleId,
|
||||||
compileChildren: dm.compileChildren,
|
|
||||||
queries: dm.queries
|
queries: dm.queries
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {DEFAULT_PIPES} from 'angular2/src/core/pipes';
|
||||||
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
||||||
import {MockAnimationBuilder} from 'angular2/src/mock/animation_builder_mock';
|
import {MockAnimationBuilder} from 'angular2/src/mock/animation_builder_mock';
|
||||||
|
|
||||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||||
import {Reflector, reflector} from 'angular2/src/core/reflection/reflection';
|
import {Reflector, reflector} from 'angular2/src/core/reflection/reflection';
|
||||||
import {
|
import {
|
||||||
Parser,
|
Parser,
|
||||||
|
@ -13,7 +13,8 @@ import {
|
||||||
IterableDiffers,
|
IterableDiffers,
|
||||||
defaultIterableDiffers,
|
defaultIterableDiffers,
|
||||||
KeyValueDiffers,
|
KeyValueDiffers,
|
||||||
defaultKeyValueDiffers
|
defaultKeyValueDiffers,
|
||||||
|
ChangeDetectorGenConfig
|
||||||
} from 'angular2/src/core/change_detection/change_detection';
|
} from 'angular2/src/core/change_detection/change_detection';
|
||||||
import {ExceptionHandler} from 'angular2/src/core/facade/exceptions';
|
import {ExceptionHandler} from 'angular2/src/core/facade/exceptions';
|
||||||
import {ViewLoader} from 'angular2/src/core/render/dom/compiler/view_loader';
|
import {ViewLoader} from 'angular2/src/core/render/dom/compiler/view_loader';
|
||||||
|
@ -56,7 +57,6 @@ import {FunctionWrapper, Type} from 'angular2/src/core/facade/lang';
|
||||||
import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
|
import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
|
||||||
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||||
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
||||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
|
||||||
import {RenderCompiler, Renderer} from 'angular2/src/core/render/api';
|
import {RenderCompiler, Renderer} from 'angular2/src/core/render/api';
|
||||||
import {
|
import {
|
||||||
DomRenderer,
|
DomRenderer,
|
||||||
|
@ -109,6 +109,7 @@ function _getAppBindings() {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
compilerBindings(),
|
compilerBindings(),
|
||||||
|
bind(ChangeDetectorGenConfig).toValue(new ChangeDetectorGenConfig(true, true, false, true)),
|
||||||
bind(DOCUMENT).toValue(appDoc),
|
bind(DOCUMENT).toValue(appDoc),
|
||||||
DomRenderer,
|
DomRenderer,
|
||||||
bind(Renderer).toAlias(DomRenderer),
|
bind(Renderer).toAlias(DomRenderer),
|
||||||
|
@ -120,15 +121,13 @@ function _getAppBindings() {
|
||||||
bind(ElementSchemaRegistry).toValue(new DomElementSchemaRegistry()),
|
bind(ElementSchemaRegistry).toValue(new DomElementSchemaRegistry()),
|
||||||
DomSharedStylesHost,
|
DomSharedStylesHost,
|
||||||
bind(SharedStylesHost).toAlias(DomSharedStylesHost),
|
bind(SharedStylesHost).toAlias(DomSharedStylesHost),
|
||||||
ProtoViewFactory,
|
|
||||||
AppViewPool,
|
AppViewPool,
|
||||||
AppViewManager,
|
AppViewManager,
|
||||||
AppViewManagerUtils,
|
AppViewManagerUtils,
|
||||||
Serializer,
|
Serializer,
|
||||||
ELEMENT_PROBE_BINDINGS,
|
ELEMENT_PROBE_BINDINGS,
|
||||||
bind(APP_VIEW_POOL_CAPACITY).toValue(500),
|
bind(APP_VIEW_POOL_CAPACITY).toValue(500),
|
||||||
Compiler,
|
ProtoViewFactory,
|
||||||
CompilerCache,
|
|
||||||
bind(DirectiveResolver).toClass(MockDirectiveResolver),
|
bind(DirectiveResolver).toClass(MockDirectiveResolver),
|
||||||
bind(ViewResolver).toClass(MockViewResolver),
|
bind(ViewResolver).toClass(MockViewResolver),
|
||||||
DEFAULT_PIPES,
|
DEFAULT_PIPES,
|
||||||
|
|
|
@ -1,9 +1,75 @@
|
||||||
import {CONST_EXPR} from "angular2/src/core/facade/lang";
|
import {CONST_EXPR} from "angular2/src/core/facade/lang";
|
||||||
import {OpaqueToken} from "angular2/src/core/di";
|
import {OpaqueToken} from "angular2/src/core/di";
|
||||||
import {RenderElementRef, RenderViewRef} from "angular2/src/core/render/api";
|
import {
|
||||||
|
RenderElementRef,
|
||||||
|
RenderViewRef,
|
||||||
|
RenderTemplateCmd,
|
||||||
|
RenderTextCmd,
|
||||||
|
RenderNgContentCmd,
|
||||||
|
RenderBeginElementCmd,
|
||||||
|
RenderBeginComponentCmd,
|
||||||
|
RenderEmbeddedTemplateCmd,
|
||||||
|
RenderCommandVisitor
|
||||||
|
} from "angular2/src/core/render/api";
|
||||||
|
|
||||||
export const ON_WEB_WORKER = CONST_EXPR(new OpaqueToken('WebWorker.onWebWorker'));
|
export const ON_WEB_WORKER = CONST_EXPR(new OpaqueToken('WebWorker.onWebWorker'));
|
||||||
|
|
||||||
export class WebWorkerElementRef implements RenderElementRef {
|
export class WebWorkerElementRef implements RenderElementRef {
|
||||||
constructor(public renderView: RenderViewRef, public renderBoundElementIndex: number) {}
|
constructor(public renderView: RenderViewRef, public renderBoundElementIndex: number) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class WebWorkerTemplateCmd implements RenderTemplateCmd {
|
||||||
|
visit(visitor: RenderCommandVisitor, context: any): any { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WebWorkerTextCmd implements RenderTextCmd {
|
||||||
|
constructor(public isBound: boolean, public ngContentIndex: number, public value: string) {}
|
||||||
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
|
return visitor.visitText(this, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WebWorkerNgContentCmd implements RenderNgContentCmd {
|
||||||
|
constructor(public ngContentIndex: number) {}
|
||||||
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
|
return visitor.visitNgContent(this, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WebWorkerBeginElementCmd implements RenderBeginElementCmd {
|
||||||
|
constructor(public isBound: boolean, public ngContentIndex: number, public name: string,
|
||||||
|
public attrNameAndValues: string[], public eventTargetAndNames: string[]) {}
|
||||||
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
|
return visitor.visitBeginElement(this, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WebWorkerEndElementCmd implements RenderTemplateCmd {
|
||||||
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
|
return visitor.visitEndElement(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {}
|
||||||
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
|
return visitor.visitBeginComponent(this, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WebWorkerEndComponentCmd implements RenderTemplateCmd {
|
||||||
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
|
return visitor.visitEndComponent(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WebWorkerEmbeddedTemplateCmd implements RenderEmbeddedTemplateCmd {
|
||||||
|
constructor(public isBound: boolean, public ngContentIndex: number, public name: string,
|
||||||
|
public attrNameAndValues: string[], public eventTargetAndNames: string[],
|
||||||
|
public isMerged: boolean, public children: RenderTemplateCmd[]) {}
|
||||||
|
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||||
|
return visitor.visitEmbeddedTemplate(this, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
* You should not use these channels in your application code.
|
* You should not use these channels in your application code.
|
||||||
*/
|
*/
|
||||||
export const SETUP_CHANNEL = "ng-WebWorkerSetup";
|
export const SETUP_CHANNEL = "ng-WebWorkerSetup";
|
||||||
export const RENDER_COMPILER_CHANNEL = "ng-RenderCompiler";
|
|
||||||
export const RENDERER_CHANNEL = "ng-Renderer";
|
export const RENDERER_CHANNEL = "ng-Renderer";
|
||||||
export const XHR_CHANNEL = "ng-XHR";
|
export const XHR_CHANNEL = "ng-XHR";
|
||||||
export const EVENT_CHANNEL = "ng-events";
|
export const EVENT_CHANNEL = "ng-events";
|
||||||
|
|
|
@ -12,41 +12,33 @@ export class RenderProtoViewRefStore {
|
||||||
|
|
||||||
constructor(@Inject(ON_WEB_WORKER) onWebworker) { this._onWebworker = onWebworker; }
|
constructor(@Inject(ON_WEB_WORKER) onWebworker) { this._onWebworker = onWebworker; }
|
||||||
|
|
||||||
storeRenderProtoViewRef(ref: RenderProtoViewRef): number {
|
allocate(): RenderProtoViewRef {
|
||||||
if (this._lookupByProtoView.has(ref)) {
|
var index = this._nextIndex++;
|
||||||
return this._lookupByProtoView.get(ref);
|
var result = new WebWorkerRenderProtoViewRef(index);
|
||||||
} else {
|
this.store(result, index);
|
||||||
this._lookupByIndex.set(this._nextIndex, ref);
|
return result;
|
||||||
this._lookupByProtoView.set(ref, this._nextIndex);
|
|
||||||
return this._nextIndex++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
retreiveRenderProtoViewRef(index: number): RenderProtoViewRef {
|
store(ref: RenderProtoViewRef, index: number): void {
|
||||||
return this._lookupByIndex.get(index);
|
this._lookupByProtoView.set(ref, index);
|
||||||
|
this._lookupByIndex.set(index, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
deserialize(index: number): RenderProtoViewRef {
|
deserialize(index: number): RenderProtoViewRef {
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return this._lookupByIndex.get(index);
|
||||||
if (this._onWebworker) {
|
|
||||||
return new WebWorkerRenderProtoViewRef(index);
|
|
||||||
} else {
|
|
||||||
return this.retreiveRenderProtoViewRef(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(ref: RenderProtoViewRef): number {
|
serialize(ref: RenderProtoViewRef): number {
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._onWebworker) {
|
if (this._onWebworker) {
|
||||||
return (<WebWorkerRenderProtoViewRef>ref).refNumber;
|
return (<WebWorkerRenderProtoViewRef>ref).refNumber;
|
||||||
} else {
|
} else {
|
||||||
return this.storeRenderProtoViewRef(ref);
|
return this._lookupByProtoView.get(ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,26 @@ import {
|
||||||
RenderElementRef,
|
RenderElementRef,
|
||||||
ViewType,
|
ViewType,
|
||||||
ViewEncapsulation,
|
ViewEncapsulation,
|
||||||
PropertyBindingType
|
PropertyBindingType,
|
||||||
|
RenderTemplateCmd,
|
||||||
|
RenderCommandVisitor,
|
||||||
|
RenderTextCmd,
|
||||||
|
RenderNgContentCmd,
|
||||||
|
RenderBeginElementCmd,
|
||||||
|
RenderBeginComponentCmd,
|
||||||
|
RenderEmbeddedTemplateCmd
|
||||||
} from "angular2/src/core/render/api";
|
} from "angular2/src/core/render/api";
|
||||||
import {WebWorkerElementRef} from 'angular2/src/web_workers/shared/api';
|
import {
|
||||||
|
WebWorkerElementRef,
|
||||||
|
WebWorkerTemplateCmd,
|
||||||
|
WebWorkerTextCmd,
|
||||||
|
WebWorkerNgContentCmd,
|
||||||
|
WebWorkerBeginElementCmd,
|
||||||
|
WebWorkerEndElementCmd,
|
||||||
|
WebWorkerBeginComponentCmd,
|
||||||
|
WebWorkerEndComponentCmd,
|
||||||
|
WebWorkerEmbeddedTemplateCmd
|
||||||
|
} from 'angular2/src/web_workers/shared/api';
|
||||||
import {AST, ASTWithSource} from 'angular2/src/core/change_detection/change_detection';
|
import {AST, ASTWithSource} from 'angular2/src/core/change_detection/change_detection';
|
||||||
import {Parser} from "angular2/src/core/change_detection/parser/parser";
|
import {Parser} from "angular2/src/core/change_detection/parser/parser";
|
||||||
import {Injectable} from "angular2/src/core/di";
|
import {Injectable} from "angular2/src/core/di";
|
||||||
|
@ -109,6 +126,8 @@ export class Serializer {
|
||||||
return this._serializeElementPropertyBinding(obj);
|
return this._serializeElementPropertyBinding(obj);
|
||||||
} else if (type == EventBinding) {
|
} else if (type == EventBinding) {
|
||||||
return this._serializeEventBinding(obj);
|
return this._serializeEventBinding(obj);
|
||||||
|
} else if (type == WebWorkerTemplateCmd) {
|
||||||
|
return serializeTemplateCmd(obj);
|
||||||
} else {
|
} else {
|
||||||
throw new BaseException("No serializer for " + type.toString());
|
throw new BaseException("No serializer for " + type.toString());
|
||||||
}
|
}
|
||||||
|
@ -153,6 +172,8 @@ export class Serializer {
|
||||||
return this._deserializeEventBinding(map);
|
return this._deserializeEventBinding(map);
|
||||||
} else if (type == ElementPropertyBinding) {
|
} else if (type == ElementPropertyBinding) {
|
||||||
return this._deserializeElementPropertyBinding(map);
|
return this._deserializeElementPropertyBinding(map);
|
||||||
|
} else if (type == WebWorkerTemplateCmd) {
|
||||||
|
return deserializeTemplateCmd(map);
|
||||||
} else {
|
} else {
|
||||||
throw new BaseException("No deserializer for " + type.toString());
|
throw new BaseException("No deserializer for " + type.toString());
|
||||||
}
|
}
|
||||||
|
@ -406,3 +427,82 @@ export class Serializer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function serializeTemplateCmd(cmd: RenderTemplateCmd): Object {
|
||||||
|
return cmd.visit(RENDER_TEMPLATE_CMD_SERIALIZER, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deserializeTemplateCmd(data: StringMap<string, any>): RenderTemplateCmd {
|
||||||
|
return RENDER_TEMPLATE_CMD_DESERIALIZERS[data['deserializerIndex']](data);
|
||||||
|
}
|
||||||
|
|
||||||
|
class RenderTemplateCmdSerializer implements RenderCommandVisitor {
|
||||||
|
visitText(cmd: RenderTextCmd, context: any): any {
|
||||||
|
return {
|
||||||
|
'deserializerIndex': 0,
|
||||||
|
'isBound': cmd.isBound,
|
||||||
|
'ngContentIndex': cmd.ngContentIndex,
|
||||||
|
'value': cmd.value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
visitNgContent(cmd: RenderNgContentCmd, context: any): any {
|
||||||
|
return {'deserializerIndex': 1, 'ngContentIndex': cmd.ngContentIndex};
|
||||||
|
}
|
||||||
|
visitBeginElement(cmd: RenderBeginElementCmd, context: any): any {
|
||||||
|
return {
|
||||||
|
'deserializerIndex': 2,
|
||||||
|
'isBound': cmd.isBound,
|
||||||
|
'ngContentIndex': cmd.ngContentIndex,
|
||||||
|
'name': cmd.name,
|
||||||
|
'attrNameAndValues': cmd.attrNameAndValues,
|
||||||
|
'eventTargetAndNames': cmd.eventTargetAndNames
|
||||||
|
};
|
||||||
|
}
|
||||||
|
visitEndElement(context: any): any { return {'deserializerIndex': 3}; }
|
||||||
|
visitBeginComponent(cmd: RenderBeginComponentCmd, context: any): any {
|
||||||
|
return {
|
||||||
|
'deserializerIndex': 4,
|
||||||
|
'isBound': cmd.isBound,
|
||||||
|
'ngContentIndex': cmd.ngContentIndex,
|
||||||
|
'name': cmd.name,
|
||||||
|
'attrNameAndValues': cmd.attrNameAndValues,
|
||||||
|
'eventTargetAndNames': cmd.eventTargetAndNames,
|
||||||
|
'nativeShadow': cmd.nativeShadow,
|
||||||
|
'templateId': cmd.templateId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
visitEndComponent(context: any): any { return {'deserializerIndex': 5}; }
|
||||||
|
visitEmbeddedTemplate(cmd: RenderEmbeddedTemplateCmd, context: any): any {
|
||||||
|
var children = cmd.children.map(child => child.visit(this, null));
|
||||||
|
return {
|
||||||
|
'deserializerIndex': 6,
|
||||||
|
'isBound': cmd.isBound,
|
||||||
|
'ngContentIndex': cmd.ngContentIndex,
|
||||||
|
'name': cmd.name,
|
||||||
|
'attrNameAndValues': cmd.attrNameAndValues,
|
||||||
|
'eventTargetAndNames': cmd.eventTargetAndNames,
|
||||||
|
'isMerged': cmd.isMerged,
|
||||||
|
'children': children
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var RENDER_TEMPLATE_CMD_SERIALIZER = new RenderTemplateCmdSerializer();
|
||||||
|
|
||||||
|
var RENDER_TEMPLATE_CMD_DESERIALIZERS = [
|
||||||
|
(data: StringMap<string, any>) =>
|
||||||
|
new WebWorkerTextCmd(data['isBound'], data['ngContentIndex'], data['value']),
|
||||||
|
(data: StringMap<string, any>) => new WebWorkerNgContentCmd(data['ngContentIndex']),
|
||||||
|
(data: StringMap<string, any>) =>
|
||||||
|
new WebWorkerBeginElementCmd(data['isBound'], data['ngContentIndex'], data['name'],
|
||||||
|
data['attrNameAndValues'], data['eventTargetAndNames']),
|
||||||
|
(data: StringMap<string, any>) => new WebWorkerEndElementCmd(),
|
||||||
|
(data: StringMap<string, any>) => new WebWorkerBeginComponentCmd(
|
||||||
|
data['isBound'], data['ngContentIndex'], data['name'], data['attrNameAndValues'],
|
||||||
|
data['eventTargetAndNames'], data['nativeShadow'], data['templateId']),
|
||||||
|
(data: StringMap<string, any>) => new WebWorkerEndComponentCmd(),
|
||||||
|
(data: StringMap<string, any>) => new WebWorkerEmbeddedTemplateCmd(
|
||||||
|
data['isBound'], data['ngContentIndex'], data['name'], data['attrNameAndValues'],
|
||||||
|
data['eventTargetAndNames'], data['isMerged'],
|
||||||
|
(<any[]>data['children']).map(childData => deserializeTemplateCmd(childData))),
|
||||||
|
];
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {
|
||||||
DomEventsPlugin,
|
DomEventsPlugin,
|
||||||
EVENT_MANAGER_PLUGINS
|
EVENT_MANAGER_PLUGINS
|
||||||
} from 'angular2/src/core/render/dom/events/event_manager';
|
} from 'angular2/src/core/render/dom/events/event_manager';
|
||||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||||
import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter';
|
import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter';
|
||||||
import {KeyEventsPlugin} from 'angular2/src/core/render/dom/events/key_events';
|
import {KeyEventsPlugin} from 'angular2/src/core/render/dom/events/key_events';
|
||||||
import {HammerGesturesPlugin} from 'angular2/src/core/render/dom/events/hammer_gestures';
|
import {HammerGesturesPlugin} from 'angular2/src/core/render/dom/events/hammer_gestures';
|
||||||
|
@ -46,7 +46,6 @@ import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||||
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||||
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
||||||
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
|
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
|
||||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
|
||||||
import {ViewResolver} from 'angular2/src/core/compiler/view_resolver';
|
import {ViewResolver} from 'angular2/src/core/compiler/view_resolver';
|
||||||
import {ViewLoader} from 'angular2/src/core/render/dom/compiler/view_loader';
|
import {ViewLoader} from 'angular2/src/core/render/dom/compiler/view_loader';
|
||||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
||||||
|
@ -68,7 +67,6 @@ import {
|
||||||
import {AnchorBasedAppRootUrl} from 'angular2/src/core/services/anchor_based_app_root_url';
|
import {AnchorBasedAppRootUrl} from 'angular2/src/core/services/anchor_based_app_root_url';
|
||||||
import {WebWorkerApplication} from 'angular2/src/web_workers/ui/impl';
|
import {WebWorkerApplication} from 'angular2/src/web_workers/ui/impl';
|
||||||
import {MessageBus} from 'angular2/src/web_workers/shared/message_bus';
|
import {MessageBus} from 'angular2/src/web_workers/shared/message_bus';
|
||||||
import {MessageBasedRenderCompiler} from 'angular2/src/web_workers/ui/render_compiler';
|
|
||||||
import {MessageBasedRenderer} from 'angular2/src/web_workers/ui/renderer';
|
import {MessageBasedRenderer} from 'angular2/src/web_workers/ui/renderer';
|
||||||
import {MessageBasedXHRImpl} from 'angular2/src/web_workers/ui/xhr_impl';
|
import {MessageBasedXHRImpl} from 'angular2/src/web_workers/ui/xhr_impl';
|
||||||
import {WebWorkerSetup} from 'angular2/src/web_workers/ui/setup';
|
import {WebWorkerSetup} from 'angular2/src/web_workers/ui/setup';
|
||||||
|
@ -111,14 +109,12 @@ function _injectorBindings(): any[] {
|
||||||
bind(ElementSchemaRegistry).toValue(new DomElementSchemaRegistry()),
|
bind(ElementSchemaRegistry).toValue(new DomElementSchemaRegistry()),
|
||||||
RenderViewWithFragmentsStore,
|
RenderViewWithFragmentsStore,
|
||||||
RenderProtoViewRefStore,
|
RenderProtoViewRefStore,
|
||||||
ProtoViewFactory,
|
|
||||||
AppViewPool,
|
AppViewPool,
|
||||||
bind(APP_VIEW_POOL_CAPACITY).toValue(10000),
|
bind(APP_VIEW_POOL_CAPACITY).toValue(10000),
|
||||||
AppViewManager,
|
AppViewManager,
|
||||||
AppViewManagerUtils,
|
AppViewManagerUtils,
|
||||||
AppViewListener,
|
AppViewListener,
|
||||||
Compiler,
|
ProtoViewFactory,
|
||||||
CompilerCache,
|
|
||||||
ViewResolver,
|
ViewResolver,
|
||||||
DEFAULT_PIPES,
|
DEFAULT_PIPES,
|
||||||
bind(ChangeDetection).toValue(bestChangeDetection),
|
bind(ChangeDetection).toValue(bestChangeDetection),
|
||||||
|
@ -138,7 +134,6 @@ function _injectorBindings(): any[] {
|
||||||
bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl),
|
bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl),
|
||||||
WebWorkerApplication,
|
WebWorkerApplication,
|
||||||
WebWorkerSetup,
|
WebWorkerSetup,
|
||||||
MessageBasedRenderCompiler,
|
|
||||||
MessageBasedXHRImpl,
|
MessageBasedXHRImpl,
|
||||||
MessageBasedRenderer,
|
MessageBasedRenderer,
|
||||||
ServiceMessageBrokerFactory,
|
ServiceMessageBrokerFactory,
|
||||||
|
|
|
@ -77,7 +77,6 @@ Map<String, dynamic> serializeKeyboardEvent(dynamic e) {
|
||||||
serialized['eventPhase'] = e.eventPhase;
|
serialized['eventPhase'] = e.eventPhase;
|
||||||
serialized['keyCode'] = e.keyCode;
|
serialized['keyCode'] = e.keyCode;
|
||||||
serialized['keyLocation'] = e.keyLocation;
|
serialized['keyLocation'] = e.keyLocation;
|
||||||
serialized['layer'] = serializePoint(e.layer);
|
|
||||||
serialized['location'] = e.location;
|
serialized['location'] = e.location;
|
||||||
serialized['repeat'] = e.repeat;
|
serialized['repeat'] = e.repeat;
|
||||||
serialized['shiftKey'] = e.shiftKey;
|
serialized['shiftKey'] = e.shiftKey;
|
||||||
|
|
|
@ -12,7 +12,6 @@ import {Injectable} from 'angular2/src/core/di';
|
||||||
import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter';
|
import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter';
|
||||||
import {wtfInit} from 'angular2/src/core/profile/wtf_init';
|
import {wtfInit} from 'angular2/src/core/profile/wtf_init';
|
||||||
import {WebWorkerSetup} from 'angular2/src/web_workers/ui/setup';
|
import {WebWorkerSetup} from 'angular2/src/web_workers/ui/setup';
|
||||||
import {MessageBasedRenderCompiler} from 'angular2/src/web_workers/ui/render_compiler';
|
|
||||||
import {MessageBasedRenderer} from 'angular2/src/web_workers/ui/renderer';
|
import {MessageBasedRenderer} from 'angular2/src/web_workers/ui/renderer';
|
||||||
import {MessageBasedXHRImpl} from 'angular2/src/web_workers/ui/xhr_impl';
|
import {MessageBasedXHRImpl} from 'angular2/src/web_workers/ui/xhr_impl';
|
||||||
import {
|
import {
|
||||||
|
@ -35,7 +34,6 @@ export function bootstrapUICommon(bus: MessageBus): WebWorkerApplication {
|
||||||
bus.attachToZone(zone);
|
bus.attachToZone(zone);
|
||||||
return zone.run(() => {
|
return zone.run(() => {
|
||||||
var injector = createInjector(zone, bus);
|
var injector = createInjector(zone, bus);
|
||||||
injector.get(MessageBasedRenderCompiler).start();
|
|
||||||
injector.get(MessageBasedRenderer).start();
|
injector.get(MessageBasedRenderer).start();
|
||||||
injector.get(MessageBasedXHRImpl).start();
|
injector.get(MessageBasedXHRImpl).start();
|
||||||
injector.get(WebWorkerSetup).start();
|
injector.get(WebWorkerSetup).start();
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
import {Injectable} from 'angular2/src/core/di/decorators';
|
|
||||||
import {
|
|
||||||
RenderDirectiveMetadata,
|
|
||||||
ProtoViewDto,
|
|
||||||
ViewDefinition,
|
|
||||||
RenderProtoViewRef,
|
|
||||||
RenderProtoViewMergeMapping,
|
|
||||||
RenderCompiler
|
|
||||||
} from 'angular2/src/core/render/api';
|
|
||||||
import {RENDER_COMPILER_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
|
|
||||||
import {bind} from './bind';
|
|
||||||
import {ServiceMessageBrokerFactory} from 'angular2/src/web_workers/shared/service_message_broker';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class MessageBasedRenderCompiler {
|
|
||||||
constructor(private _brokerFactory: ServiceMessageBrokerFactory,
|
|
||||||
private _renderCompiler: RenderCompiler) {}
|
|
||||||
|
|
||||||
start(): void {
|
|
||||||
var broker = this._brokerFactory.createMessageBroker(RENDER_COMPILER_CHANNEL, false);
|
|
||||||
broker.registerMethod("compileHost", [RenderDirectiveMetadata],
|
|
||||||
bind(this._renderCompiler.compileHost, this._renderCompiler),
|
|
||||||
ProtoViewDto);
|
|
||||||
broker.registerMethod("compile", [ViewDefinition],
|
|
||||||
bind(this._renderCompiler.compile, this._renderCompiler), ProtoViewDto);
|
|
||||||
broker.registerMethod(
|
|
||||||
"mergeProtoViewsRecursively", [RenderProtoViewRef],
|
|
||||||
bind(this._renderCompiler.mergeProtoViewsRecursively, this._renderCompiler),
|
|
||||||
RenderProtoViewMergeMapping);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,13 +5,15 @@ import {
|
||||||
RenderViewRef,
|
RenderViewRef,
|
||||||
RenderFragmentRef,
|
RenderFragmentRef,
|
||||||
RenderProtoViewRef,
|
RenderProtoViewRef,
|
||||||
Renderer
|
Renderer,
|
||||||
|
RenderTemplateCmd
|
||||||
} from 'angular2/src/core/render/api';
|
} from 'angular2/src/core/render/api';
|
||||||
import {WebWorkerElementRef} from 'angular2/src/web_workers/shared/api';
|
import {WebWorkerElementRef, WebWorkerTemplateCmd} from 'angular2/src/web_workers/shared/api';
|
||||||
import {EVENT_CHANNEL, RENDERER_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
|
import {EVENT_CHANNEL, RENDERER_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
|
||||||
import {Type} from 'angular2/src/core/facade/lang';
|
import {Type} from 'angular2/src/core/facade/lang';
|
||||||
import {bind} from './bind';
|
import {bind} from './bind';
|
||||||
import {EventDispatcher} from 'angular2/src/web_workers/ui/event_dispatcher';
|
import {EventDispatcher} from 'angular2/src/web_workers/ui/event_dispatcher';
|
||||||
|
import {RenderProtoViewRefStore} from 'angular2/src/web_workers/shared/render_proto_view_ref_store';
|
||||||
import {
|
import {
|
||||||
RenderViewWithFragmentsStore
|
RenderViewWithFragmentsStore
|
||||||
} from 'angular2/src/web_workers/shared/render_view_with_fragments_store';
|
} from 'angular2/src/web_workers/shared/render_view_with_fragments_store';
|
||||||
|
@ -21,12 +23,18 @@ import {ServiceMessageBrokerFactory} from 'angular2/src/web_workers/shared/servi
|
||||||
export class MessageBasedRenderer {
|
export class MessageBasedRenderer {
|
||||||
constructor(private _brokerFactory: ServiceMessageBrokerFactory, private _bus: MessageBus,
|
constructor(private _brokerFactory: ServiceMessageBrokerFactory, private _bus: MessageBus,
|
||||||
private _serializer: Serializer,
|
private _serializer: Serializer,
|
||||||
|
private _renderProtoViewRefStore: RenderProtoViewRefStore,
|
||||||
private _renderViewWithFragmentsStore: RenderViewWithFragmentsStore,
|
private _renderViewWithFragmentsStore: RenderViewWithFragmentsStore,
|
||||||
private _renderer: Renderer) {}
|
private _renderer: Renderer) {}
|
||||||
|
|
||||||
start(): void {
|
start(): void {
|
||||||
var broker = this._brokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
var broker = this._brokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
||||||
this._bus.initChannel(EVENT_CHANNEL);
|
this._bus.initChannel(EVENT_CHANNEL);
|
||||||
|
|
||||||
|
broker.registerMethod("registerComponentTemplate", [PRIMITIVE, WebWorkerTemplateCmd, PRIMITIVE],
|
||||||
|
bind(this._renderer.registerComponentTemplate, this._renderer));
|
||||||
|
broker.registerMethod("createProtoView", [WebWorkerTemplateCmd, PRIMITIVE],
|
||||||
|
bind(this._createProtoView, this));
|
||||||
broker.registerMethod("createRootHostView",
|
broker.registerMethod("createRootHostView",
|
||||||
[RenderProtoViewRef, PRIMITIVE, PRIMITIVE, PRIMITIVE],
|
[RenderProtoViewRef, PRIMITIVE, PRIMITIVE, PRIMITIVE],
|
||||||
bind(this._createRootHostView, this));
|
bind(this._createRootHostView, this));
|
||||||
|
@ -64,6 +72,11 @@ export class MessageBasedRenderer {
|
||||||
this._renderViewWithFragmentsStore.remove(viewRef);
|
this._renderViewWithFragmentsStore.remove(viewRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _createProtoView(cmds: RenderTemplateCmd[], refIndex: number) {
|
||||||
|
var protoViewRef = this._renderer.createProtoView(cmds);
|
||||||
|
this._renderProtoViewRefStore.store(protoViewRef, refIndex);
|
||||||
|
}
|
||||||
|
|
||||||
private _createRootHostView(ref: RenderProtoViewRef, fragmentCount: number, selector: string,
|
private _createRootHostView(ref: RenderProtoViewRef, fragmentCount: number, selector: string,
|
||||||
startIndex: number) {
|
startIndex: number) {
|
||||||
var renderViewWithFragments = this._renderer.createRootHostView(ref, fragmentCount, selector);
|
var renderViewWithFragments = this._renderer.createRootHostView(ref, fragmentCount, selector);
|
||||||
|
|
|
@ -9,6 +9,7 @@ import "package:angular2/src/core/compiler/dynamic_component_loader.dart" show C
|
||||||
import "dart:isolate";
|
import "dart:isolate";
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
import 'package:angular2/src/core/dom/webworker_adapter.dart';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrapping a Webworker Application
|
* Bootstrapping a Webworker Application
|
||||||
|
@ -24,6 +25,7 @@ import 'dart:core';
|
||||||
Future<ComponentRef> bootstrapWebWorker(
|
Future<ComponentRef> bootstrapWebWorker(
|
||||||
SendPort replyTo, Type appComponentType,
|
SendPort replyTo, Type appComponentType,
|
||||||
[List<dynamic> componentInjectableBindings = null]) {
|
[List<dynamic> componentInjectableBindings = null]) {
|
||||||
|
WebWorkerDomAdapter.makeCurrent();
|
||||||
ReceivePort rPort = new ReceivePort();
|
ReceivePort rPort = new ReceivePort();
|
||||||
var sink = new WebWorkerMessageBusSink(replyTo, rPort);
|
var sink = new WebWorkerMessageBusSink(replyTo, rPort);
|
||||||
var source = new IsolateMessageBusSource(rPort);
|
var source = new IsolateMessageBusSource(rPort);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {Promise} from 'angular2/src/core/facade/async';
|
||||||
import {bootstrapWebWorkerCommon} from "angular2/src/web_workers/worker/application_common";
|
import {bootstrapWebWorkerCommon} from "angular2/src/web_workers/worker/application_common";
|
||||||
import {ComponentRef} from "angular2/src/core/compiler/dynamic_component_loader";
|
import {ComponentRef} from "angular2/src/core/compiler/dynamic_component_loader";
|
||||||
export * from "angular2/src/web_workers/shared/message_bus";
|
export * from "angular2/src/web_workers/shared/message_bus";
|
||||||
|
import {Parse5DomAdapter} from 'angular2/src/core/dom/parse5_adapter';
|
||||||
|
|
||||||
// TODO(jteplitz602) remove this and compile with lib.webworker.d.ts (#3492)
|
// TODO(jteplitz602) remove this and compile with lib.webworker.d.ts (#3492)
|
||||||
interface PostMessageInterface {
|
interface PostMessageInterface {
|
||||||
|
@ -29,6 +30,7 @@ var _postMessage: PostMessageInterface = <any>postMessage;
|
||||||
export function bootstrapWebWorker(
|
export function bootstrapWebWorker(
|
||||||
appComponentType: Type, componentInjectableBindings: Array<Type | Binding | any[]> = null):
|
appComponentType: Type, componentInjectableBindings: Array<Type | Binding | any[]> = null):
|
||||||
Promise<ComponentRef> {
|
Promise<ComponentRef> {
|
||||||
|
Parse5DomAdapter.makeCurrent();
|
||||||
var sink = new PostMessageBusSink({
|
var sink = new PostMessageBusSink({
|
||||||
postMessage: (message: any, transferrables?:[ArrayBuffer]) => {
|
postMessage: (message: any, transferrables?:[ArrayBuffer]) => {
|
||||||
console.log("Sending", message);
|
console.log("Sending", message);
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/core/facad
|
||||||
import {XHR} from 'angular2/src/core/render/xhr';
|
import {XHR} from 'angular2/src/core/render/xhr';
|
||||||
import {WebWorkerXHRImpl} from 'angular2/src/web_workers/worker/xhr_impl';
|
import {WebWorkerXHRImpl} from 'angular2/src/web_workers/worker/xhr_impl';
|
||||||
import {AppRootUrl} from 'angular2/src/core/services/app_root_url';
|
import {AppRootUrl} from 'angular2/src/core/services/app_root_url';
|
||||||
import {WebWorkerRenderer, WebWorkerCompiler} from './renderer';
|
import {WebWorkerRenderer} from './renderer';
|
||||||
import {Renderer, RenderCompiler} from 'angular2/src/core/render/api';
|
import {Renderer, RenderCompiler} from 'angular2/src/core/render/api';
|
||||||
import {ClientMessageBrokerFactory} from 'angular2/src/web_workers/shared/client_message_broker';
|
import {ClientMessageBrokerFactory} from 'angular2/src/web_workers/shared/client_message_broker';
|
||||||
import {MessageBus} from 'angular2/src/web_workers/shared/message_bus';
|
import {MessageBus} from 'angular2/src/web_workers/shared/message_bus';
|
||||||
|
@ -35,6 +35,7 @@ import {SETUP_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
|
||||||
import {WebWorkerEventDispatcher} from 'angular2/src/web_workers/worker/event_dispatcher';
|
import {WebWorkerEventDispatcher} from 'angular2/src/web_workers/worker/event_dispatcher';
|
||||||
import {ComponentRef} from 'angular2/src/core/compiler/dynamic_component_loader';
|
import {ComponentRef} from 'angular2/src/core/compiler/dynamic_component_loader';
|
||||||
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||||
|
import {compilerBindings} from 'angular2/src/compiler/compiler';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the Angular 'platform' on the page in a manner suitable for applications
|
* Initialize the Angular 'platform' on the page in a manner suitable for applications
|
||||||
|
@ -86,13 +87,12 @@ class PrintLogger {
|
||||||
function webWorkerBindings(appComponentType, bus: MessageBus, initData: StringMap<string, any>):
|
function webWorkerBindings(appComponentType, bus: MessageBus, initData: StringMap<string, any>):
|
||||||
Array<Type | Binding | any[]> {
|
Array<Type | Binding | any[]> {
|
||||||
return [
|
return [
|
||||||
|
compilerBindings(),
|
||||||
Serializer,
|
Serializer,
|
||||||
bind(MessageBus).toValue(bus),
|
bind(MessageBus).toValue(bus),
|
||||||
ClientMessageBrokerFactory,
|
ClientMessageBrokerFactory,
|
||||||
WebWorkerRenderer,
|
WebWorkerRenderer,
|
||||||
bind(Renderer).toAlias(WebWorkerRenderer),
|
bind(Renderer).toAlias(WebWorkerRenderer),
|
||||||
WebWorkerCompiler,
|
|
||||||
bind(RenderCompiler).toAlias(WebWorkerCompiler),
|
|
||||||
bind(ON_WEB_WORKER).toValue(true),
|
bind(ON_WEB_WORKER).toValue(true),
|
||||||
RenderViewWithFragmentsStore,
|
RenderViewWithFragmentsStore,
|
||||||
RenderProtoViewRefStore,
|
RenderProtoViewRefStore,
|
||||||
|
|
|
@ -10,9 +10,9 @@ import {
|
||||||
RenderEventDispatcher,
|
RenderEventDispatcher,
|
||||||
RenderProtoViewMergeMapping,
|
RenderProtoViewMergeMapping,
|
||||||
RenderViewWithFragments,
|
RenderViewWithFragments,
|
||||||
RenderFragmentRef
|
RenderFragmentRef,
|
||||||
|
RenderTemplateCmd
|
||||||
} from 'angular2/src/core/render/api';
|
} from 'angular2/src/core/render/api';
|
||||||
import {Promise, PromiseWrapper} from "angular2/src/core/facade/async";
|
|
||||||
import {
|
import {
|
||||||
ClientMessageBroker,
|
ClientMessageBroker,
|
||||||
ClientMessageBrokerFactory,
|
ClientMessageBrokerFactory,
|
||||||
|
@ -21,69 +21,45 @@ import {
|
||||||
} from "angular2/src/web_workers/shared/client_message_broker";
|
} from "angular2/src/web_workers/shared/client_message_broker";
|
||||||
import {isPresent, print} from "angular2/src/core/facade/lang";
|
import {isPresent, print} from "angular2/src/core/facade/lang";
|
||||||
import {Injectable} from "angular2/src/core/di";
|
import {Injectable} from "angular2/src/core/di";
|
||||||
|
import {RenderProtoViewRefStore} from 'angular2/src/web_workers/shared/render_proto_view_ref_store';
|
||||||
import {
|
import {
|
||||||
RenderViewWithFragmentsStore,
|
RenderViewWithFragmentsStore,
|
||||||
WebWorkerRenderViewRef
|
WebWorkerRenderViewRef
|
||||||
} from 'angular2/src/web_workers/shared/render_view_with_fragments_store';
|
} from 'angular2/src/web_workers/shared/render_view_with_fragments_store';
|
||||||
import {WebWorkerElementRef} from 'angular2/src/web_workers/shared/api';
|
import {WebWorkerElementRef, WebWorkerTemplateCmd} from 'angular2/src/web_workers/shared/api';
|
||||||
import {
|
import {RENDERER_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
|
||||||
RENDER_COMPILER_CHANNEL,
|
|
||||||
RENDERER_CHANNEL
|
|
||||||
} from 'angular2/src/web_workers/shared/messaging_api';
|
|
||||||
import {WebWorkerEventDispatcher} from 'angular2/src/web_workers/worker/event_dispatcher';
|
import {WebWorkerEventDispatcher} from 'angular2/src/web_workers/worker/event_dispatcher';
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class WebWorkerCompiler implements RenderCompiler {
|
|
||||||
private _messageBroker;
|
|
||||||
constructor(messageBrokerFactory: ClientMessageBrokerFactory) {
|
|
||||||
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDER_COMPILER_CHANNEL);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Creates a ProtoViewDto that contains a single nested component with the given componentId.
|
|
||||||
*/
|
|
||||||
compileHost(directiveMetadata: RenderDirectiveMetadata): Promise<ProtoViewDto> {
|
|
||||||
var fnArgs: FnArg[] = [new FnArg(directiveMetadata, RenderDirectiveMetadata)];
|
|
||||||
var args: UiArguments = new UiArguments("compileHost", fnArgs);
|
|
||||||
return this._messageBroker.runOnService(args, ProtoViewDto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compiles a single DomProtoView. Non recursive so that
|
|
||||||
* we don't need to serialize all possible components over the wire,
|
|
||||||
* but only the needed ones based on previous calls.
|
|
||||||
*/
|
|
||||||
compile(view: ViewDefinition): Promise<ProtoViewDto> {
|
|
||||||
var fnArgs: FnArg[] = [new FnArg(view, ViewDefinition)];
|
|
||||||
var args: UiArguments = new UiArguments("compile", fnArgs);
|
|
||||||
return this._messageBroker.runOnService(args, ProtoViewDto);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merges ProtoViews.
|
|
||||||
* The first entry of the array is the protoview into which all the other entries of the array
|
|
||||||
* should be merged.
|
|
||||||
* If the array contains other arrays, they will be merged before processing the parent array.
|
|
||||||
* The array must contain an entry for every component and embedded ProtoView of the first entry.
|
|
||||||
* @param protoViewRefs Array of ProtoViewRefs or nested
|
|
||||||
* @return the merge result for every input array in depth first order.
|
|
||||||
*/
|
|
||||||
mergeProtoViewsRecursively(
|
|
||||||
protoViewRefs: Array<RenderProtoViewRef | any[]>): Promise<RenderProtoViewMergeMapping> {
|
|
||||||
var fnArgs: FnArg[] = [new FnArg(protoViewRefs, RenderProtoViewRef)];
|
|
||||||
var args: UiArguments = new UiArguments("mergeProtoViewsRecursively", fnArgs);
|
|
||||||
return this._messageBroker.runOnService(args, RenderProtoViewMergeMapping);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WebWorkerRenderer implements Renderer {
|
export class WebWorkerRenderer implements Renderer {
|
||||||
private _messageBroker;
|
private _messageBroker;
|
||||||
constructor(messageBrokerFactory: ClientMessageBrokerFactory,
|
constructor(messageBrokerFactory: ClientMessageBrokerFactory,
|
||||||
|
private _renderProtoViewRefStore: RenderProtoViewRefStore,
|
||||||
private _renderViewStore: RenderViewWithFragmentsStore,
|
private _renderViewStore: RenderViewWithFragmentsStore,
|
||||||
private _eventDispatcher: WebWorkerEventDispatcher) {
|
private _eventDispatcher: WebWorkerEventDispatcher) {
|
||||||
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[], styles: string[]) {
|
||||||
|
var fnArgs = [
|
||||||
|
new FnArg(templateId, null),
|
||||||
|
new FnArg(commands, WebWorkerTemplateCmd),
|
||||||
|
new FnArg(styles, null)
|
||||||
|
];
|
||||||
|
var args = new UiArguments("registerComponentTemplate", fnArgs);
|
||||||
|
this._messageBroker.runOnService(args, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
createProtoView(cmds: RenderTemplateCmd[]): RenderProtoViewRef {
|
||||||
|
var renderProtoViewRef = this._renderProtoViewRefStore.allocate();
|
||||||
|
|
||||||
|
var fnArgs: FnArg[] =
|
||||||
|
[new FnArg(cmds, WebWorkerTemplateCmd), new FnArg(renderProtoViewRef, RenderProtoViewRef)];
|
||||||
|
var args: UiArguments = new UiArguments("createProtoView", fnArgs);
|
||||||
|
this._messageBroker.runOnService(args, null);
|
||||||
|
return renderProtoViewRef;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a root host view that includes the given element.
|
* Creates a root host view that includes the given element.
|
||||||
* Note that the fragmentCount needs to be passed in so that we can create a result
|
* Note that the fragmentCount needs to be passed in so that we can create a result
|
||||||
|
|
|
@ -33,7 +33,7 @@ import {
|
||||||
} from 'angular2/src/core/change_detection/change_detection';
|
} from 'angular2/src/core/change_detection/change_detection';
|
||||||
import {Pipes} from 'angular2/src/core/change_detection/pipes';
|
import {Pipes} from 'angular2/src/core/change_detection/pipes';
|
||||||
import {createChangeDetectorDefinitions} from 'angular2/src/compiler/change_definition_factory';
|
import {createChangeDetectorDefinitions} from 'angular2/src/compiler/change_definition_factory';
|
||||||
import {TestContext, TestDirective, TestDispatcher, TestPipes} from './change_detector_mocks';
|
import {TestDirective, TestDispatcher, TestPipes} from './change_detector_mocks';
|
||||||
|
|
||||||
import {TEST_BINDINGS} from './test_bindings';
|
import {TEST_BINDINGS} from './test_bindings';
|
||||||
|
|
||||||
|
@ -186,3 +186,11 @@ export function main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestContext {
|
||||||
|
eventLog: string[] = [];
|
||||||
|
someProp: string;
|
||||||
|
someProp2: string;
|
||||||
|
|
||||||
|
onEvent(value: string) { this.eventLog.push(value); }
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
import {bind} from 'angular2/src/core/di';
|
import {bind} from 'angular2/src/core/di';
|
||||||
|
|
||||||
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
|
import {CONST_EXPR, stringify} from 'angular2/src/core/facade/lang';
|
||||||
import {MapWrapper} from 'angular2/src/core/facade/collection';
|
import {MapWrapper} from 'angular2/src/core/facade/collection';
|
||||||
import {Promise} from 'angular2/src/core/facade/async';
|
import {Promise} from 'angular2/src/core/facade/async';
|
||||||
|
|
||||||
|
@ -46,12 +46,13 @@ import {
|
||||||
import {evalModule} from './eval_module';
|
import {evalModule} from './eval_module';
|
||||||
|
|
||||||
import {TEST_BINDINGS} from './test_bindings';
|
import {TEST_BINDINGS} from './test_bindings';
|
||||||
import {TestContext, TestDispatcher, TestPipes} from './change_detector_mocks';
|
import {TestDispatcher, TestPipes} from './change_detector_mocks';
|
||||||
import {codeGenValueFn, codeGenExportVariable} from 'angular2/src/compiler/util';
|
import {codeGenValueFn, codeGenExportVariable, MODULE_SUFFIX} from 'angular2/src/compiler/util';
|
||||||
|
|
||||||
// Attention: These module names have to correspond to real modules!
|
// Attention: These module names have to correspond to real modules!
|
||||||
const THIS_MODULE = 'angular2/test/compiler/change_detector_compiler_spec';
|
var THIS_MODULE_ID = 'angular2/test/compiler/change_detector_compiler_spec';
|
||||||
var THIS_MODULE_REF = moduleRef(THIS_MODULE);
|
var THIS_MODULE_URL = `package:${THIS_MODULE_ID}${MODULE_SUFFIX}`;
|
||||||
|
var THIS_MODULE_REF = moduleRef(THIS_MODULE_URL);
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('ChangeDetectorCompiler', () => {
|
describe('ChangeDetectorCompiler', () => {
|
||||||
|
@ -68,7 +69,8 @@ export function main() {
|
||||||
describe('compileComponentRuntime', () => {
|
describe('compileComponentRuntime', () => {
|
||||||
function detectChanges(compiler: ChangeDetectionCompiler, template: string,
|
function detectChanges(compiler: ChangeDetectionCompiler, template: string,
|
||||||
directives: CompileDirectiveMetadata[] = CONST_EXPR([])): string[] {
|
directives: CompileDirectiveMetadata[] = CONST_EXPR([])): string[] {
|
||||||
var type = new CompileTypeMetadata({name: 'SomeComp'});
|
var type =
|
||||||
|
new CompileTypeMetadata({name: stringify(SomeComponent), moduleUrl: THIS_MODULE_URL});
|
||||||
var parsedTemplate = parser.parse(template, directives, 'TestComp');
|
var parsedTemplate = parser.parse(template, directives, 'TestComp');
|
||||||
var factories =
|
var factories =
|
||||||
compiler.compileComponentRuntime(type, ChangeDetectionStrategy.Default, parsedTemplate);
|
compiler.compileComponentRuntime(type, ChangeDetectionStrategy.Default, parsedTemplate);
|
||||||
|
@ -105,7 +107,8 @@ export function main() {
|
||||||
function detectChanges(compiler: ChangeDetectionCompiler, template: string,
|
function detectChanges(compiler: ChangeDetectionCompiler, template: string,
|
||||||
directives: CompileDirectiveMetadata[] = CONST_EXPR([])):
|
directives: CompileDirectiveMetadata[] = CONST_EXPR([])):
|
||||||
Promise<string[]> {
|
Promise<string[]> {
|
||||||
var type = new CompileTypeMetadata({name: 'SomeComp'});
|
var type =
|
||||||
|
new CompileTypeMetadata({name: stringify(SomeComponent), moduleUrl: THIS_MODULE_URL});
|
||||||
var parsedTemplate = parser.parse(template, directives, 'TestComp');
|
var parsedTemplate = parser.parse(template, directives, 'TestComp');
|
||||||
var sourceExpressions =
|
var sourceExpressions =
|
||||||
compiler.compileComponentCodeGen(type, ChangeDetectionStrategy.Default, parsedTemplate);
|
compiler.compileComponentCodeGen(type, ChangeDetectionStrategy.Default, parsedTemplate);
|
||||||
|
@ -138,10 +141,14 @@ function createTestableModule(source: SourceExpressions, changeDetectorIndex: nu
|
||||||
export function testChangeDetector(changeDetectorFactory: Function): string[] {
|
export function testChangeDetector(changeDetectorFactory: Function): string[] {
|
||||||
var dispatcher = new TestDispatcher([], []);
|
var dispatcher = new TestDispatcher([], []);
|
||||||
var cd = changeDetectorFactory(dispatcher);
|
var cd = changeDetectorFactory(dispatcher);
|
||||||
var ctx = new TestContext();
|
var ctx = new SomeComponent();
|
||||||
ctx.someProp = 'someValue';
|
ctx.someProp = 'someValue';
|
||||||
var locals = new Locals(null, MapWrapper.createFromStringMap({'someVar': null}));
|
var locals = new Locals(null, MapWrapper.createFromStringMap({'someVar': null}));
|
||||||
cd.hydrate(ctx, locals, dispatcher, new TestPipes());
|
cd.hydrate(ctx, locals, dispatcher, new TestPipes());
|
||||||
cd.detectChanges();
|
cd.detectChanges();
|
||||||
return dispatcher.log;
|
return dispatcher.log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SomeComponent {
|
||||||
|
someProp: string;
|
||||||
|
}
|
|
@ -7,14 +7,6 @@ import {
|
||||||
BindingTarget
|
BindingTarget
|
||||||
} from 'angular2/src/core/change_detection/change_detection';
|
} from 'angular2/src/core/change_detection/change_detection';
|
||||||
|
|
||||||
export class TestContext {
|
|
||||||
eventLog: string[] = [];
|
|
||||||
someProp: string;
|
|
||||||
someProp2: string;
|
|
||||||
|
|
||||||
onEvent(value: string) { this.eventLog.push(value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TestDirective {
|
export class TestDirective {
|
||||||
eventLog: string[] = [];
|
eventLog: string[] = [];
|
||||||
dirProp: string;
|
dirProp: string;
|
||||||
|
|
|
@ -40,7 +40,8 @@ import {evalModule} from './eval_module';
|
||||||
import {
|
import {
|
||||||
escapeSingleQuoteString,
|
escapeSingleQuoteString,
|
||||||
codeGenValueFn,
|
codeGenValueFn,
|
||||||
codeGenExportVariable
|
codeGenExportVariable,
|
||||||
|
MODULE_SUFFIX
|
||||||
} from 'angular2/src/compiler/util';
|
} from 'angular2/src/compiler/util';
|
||||||
import {TEST_BINDINGS} from './test_bindings';
|
import {TEST_BINDINGS} from './test_bindings';
|
||||||
|
|
||||||
|
@ -53,9 +54,10 @@ const NG_CONTENT = 'NG_CONTENT';
|
||||||
const EMBEDDED_TEMPLATE = 'EMBEDDED_TEMPLATE';
|
const EMBEDDED_TEMPLATE = 'EMBEDDED_TEMPLATE';
|
||||||
|
|
||||||
// Attention: These module names have to correspond to real modules!
|
// Attention: These module names have to correspond to real modules!
|
||||||
const THIS_MODULE_NAME = 'angular2/test/compiler/command_compiler_spec';
|
var THIS_MODULE_URL = `package:angular2/test/compiler/command_compiler_spec${MODULE_SUFFIX}`;
|
||||||
var THIS_MODULE_REF = moduleRef(THIS_MODULE_NAME);
|
var THIS_MODULE_REF = moduleRef(THIS_MODULE_URL);
|
||||||
var TEMPLATE_COMMANDS_MODULE_REF = moduleRef('angular2/src/core/compiler/template_commands');
|
var TEMPLATE_COMMANDS_MODULE_REF =
|
||||||
|
moduleRef(`package:angular2/src/core/compiler/template_commands${MODULE_SUFFIX}`);
|
||||||
|
|
||||||
// Attention: read by eval!
|
// Attention: read by eval!
|
||||||
export class RootComp {}
|
export class RootComp {}
|
||||||
|
@ -63,11 +65,11 @@ export class SomeDir {}
|
||||||
export class AComp {}
|
export class AComp {}
|
||||||
|
|
||||||
var RootCompTypeMeta =
|
var RootCompTypeMeta =
|
||||||
new CompileTypeMetadata({name: 'RootComp', runtime: RootComp, moduleId: THIS_MODULE_NAME});
|
new CompileTypeMetadata({name: 'RootComp', runtime: RootComp, moduleUrl: THIS_MODULE_URL});
|
||||||
var SomeDirTypeMeta =
|
var SomeDirTypeMeta =
|
||||||
new CompileTypeMetadata({name: 'SomeDir', runtime: SomeDir, moduleId: THIS_MODULE_NAME});
|
new CompileTypeMetadata({name: 'SomeDir', runtime: SomeDir, moduleUrl: THIS_MODULE_URL});
|
||||||
var ACompTypeMeta =
|
var ACompTypeMeta =
|
||||||
new CompileTypeMetadata({name: 'AComp', runtime: AComp, moduleId: THIS_MODULE_NAME});
|
new CompileTypeMetadata({name: 'AComp', runtime: AComp, moduleUrl: THIS_MODULE_URL});
|
||||||
var compTypeTemplateId: Map<CompileTypeMetadata, number> =
|
var compTypeTemplateId: Map<CompileTypeMetadata, number> =
|
||||||
MapWrapper.createFromPairs([[RootCompTypeMeta, 1], [SomeDirTypeMeta, 2], [ACompTypeMeta, 3]]);
|
MapWrapper.createFromPairs([[RootCompTypeMeta, 1], [SomeDirTypeMeta, 2], [ACompTypeMeta, 3]]);
|
||||||
const APP_ID = 'app1';
|
const APP_ID = 'app1';
|
||||||
|
|
|
@ -28,7 +28,8 @@ export function main() {
|
||||||
var fullDirectiveMeta: CompileDirectiveMetadata;
|
var fullDirectiveMeta: CompileDirectiveMetadata;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fullTypeMeta = new CompileTypeMetadata({name: 'SomeType', moduleId: 'someUrl'});
|
fullTypeMeta =
|
||||||
|
new CompileTypeMetadata({name: 'SomeType', moduleUrl: 'someUrl', isHost: true});
|
||||||
fullTemplateMeta = new CompileTemplateMetadata({
|
fullTemplateMeta = new CompileTemplateMetadata({
|
||||||
encapsulation: ViewEncapsulation.Emulated,
|
encapsulation: ViewEncapsulation.Emulated,
|
||||||
template: '<a></a>',
|
template: '<a></a>',
|
||||||
|
|
|
@ -11,7 +11,7 @@ createIsolateSource(String moduleSource, List<List<String>> moduleImports) {
|
||||||
moduleImports.forEach((sourceImport) {
|
moduleImports.forEach((sourceImport) {
|
||||||
String modName = sourceImport[0];
|
String modName = sourceImport[0];
|
||||||
String modAlias = sourceImport[1];
|
String modAlias = sourceImport[1];
|
||||||
moduleSourceParts.add("import 'package:${modName}.dart' as ${modAlias};");
|
moduleSourceParts.add("import '${modName}' as ${modAlias};");
|
||||||
});
|
});
|
||||||
moduleSourceParts.add(moduleSource);
|
moduleSourceParts.add(moduleSource);
|
||||||
moduleSourceParts.add("""
|
moduleSourceParts.add("""
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';
|
||||||
import {isPresent, global, StringWrapper} from 'angular2/src/core/facade/lang';
|
import {isPresent, global, StringWrapper} from 'angular2/src/core/facade/lang';
|
||||||
|
|
||||||
var evalCounter = 0;
|
var evalCounter = 0;
|
||||||
|
var MODULE_URL_REGEX = /^package:(.*)\.js/;
|
||||||
|
|
||||||
function nextModuleId() {
|
function nextModuleId() {
|
||||||
return `evalScript${evalCounter++}`;
|
return `evalScript${evalCounter++}`;
|
||||||
|
@ -10,24 +11,30 @@ function nextModuleId() {
|
||||||
export function evalModule(moduleSource: string, imports: string[][], args: any[]): Promise<any> {
|
export function evalModule(moduleSource: string, imports: string[][], args: any[]): Promise<any> {
|
||||||
var moduleId = nextModuleId();
|
var moduleId = nextModuleId();
|
||||||
var moduleSourceWithImports = [];
|
var moduleSourceWithImports = [];
|
||||||
var importModuleNames = [];
|
var importModuleIds = [];
|
||||||
imports.forEach(sourceImport => {
|
imports.forEach(sourceImport => {
|
||||||
var modName = sourceImport[0];
|
var modUrl = sourceImport[0];
|
||||||
|
var modMatch = MODULE_URL_REGEX.exec(modUrl);
|
||||||
|
if (!modMatch) {
|
||||||
|
throw new Error(`Module url ${modUrl} does not match the pattern ${MODULE_URL_REGEX}`);
|
||||||
|
}
|
||||||
|
var modId = modMatch[1];
|
||||||
|
|
||||||
var modAlias = sourceImport[1];
|
var modAlias = sourceImport[1];
|
||||||
importModuleNames.push(modName);
|
importModuleIds.push(modId);
|
||||||
// Note: After transpilation to commonJS and loading this file in a browser
|
// Note: After transpilation to commonJS and loading this file in a browser
|
||||||
// using SystemJS, the loader might get confused by the presence of require,
|
// using SystemJS, the loader might get confused by the presence of require,
|
||||||
// and attempt to load "+ modName +.js" !?!
|
// and attempt to load "+ modName +.js" !?!
|
||||||
// A simple string concat manages to prevent that, but that is one compiler
|
// A simple string concat manages to prevent that, but that is one compiler
|
||||||
// optimaztion away from breaking again. Proceed with caution!
|
// optimaztion away from breaking again. Proceed with caution!
|
||||||
moduleSourceWithImports.push(`var ${modAlias} = require` + `('${modName}');`);
|
moduleSourceWithImports.push(`var ${modAlias} = require` + `('${modId}');`);
|
||||||
});
|
});
|
||||||
moduleSourceWithImports.push(moduleSource);
|
moduleSourceWithImports.push(moduleSource);
|
||||||
|
|
||||||
var moduleBody = new Function('require', 'exports', 'module', moduleSourceWithImports.join('\n'));
|
var moduleBody = new Function('require', 'exports', 'module', moduleSourceWithImports.join('\n'));
|
||||||
var System = global['System'];
|
var System = global['System'];
|
||||||
if (isPresent(System) && isPresent(System.registerDynamic)) {
|
if (isPresent(System) && isPresent(System.registerDynamic)) {
|
||||||
System.registerDynamic(moduleId, importModuleNames, false, moduleBody);
|
System.registerDynamic(moduleId, importModuleIds, false, moduleBody);
|
||||||
return <Promise<any>>System.import(moduleId).then((module) => module.run(args));
|
return <Promise<any>>System.import(moduleId).then((module) => module.run(args));
|
||||||
} else {
|
} else {
|
||||||
var exports = {};
|
var exports = {};
|
||||||
|
|
|
@ -19,14 +19,14 @@ import {evalModule} from './eval_module';
|
||||||
// when evaling the test module!
|
// when evaling the test module!
|
||||||
export var TEST_VALUE = 23;
|
export var TEST_VALUE = 23;
|
||||||
|
|
||||||
const THIS_MODULE = 'angular2/test/compiler/eval_module_spec';
|
const THIS_MODULE_URL = `package:angular2/test/compiler/eval_module_spec${IS_DART?'.dart':'.js'}`;
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('evalModule', () => {
|
describe('evalModule', () => {
|
||||||
it('should call the "run" function and allow to use imports',
|
it('should call the "run" function and allow to use imports',
|
||||||
inject([AsyncTestCompleter], (async) => {
|
inject([AsyncTestCompleter], (async) => {
|
||||||
var moduleSource = IS_DART ? testDartModule : testJsModule;
|
var moduleSource = IS_DART ? testDartModule : testJsModule;
|
||||||
evalModule(moduleSource, [[THIS_MODULE, 'tst']], [1])
|
evalModule(moduleSource, [[THIS_MODULE_URL, 'tst']], [1])
|
||||||
.then((value) => {
|
.then((value) => {
|
||||||
expect(value).toEqual([1, 23]);
|
expect(value).toEqual([1, 23]);
|
||||||
async.done();
|
async.done();
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
import {
|
||||||
|
ddescribe,
|
||||||
|
describe,
|
||||||
|
xdescribe,
|
||||||
|
it,
|
||||||
|
iit,
|
||||||
|
xit,
|
||||||
|
expect,
|
||||||
|
beforeEach,
|
||||||
|
afterEach,
|
||||||
|
AsyncTestCompleter,
|
||||||
|
inject,
|
||||||
|
beforeEachBindings
|
||||||
|
} from 'angular2/test_lib';
|
||||||
|
|
||||||
|
import {Component, View, bind} from 'angular2/core';
|
||||||
|
import {PromiseWrapper} from 'angular2/src/core/facade/async';
|
||||||
|
import {SpyProtoViewFactory} from '../core/spies';
|
||||||
|
import {
|
||||||
|
CompiledHostTemplate,
|
||||||
|
CompiledTemplate,
|
||||||
|
BeginComponentCmd
|
||||||
|
} from 'angular2/src/core/compiler/template_commands';
|
||||||
|
import {RuntimeCompiler} from 'angular2/src/compiler/runtime_compiler';
|
||||||
|
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||||
|
import {AppProtoView} from 'angular2/src/core/compiler/view';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
describe('RuntimeCompiler', () => {
|
||||||
|
var compiler: RuntimeCompiler;
|
||||||
|
|
||||||
|
beforeEach(inject([RuntimeCompiler], (_compiler) => { compiler = _compiler; }));
|
||||||
|
|
||||||
|
describe('compileInHost', () => {
|
||||||
|
var protoViewFactorySpy;
|
||||||
|
var someProtoView;
|
||||||
|
|
||||||
|
beforeEachBindings(() => {
|
||||||
|
protoViewFactorySpy = new SpyProtoViewFactory();
|
||||||
|
someProtoView = new AppProtoView(null, null, null, null, null, null);
|
||||||
|
protoViewFactorySpy.spy('createHost').andReturn(someProtoView);
|
||||||
|
return [bind(ProtoViewFactory).toValue(protoViewFactorySpy)];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should compile the template via TemplateCompiler',
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
var cht: CompiledHostTemplate;
|
||||||
|
protoViewFactorySpy.spy('createHost')
|
||||||
|
.andCallFake((_cht) => {
|
||||||
|
cht = _cht;
|
||||||
|
return someProtoView;
|
||||||
|
});
|
||||||
|
compiler.compileInHost(SomeComponent)
|
||||||
|
.then((_) => {
|
||||||
|
var beginComponentCmd =
|
||||||
|
<BeginComponentCmd>cht.getTemplate().getData('app1').commands[0];
|
||||||
|
expect(beginComponentCmd.name).toEqual('some-comp');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should cache the result', inject([AsyncTestCompleter], (async) => {
|
||||||
|
PromiseWrapper
|
||||||
|
.all([compiler.compileInHost(SomeComponent), compiler.compileInHost(SomeComponent)])
|
||||||
|
.then((protoViewRefs) => {
|
||||||
|
expect(protoViewRefs[0]).toBe(protoViewRefs[1]);
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should clear the cache',
|
||||||
|
inject([AsyncTestCompleter], (async) => {compiler.compileInHost(SomeComponent)
|
||||||
|
.then((protoViewRef1) => {
|
||||||
|
compiler.clearCache();
|
||||||
|
compiler.compileInHost(SomeComponent)
|
||||||
|
.then((protoViewRef2) => {
|
||||||
|
expect(protoViewRef1)
|
||||||
|
.not.toBe(protoViewRef2);
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
})}));
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'some-comp'})
|
||||||
|
@View({template: ''})
|
||||||
|
class SomeComponent {
|
||||||
|
}
|
|
@ -34,7 +34,7 @@ import {
|
||||||
} from 'angular2/core';
|
} from 'angular2/core';
|
||||||
|
|
||||||
import {TEST_BINDINGS} from './test_bindings';
|
import {TEST_BINDINGS} from './test_bindings';
|
||||||
import {IS_DART} from '../platform';
|
import {MODULE_SUFFIX, IS_DART} from 'angular2/src/compiler/util';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('RuntimeMetadataResolver', () => {
|
describe('RuntimeMetadataResolver', () => {
|
||||||
|
@ -50,7 +50,7 @@ export function main() {
|
||||||
expect(meta.dynamicLoadable).toBe(true);
|
expect(meta.dynamicLoadable).toBe(true);
|
||||||
expect(meta.type.runtime).toBe(ComponentWithEverything);
|
expect(meta.type.runtime).toBe(ComponentWithEverything);
|
||||||
expect(meta.type.name).toEqual(stringify(ComponentWithEverything));
|
expect(meta.type.name).toEqual(stringify(ComponentWithEverything));
|
||||||
expect(meta.type.moduleId).toEqual('someModuleId');
|
expect(meta.type.moduleUrl).toEqual(`package:someModuleId${MODULE_SUFFIX}`);
|
||||||
expect(meta.lifecycleHooks).toEqual(LIFECYCLE_HOOKS_VALUES);
|
expect(meta.lifecycleHooks).toEqual(LIFECYCLE_HOOKS_VALUES);
|
||||||
expect(meta.changeDetection).toBe(ChangeDetectionStrategy.CheckAlways);
|
expect(meta.changeDetection).toBe(ChangeDetectionStrategy.CheckAlways);
|
||||||
expect(meta.inputs).toEqual({'someProp': 'someProp'});
|
expect(meta.inputs).toEqual({'someProp': 'someProp'});
|
||||||
|
@ -65,12 +65,12 @@ export function main() {
|
||||||
expect(meta.template.templateUrl).toEqual('someTemplateUrl');
|
expect(meta.template.templateUrl).toEqual('someTemplateUrl');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should use the moduleId from the reflector if none is given',
|
it('should use the moduleUrl from the reflector if none is given',
|
||||||
inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => {
|
inject([RuntimeMetadataResolver], (resolver: RuntimeMetadataResolver) => {
|
||||||
var expectedValue =
|
var value: string = resolver.getMetadata(DirectiveWithoutModuleId).type.moduleUrl;
|
||||||
IS_DART ? 'base/dist/dart/angular2/test/compiler/runtime_metadata_spec' : './';
|
var expectedEndValue =
|
||||||
expect(resolver.getMetadata(DirectiveWithoutModuleId).type.moduleId)
|
IS_DART ? 'base/dist/dart/angular2/test/compiler/runtime_metadata_spec.dart' : './';
|
||||||
.toEqual(expectedValue);
|
expect((<any>value).endsWith(expectedEndValue)).toBe(true);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -19,22 +19,26 @@ export function main() {
|
||||||
describe('getSourceWithImports', () => {
|
describe('getSourceWithImports', () => {
|
||||||
it('should generate named imports for modules', () => {
|
it('should generate named imports for modules', () => {
|
||||||
var sourceWithImports =
|
var sourceWithImports =
|
||||||
new SourceModule('some/moda', `${moduleRef('some/modb')}A`).getSourceWithImports();
|
new SourceModule('package:some/moda', `${moduleRef('package:some/modb')}A`)
|
||||||
|
.getSourceWithImports();
|
||||||
expect(sourceWithImports.source).toEqual('import0.A');
|
expect(sourceWithImports.source).toEqual('import0.A');
|
||||||
expect(sourceWithImports.imports).toEqual([['some/modb', 'import0']]);
|
expect(sourceWithImports.imports).toEqual([['package:some/modb', 'import0']]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should dedupe imports', () => {
|
it('should dedupe imports', () => {
|
||||||
var sourceWithImports =
|
var sourceWithImports =
|
||||||
new SourceModule('some/moda', `${moduleRef('some/modb')}A + ${moduleRef('some/modb')}B`)
|
new SourceModule(
|
||||||
|
'package:some/moda',
|
||||||
|
`${moduleRef('package:some/modb')}A + ${moduleRef('package:some/modb')}B`)
|
||||||
.getSourceWithImports();
|
.getSourceWithImports();
|
||||||
expect(sourceWithImports.source).toEqual('import0.A + import0.B');
|
expect(sourceWithImports.source).toEqual('import0.A + import0.B');
|
||||||
expect(sourceWithImports.imports).toEqual([['some/modb', 'import0']]);
|
expect(sourceWithImports.imports).toEqual([['package:some/modb', 'import0']]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not use an import for the moduleId of the SourceModule', () => {
|
it('should not use an import for the moduleUrl of the SourceModule', () => {
|
||||||
var sourceWithImports =
|
var sourceWithImports =
|
||||||
new SourceModule('some/moda', `${moduleRef('some/moda')}A`).getSourceWithImports();
|
new SourceModule('package:some/moda', `${moduleRef('package:some/moda')}A`)
|
||||||
|
.getSourceWithImports();
|
||||||
expect(sourceWithImports.source).toEqual('A');
|
expect(sourceWithImports.source).toEqual('A');
|
||||||
expect(sourceWithImports.imports).toEqual([]);
|
expect(sourceWithImports.imports).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,15 +29,15 @@ import {
|
||||||
import {SourceExpression, SourceModule} from 'angular2/src/compiler/source_module';
|
import {SourceExpression, SourceModule} from 'angular2/src/compiler/source_module';
|
||||||
import {ViewEncapsulation} from 'angular2/src/core/render/api';
|
import {ViewEncapsulation} from 'angular2/src/core/render/api';
|
||||||
import {TEST_BINDINGS} from './test_bindings';
|
import {TEST_BINDINGS} from './test_bindings';
|
||||||
import {codeGenValueFn, codeGenExportVariable} from 'angular2/src/compiler/util';
|
import {codeGenValueFn, codeGenExportVariable, MODULE_SUFFIX} from 'angular2/src/compiler/util';
|
||||||
|
|
||||||
// Attention: These module names have to correspond to real modules!
|
// Attention: These module names have to correspond to real modules!
|
||||||
const MODULE_NAME = 'angular2/test/compiler/style_compiler_spec';
|
var MODULE_URL = `package:angular2/test/compiler/style_compiler_spec${MODULE_SUFFIX}`;
|
||||||
const IMPORT_ABS_MODULE_NAME = 'angular2/test/compiler/style_compiler_import';
|
var IMPORT_ABS_STYLESHEET_URL = `package:angular2/test/compiler/style_compiler_import.css`;
|
||||||
const IMPORT_REL_MODULE_NAME = './style_compiler_import';
|
var IMPORT_REL_STYLESHEET_URL = './style_compiler_import.css';
|
||||||
// Note: Not a real module, only used via mocks.
|
// Note: Not a real module, only used via mocks.
|
||||||
const IMPORT_ABS_MODULE_NAME_WITH_IMPORT =
|
var IMPORT_ABS_STYLESHEET_URL_WITH_IMPORT =
|
||||||
'angular2/test/compiler/style_compiler_transitive_import';
|
`package:angular2/test/compiler/style_compiler_transitive_import.css`;
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('StyleCompiler', () => {
|
describe('StyleCompiler', () => {
|
||||||
|
@ -65,9 +65,9 @@ export function main() {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
xhrCount = 0;
|
xhrCount = 0;
|
||||||
xhrUrlResults = {};
|
xhrUrlResults = {};
|
||||||
xhrUrlResults[IMPORT_ABS_MODULE_NAME] = 'span {color: blue}';
|
xhrUrlResults[IMPORT_ABS_STYLESHEET_URL] = 'span {color: blue}';
|
||||||
xhrUrlResults[IMPORT_ABS_MODULE_NAME_WITH_IMPORT] =
|
xhrUrlResults[IMPORT_ABS_STYLESHEET_URL_WITH_IMPORT] =
|
||||||
`a {color: green}@import ${IMPORT_REL_MODULE_NAME};`;
|
`a {color: green}@import ${IMPORT_REL_STYLESHEET_URL};`;
|
||||||
});
|
});
|
||||||
|
|
||||||
function compile(styles: string[], styleAbsUrls: string[], encapsulation: ViewEncapsulation):
|
function compile(styles: string[], styleAbsUrls: string[], encapsulation: ViewEncapsulation):
|
||||||
|
@ -100,7 +100,7 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
||||||
compile(['div {color: red}'], [IMPORT_ABS_MODULE_NAME], encapsulation)
|
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
expect(styles).toEqual(['div {color: red}', 'span {color: blue}']);
|
expect(styles).toEqual(['div {color: red}', 'span {color: blue}']);
|
||||||
async.done();
|
async.done();
|
||||||
|
@ -108,7 +108,7 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow to import rules transitively', inject([AsyncTestCompleter], (async) => {
|
it('should allow to import rules transitively', inject([AsyncTestCompleter], (async) => {
|
||||||
compile(['div {color: red}'], [IMPORT_ABS_MODULE_NAME_WITH_IMPORT], encapsulation)
|
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL_WITH_IMPORT], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
expect(styles)
|
expect(styles)
|
||||||
.toEqual(['div {color: red}', 'a {color: green}', 'span {color: blue}']);
|
.toEqual(['div {color: red}', 'a {color: green}', 'span {color: blue}']);
|
||||||
|
@ -132,7 +132,7 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
||||||
compile(['div {\ncolor: red;\n}'], [IMPORT_ABS_MODULE_NAME], encapsulation)
|
compile(['div {\ncolor: red;\n}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
compareStyles(styles, [
|
compareStyles(styles, [
|
||||||
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
|
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
|
||||||
|
@ -143,7 +143,8 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow to import rules transitively', inject([AsyncTestCompleter], (async) => {
|
it('should allow to import rules transitively', inject([AsyncTestCompleter], (async) => {
|
||||||
compile(['div {\ncolor: red;\n}'], [IMPORT_ABS_MODULE_NAME_WITH_IMPORT], encapsulation)
|
compile(['div {\ncolor: red;\n}'], [IMPORT_ABS_STYLESHEET_URL_WITH_IMPORT],
|
||||||
|
encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
compareStyles(styles, [
|
compareStyles(styles, [
|
||||||
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
|
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
|
||||||
|
@ -157,8 +158,8 @@ export function main() {
|
||||||
|
|
||||||
it('should cache stylesheets for parallel requests', inject([AsyncTestCompleter], (async) => {
|
it('should cache stylesheets for parallel requests', inject([AsyncTestCompleter], (async) => {
|
||||||
PromiseWrapper.all([
|
PromiseWrapper.all([
|
||||||
compile([], [IMPORT_ABS_MODULE_NAME], ViewEncapsulation.None),
|
compile([], [IMPORT_ABS_STYLESHEET_URL], ViewEncapsulation.None),
|
||||||
compile([], [IMPORT_ABS_MODULE_NAME], ViewEncapsulation.None)
|
compile([], [IMPORT_ABS_STYLESHEET_URL], ViewEncapsulation.None)
|
||||||
])
|
])
|
||||||
.then((styleArrays) => {
|
.then((styleArrays) => {
|
||||||
expect(styleArrays[0]).toEqual(['span {color: blue}']);
|
expect(styleArrays[0]).toEqual(['span {color: blue}']);
|
||||||
|
@ -169,10 +170,10 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should cache stylesheets for serial requests', inject([AsyncTestCompleter], (async) => {
|
it('should cache stylesheets for serial requests', inject([AsyncTestCompleter], (async) => {
|
||||||
compile([], [IMPORT_ABS_MODULE_NAME], ViewEncapsulation.None)
|
compile([], [IMPORT_ABS_STYLESHEET_URL], ViewEncapsulation.None)
|
||||||
.then((styles0) => {
|
.then((styles0) => {
|
||||||
xhrUrlResults[IMPORT_ABS_MODULE_NAME] = 'span {color: black}';
|
xhrUrlResults[IMPORT_ABS_STYLESHEET_URL] = 'span {color: black}';
|
||||||
return compile([], [IMPORT_ABS_MODULE_NAME], ViewEncapsulation.None)
|
return compile([], [IMPORT_ABS_STYLESHEET_URL], ViewEncapsulation.None)
|
||||||
.then((styles1) => {
|
.then((styles1) => {
|
||||||
expect(styles0).toEqual(['span {color: blue}']);
|
expect(styles0).toEqual(['span {color: blue}']);
|
||||||
expect(styles1).toEqual(['span {color: blue}']);
|
expect(styles1).toEqual(['span {color: blue}']);
|
||||||
|
@ -183,11 +184,11 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow to clear the cache', inject([AsyncTestCompleter], (async) => {
|
it('should allow to clear the cache', inject([AsyncTestCompleter], (async) => {
|
||||||
compile([], [IMPORT_ABS_MODULE_NAME], ViewEncapsulation.None)
|
compile([], [IMPORT_ABS_STYLESHEET_URL], ViewEncapsulation.None)
|
||||||
.then((_) => {
|
.then((_) => {
|
||||||
compiler.clearCache();
|
compiler.clearCache();
|
||||||
xhrUrlResults[IMPORT_ABS_MODULE_NAME] = 'span {color: black}';
|
xhrUrlResults[IMPORT_ABS_STYLESHEET_URL] = 'span {color: black}';
|
||||||
return compile([], [IMPORT_ABS_MODULE_NAME], ViewEncapsulation.None);
|
return compile([], [IMPORT_ABS_STYLESHEET_URL], ViewEncapsulation.None);
|
||||||
})
|
})
|
||||||
.then((styles) => {
|
.then((styles) => {
|
||||||
expect(xhrCount).toBe(2);
|
expect(xhrCount).toBe(2);
|
||||||
|
@ -229,7 +230,7 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
||||||
compile(['div {color: red}'], [IMPORT_ABS_MODULE_NAME], encapsulation)
|
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
expect(styles).toEqual(['div {color: red}', 'span {color: blue}']);
|
expect(styles).toEqual(['div {color: red}', 'span {color: blue}']);
|
||||||
async.done();
|
async.done();
|
||||||
|
@ -252,7 +253,7 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
it('should allow to import rules', inject([AsyncTestCompleter], (async) => {
|
||||||
compile(['div {color: red}'], [IMPORT_ABS_MODULE_NAME], encapsulation)
|
compile(['div {color: red}'], [IMPORT_ABS_STYLESHEET_URL], encapsulation)
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
compareStyles(styles, [
|
compareStyles(styles, [
|
||||||
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
|
'div[_ngcontent-app1-23] {\ncolor: red;\n}',
|
||||||
|
@ -266,7 +267,7 @@ export function main() {
|
||||||
|
|
||||||
describe('compileStylesheetCodeGen', () => {
|
describe('compileStylesheetCodeGen', () => {
|
||||||
function compile(style: string): Promise<string[][]> {
|
function compile(style: string): Promise<string[][]> {
|
||||||
var sourceModules = compiler.compileStylesheetCodeGen(MODULE_NAME, style);
|
var sourceModules = compiler.compileStylesheetCodeGen(MODULE_URL, style);
|
||||||
return PromiseWrapper.all(sourceModules.map(sourceModule => {
|
return PromiseWrapper.all(sourceModules.map(sourceModule => {
|
||||||
var sourceWithImports = testableModule(sourceModule).getSourceWithImports();
|
var sourceWithImports = testableModule(sourceModule).getSourceWithImports();
|
||||||
return evalModule(sourceWithImports.source, sourceWithImports.imports, null);
|
return evalModule(sourceWithImports.source, sourceWithImports.imports, null);
|
||||||
|
@ -286,7 +287,7 @@ export function main() {
|
||||||
|
|
||||||
it('should allow to import rules with relative paths',
|
it('should allow to import rules with relative paths',
|
||||||
inject([AsyncTestCompleter], (async) => {
|
inject([AsyncTestCompleter], (async) => {
|
||||||
compile(`div {color: red}@import ${IMPORT_REL_MODULE_NAME};`)
|
compile(`div {color: red}@import ${IMPORT_REL_STYLESHEET_URL};`)
|
||||||
.then(stylesAndShimStyles => {
|
.then(stylesAndShimStyles => {
|
||||||
var expected = [
|
var expected = [
|
||||||
['div {color: red}', 'span {color: blue}'],
|
['div {color: red}', 'span {color: blue}'],
|
||||||
|
@ -314,7 +315,7 @@ function testableExpression(source: SourceExpression): SourceModule {
|
||||||
function testableModule(sourceModule: SourceModule): SourceModule {
|
function testableModule(sourceModule: SourceModule): SourceModule {
|
||||||
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
||||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], 'STYLES')};`;
|
${codeGenExportVariable('run')}${codeGenValueFn(['_'], 'STYLES')};`;
|
||||||
return new SourceModule(sourceModule.moduleId, testableSource);
|
return new SourceModule(sourceModule.moduleUrl, testableSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needed for Android browsers which add an extra space at the end of some lines
|
// Needed for Android browsers which add an extra space at the end of some lines
|
||||||
|
|
|
@ -44,13 +44,13 @@ import {
|
||||||
import {Component, View, Directive, bind} from 'angular2/core';
|
import {Component, View, Directive, bind} from 'angular2/core';
|
||||||
|
|
||||||
import {TEST_BINDINGS} from './test_bindings';
|
import {TEST_BINDINGS} from './test_bindings';
|
||||||
import {TestContext, TestDispatcher, TestPipes} from './change_detector_mocks';
|
import {TestDispatcher, TestPipes} from './change_detector_mocks';
|
||||||
import {codeGenValueFn, codeGenExportVariable} from 'angular2/src/compiler/util';
|
import {codeGenValueFn, codeGenExportVariable, MODULE_SUFFIX} from 'angular2/src/compiler/util';
|
||||||
import {APP_ID} from 'angular2/src/core/render/dom/dom_tokens';
|
import {APP_ID} from 'angular2/src/core/render/dom/dom_tokens';
|
||||||
|
|
||||||
// Attention: This path has to point to this test file!
|
// Attention: This path has to point to this test file!
|
||||||
const THIS_MODULE = 'angular2/test/compiler/template_compiler_spec';
|
const THIS_MODULE_ID = 'angular2/test/compiler/template_compiler_spec';
|
||||||
var THIS_MODULE_REF = moduleRef(THIS_MODULE);
|
var THIS_MODULE_REF = moduleRef(`package:${THIS_MODULE_ID}${MODULE_SUFFIX}`);
|
||||||
|
|
||||||
const APP_ID_VALUE = 'app1';
|
const APP_ID_VALUE = 'app1';
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ export function main() {
|
||||||
|
|
||||||
it('should cache components for parallel requests',
|
it('should cache components for parallel requests',
|
||||||
inject([AsyncTestCompleter, XHR], (async, xhr: MockXHR) => {
|
inject([AsyncTestCompleter, XHR], (async, xhr: MockXHR) => {
|
||||||
xhr.expect('angular2/test/compiler/compUrl.html', 'a');
|
xhr.expect('package:angular2/test/compiler/compUrl.html', 'a');
|
||||||
PromiseWrapper.all([compile([CompWithTemplateUrl]), compile([CompWithTemplateUrl])])
|
PromiseWrapper.all([compile([CompWithTemplateUrl]), compile([CompWithTemplateUrl])])
|
||||||
.then((humanizedTemplates) => {
|
.then((humanizedTemplates) => {
|
||||||
expect(humanizedTemplates[0]['commands'][1]['commands']).toEqual(['#text(a)']);
|
expect(humanizedTemplates[0]['commands'][1]['commands']).toEqual(['#text(a)']);
|
||||||
|
@ -149,7 +149,7 @@ export function main() {
|
||||||
|
|
||||||
it('should cache components for sequential requests',
|
it('should cache components for sequential requests',
|
||||||
inject([AsyncTestCompleter, XHR], (async, xhr: MockXHR) => {
|
inject([AsyncTestCompleter, XHR], (async, xhr: MockXHR) => {
|
||||||
xhr.expect('angular2/test/compiler/compUrl.html', 'a');
|
xhr.expect('package:angular2/test/compiler/compUrl.html', 'a');
|
||||||
compile([CompWithTemplateUrl])
|
compile([CompWithTemplateUrl])
|
||||||
.then((humanizedTemplate0) => {
|
.then((humanizedTemplate0) => {
|
||||||
return compile([CompWithTemplateUrl])
|
return compile([CompWithTemplateUrl])
|
||||||
|
@ -166,11 +166,11 @@ export function main() {
|
||||||
|
|
||||||
it('should allow to clear the cache',
|
it('should allow to clear the cache',
|
||||||
inject([AsyncTestCompleter, XHR], (async, xhr: MockXHR) => {
|
inject([AsyncTestCompleter, XHR], (async, xhr: MockXHR) => {
|
||||||
xhr.expect('angular2/test/compiler/compUrl.html', 'a');
|
xhr.expect('package:angular2/test/compiler/compUrl.html', 'a');
|
||||||
compile([CompWithTemplateUrl])
|
compile([CompWithTemplateUrl])
|
||||||
.then((humanizedTemplate) => {
|
.then((humanizedTemplate) => {
|
||||||
compiler.clearCache();
|
compiler.clearCache();
|
||||||
xhr.expect('angular2/test/compiler/compUrl.html', 'b');
|
xhr.expect('package:angular2/test/compiler/compUrl.html', 'b');
|
||||||
var result = compile([CompWithTemplateUrl]);
|
var result = compile([CompWithTemplateUrl]);
|
||||||
xhr.flush();
|
xhr.flush();
|
||||||
return result;
|
return result;
|
||||||
|
@ -200,8 +200,7 @@ export function main() {
|
||||||
function compile(components: Type[]): Promise<any[]> {
|
function compile(components: Type[]): Promise<any[]> {
|
||||||
return PromiseWrapper.all(components.map(normalizeComponent))
|
return PromiseWrapper.all(components.map(normalizeComponent))
|
||||||
.then((normalizedCompWithViewDirMetas: NormalizedComponentWithViewDirectives[]) => {
|
.then((normalizedCompWithViewDirMetas: NormalizedComponentWithViewDirectives[]) => {
|
||||||
var sourceModule =
|
var sourceModule = compiler.compileTemplatesCodeGen(normalizedCompWithViewDirMetas);
|
||||||
compiler.compileTemplatesCodeGen(THIS_MODULE, normalizedCompWithViewDirMetas);
|
|
||||||
var sourceWithImports =
|
var sourceWithImports =
|
||||||
testableTemplateModule(sourceModule,
|
testableTemplateModule(sourceModule,
|
||||||
normalizedCompWithViewDirMetas[0].component)
|
normalizedCompWithViewDirMetas[0].component)
|
||||||
|
@ -227,7 +226,7 @@ export function main() {
|
||||||
|
|
||||||
it('should normalize the template',
|
it('should normalize the template',
|
||||||
inject([AsyncTestCompleter, XHR], (async, xhr: MockXHR) => {
|
inject([AsyncTestCompleter, XHR], (async, xhr: MockXHR) => {
|
||||||
xhr.expect('angular2/test/compiler/compUrl.html', 'loadedTemplate');
|
xhr.expect('package:angular2/test/compiler/compUrl.html', 'loadedTemplate');
|
||||||
compiler.normalizeDirectiveMetadata(
|
compiler.normalizeDirectiveMetadata(
|
||||||
runtimeMetadataResolver.getMetadata(CompWithTemplateUrl))
|
runtimeMetadataResolver.getMetadata(CompWithTemplateUrl))
|
||||||
.then((meta: CompileDirectiveMetadata) => {
|
.then((meta: CompileDirectiveMetadata) => {
|
||||||
|
@ -260,7 +259,8 @@ export function main() {
|
||||||
describe('compileStylesheetCodeGen', () => {
|
describe('compileStylesheetCodeGen', () => {
|
||||||
it('should compile stylesheets into code', inject([AsyncTestCompleter], (async) => {
|
it('should compile stylesheets into code', inject([AsyncTestCompleter], (async) => {
|
||||||
var cssText = 'div {color: red}';
|
var cssText = 'div {color: red}';
|
||||||
var sourceModule = compiler.compileStylesheetCodeGen('someModuleId', cssText)[0];
|
var sourceModule =
|
||||||
|
compiler.compileStylesheetCodeGen('package:someModuleUrl', cssText)[0];
|
||||||
var sourceWithImports = testableStylesModule(sourceModule).getSourceWithImports();
|
var sourceWithImports = testableStylesModule(sourceModule).getSourceWithImports();
|
||||||
evalModule(sourceWithImports.source, sourceWithImports.imports, null)
|
evalModule(sourceWithImports.source, sourceWithImports.imports, null)
|
||||||
.then(loadedCssText => {
|
.then(loadedCssText => {
|
||||||
|
@ -276,52 +276,47 @@ export function main() {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'comp-a',
|
selector: 'comp-a',
|
||||||
host: {'[title]': 'someProp'},
|
host: {'[title]': 'someProp'},
|
||||||
moduleId: THIS_MODULE,
|
moduleId: THIS_MODULE_ID,
|
||||||
exportAs: 'someExportAs'
|
exportAs: 'someExportAs'
|
||||||
})
|
})
|
||||||
@View({template: '<a [href]="someProp"></a>', styles: ['div {color: red}']})
|
@View({template: '<a [href]="someProp"></a>', styles: ['div {color: red}']})
|
||||||
class CompWithBindingsAndStyles {
|
class CompWithBindingsAndStyles {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'tree', moduleId: THIS_MODULE})
|
@Component({selector: 'tree', moduleId: THIS_MODULE_ID})
|
||||||
@View({template: '<tree></tree>', directives: [TreeComp]})
|
@View({template: '<tree></tree>', directives: [TreeComp]})
|
||||||
class TreeComp {
|
class TreeComp {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'comp-url', moduleId: THIS_MODULE})
|
@Component({selector: 'comp-url', moduleId: THIS_MODULE_ID})
|
||||||
@View({templateUrl: 'compUrl.html'})
|
@View({templateUrl: 'compUrl.html'})
|
||||||
class CompWithTemplateUrl {
|
class CompWithTemplateUrl {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'comp-tpl', moduleId: THIS_MODULE})
|
@Component({selector: 'comp-tpl', moduleId: THIS_MODULE_ID})
|
||||||
@View({template: '<template><a [href]="someProp"></a></template>'})
|
@View({template: '<template><a [href]="someProp"></a></template>'})
|
||||||
class CompWithEmbeddedTemplate {
|
class CompWithEmbeddedTemplate {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Directive({selector: 'plain', moduleId: THIS_MODULE})
|
@Directive({selector: 'plain', moduleId: THIS_MODULE_ID})
|
||||||
@View({template: ''})
|
@View({template: ''})
|
||||||
class NonComponent {
|
class NonComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'comp', moduleId: THIS_MODULE})
|
|
||||||
@View({template: ''})
|
|
||||||
class CompWithoutHost {
|
|
||||||
}
|
|
||||||
|
|
||||||
function testableTemplateModule(sourceModule: SourceModule, normComp: CompileDirectiveMetadata):
|
function testableTemplateModule(sourceModule: SourceModule, normComp: CompileDirectiveMetadata):
|
||||||
SourceModule {
|
SourceModule {
|
||||||
var resultExpression =
|
var resultExpression =
|
||||||
`${THIS_MODULE_REF}humanizeTemplate(Host${normComp.type.name}Template.getTemplate())`;
|
`${THIS_MODULE_REF}humanizeTemplate(Host${normComp.type.name}Template.getTemplate())`;
|
||||||
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
||||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], resultExpression)};`;
|
${codeGenExportVariable('run')}${codeGenValueFn(['_'], resultExpression)};`;
|
||||||
return new SourceModule(sourceModule.moduleId, testableSource);
|
return new SourceModule(sourceModule.moduleUrl, testableSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testableStylesModule(sourceModule: SourceModule): SourceModule {
|
function testableStylesModule(sourceModule: SourceModule): SourceModule {
|
||||||
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
var testableSource = `${sourceModule.sourceWithModuleRefs}
|
||||||
${codeGenExportVariable('run')}${codeGenValueFn(['_'], 'STYLES')};`;
|
${codeGenExportVariable('run')}${codeGenValueFn(['_'], 'STYLES')};`;
|
||||||
return new SourceModule(sourceModule.moduleId, testableSource);
|
return new SourceModule(sourceModule.moduleUrl, testableSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attention: read by eval!
|
// Attention: read by eval!
|
||||||
|
@ -347,6 +342,11 @@ export function humanizeTemplate(template: CompiledTemplate,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestContext implements CompWithBindingsAndStyles, TreeComp, CompWithTemplateUrl,
|
||||||
|
CompWithEmbeddedTemplate {
|
||||||
|
someProp: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function testChangeDetector(changeDetectorFactory: Function): string[] {
|
function testChangeDetector(changeDetectorFactory: Function): string[] {
|
||||||
var ctx = new TestContext();
|
var ctx = new TestContext();
|
||||||
|
|
|
@ -31,7 +31,7 @@ export function main() {
|
||||||
beforeEachBindings(() => TEST_BINDINGS);
|
beforeEachBindings(() => TEST_BINDINGS);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
dirType = new CompileTypeMetadata({moduleId: 'some/module/id', name: 'SomeComp'});
|
dirType = new CompileTypeMetadata({moduleUrl: 'package:some/module/a.js', name: 'SomeComp'});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('loadTemplate', () => {
|
describe('loadTemplate', () => {
|
||||||
|
@ -48,12 +48,12 @@ export function main() {
|
||||||
}))
|
}))
|
||||||
.then((template: CompileTemplateMetadata) => {
|
.then((template: CompileTemplateMetadata) => {
|
||||||
expect(template.template).toEqual('a');
|
expect(template.template).toEqual('a');
|
||||||
expect(template.templateUrl).toEqual('some/module/id');
|
expect(template.templateUrl).toEqual('package:some/module/a.js');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve styles on the annotation against the moduleId',
|
it('should resolve styles on the annotation against the moduleUrl',
|
||||||
inject([AsyncTestCompleter, TemplateNormalizer],
|
inject([AsyncTestCompleter, TemplateNormalizer],
|
||||||
(async, normalizer: TemplateNormalizer) => {
|
(async, normalizer: TemplateNormalizer) => {
|
||||||
normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||||
|
@ -64,12 +64,12 @@ export function main() {
|
||||||
styleUrls: ['test.css']
|
styleUrls: ['test.css']
|
||||||
}))
|
}))
|
||||||
.then((template: CompileTemplateMetadata) => {
|
.then((template: CompileTemplateMetadata) => {
|
||||||
expect(template.styleUrls).toEqual(['some/module/test.css']);
|
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve styles in the template against the moduleId',
|
it('should resolve styles in the template against the moduleUrl',
|
||||||
inject([AsyncTestCompleter, TemplateNormalizer],
|
inject([AsyncTestCompleter, TemplateNormalizer],
|
||||||
(async, normalizer: TemplateNormalizer) => {
|
(async, normalizer: TemplateNormalizer) => {
|
||||||
normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||||
|
@ -80,7 +80,7 @@ export function main() {
|
||||||
styleUrls: []
|
styleUrls: []
|
||||||
}))
|
}))
|
||||||
.then((template: CompileTemplateMetadata) => {
|
.then((template: CompileTemplateMetadata) => {
|
||||||
expect(template.styleUrls).toEqual(['some/module/test.css']);
|
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -88,38 +88,39 @@ export function main() {
|
||||||
|
|
||||||
describe('templateUrl', () => {
|
describe('templateUrl', () => {
|
||||||
|
|
||||||
it('should load a template from a url that is resolved against moduleId',
|
it('should load a template from a url that is resolved against moduleUrl',
|
||||||
inject([AsyncTestCompleter, TemplateNormalizer, XHR],
|
inject([AsyncTestCompleter, TemplateNormalizer, XHR],
|
||||||
(async, normalizer: TemplateNormalizer, xhr: MockXHR) => {
|
(async, normalizer: TemplateNormalizer, xhr: MockXHR) => {
|
||||||
xhr.expect('some/module/sometplurl', 'a');
|
xhr.expect('package:some/module/sometplurl.html', 'a');
|
||||||
normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||||
encapsulation: null,
|
encapsulation: null,
|
||||||
template: null,
|
template: null,
|
||||||
templateUrl: 'sometplurl',
|
templateUrl: 'sometplurl.html',
|
||||||
styles: [],
|
styles: [],
|
||||||
styleUrls: ['test.css']
|
styleUrls: ['test.css']
|
||||||
}))
|
}))
|
||||||
.then((template: CompileTemplateMetadata) => {
|
.then((template: CompileTemplateMetadata) => {
|
||||||
expect(template.template).toEqual('a');
|
expect(template.template).toEqual('a');
|
||||||
expect(template.templateUrl).toEqual('some/module/sometplurl');
|
expect(template.templateUrl)
|
||||||
|
.toEqual('package:some/module/sometplurl.html');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
xhr.flush();
|
xhr.flush();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve styles on the annotation against the moduleId',
|
it('should resolve styles on the annotation against the moduleUrl',
|
||||||
inject([AsyncTestCompleter, TemplateNormalizer, XHR],
|
inject([AsyncTestCompleter, TemplateNormalizer, XHR],
|
||||||
(async, normalizer: TemplateNormalizer, xhr: MockXHR) => {
|
(async, normalizer: TemplateNormalizer, xhr: MockXHR) => {
|
||||||
xhr.expect('some/module/tpl/sometplurl', '');
|
xhr.expect('package:some/module/tpl/sometplurl.html', '');
|
||||||
normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||||
encapsulation: null,
|
encapsulation: null,
|
||||||
template: null,
|
template: null,
|
||||||
templateUrl: 'tpl/sometplurl',
|
templateUrl: 'tpl/sometplurl.html',
|
||||||
styles: [],
|
styles: [],
|
||||||
styleUrls: ['test.css']
|
styleUrls: ['test.css']
|
||||||
}))
|
}))
|
||||||
.then((template: CompileTemplateMetadata) => {
|
.then((template: CompileTemplateMetadata) => {
|
||||||
expect(template.styleUrls).toEqual(['some/module/test.css']);
|
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
xhr.flush();
|
xhr.flush();
|
||||||
|
@ -128,16 +129,17 @@ export function main() {
|
||||||
it('should resolve styles in the template against the templateUrl',
|
it('should resolve styles in the template against the templateUrl',
|
||||||
inject([AsyncTestCompleter, TemplateNormalizer, XHR],
|
inject([AsyncTestCompleter, TemplateNormalizer, XHR],
|
||||||
(async, normalizer: TemplateNormalizer, xhr: MockXHR) => {
|
(async, normalizer: TemplateNormalizer, xhr: MockXHR) => {
|
||||||
xhr.expect('some/module/tpl/sometplurl', '<style>@import test.css</style>');
|
xhr.expect('package:some/module/tpl/sometplurl.html',
|
||||||
|
'<style>@import test.css</style>');
|
||||||
normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({
|
||||||
encapsulation: null,
|
encapsulation: null,
|
||||||
template: null,
|
template: null,
|
||||||
templateUrl: 'tpl/sometplurl',
|
templateUrl: 'tpl/sometplurl.html',
|
||||||
styles: [],
|
styles: [],
|
||||||
styleUrls: []
|
styleUrls: []
|
||||||
}))
|
}))
|
||||||
.then((template: CompileTemplateMetadata) => {
|
.then((template: CompileTemplateMetadata) => {
|
||||||
expect(template.styleUrls).toEqual(['some/module/tpl/test.css']);
|
expect(template.styleUrls).toEqual(['package:some/module/tpl/test.css']);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
xhr.flush();
|
xhr.flush();
|
||||||
|
@ -163,7 +165,7 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType, new CompileTemplateMetadata(
|
dirType, new CompileTemplateMetadata(
|
||||||
{encapsulation: viewEncapsulation, styles: [], styleUrls: []}),
|
{encapsulation: viewEncapsulation, styles: [], styleUrls: []}),
|
||||||
'', 'some/module/');
|
'', 'package:some/module/');
|
||||||
expect(template.encapsulation).toBe(viewEncapsulation);
|
expect(template.encapsulation).toBe(viewEncapsulation);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -172,7 +174,7 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType,
|
dirType,
|
||||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), 'a',
|
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), 'a',
|
||||||
'some/module/');
|
'package:some/module/');
|
||||||
expect(template.template).toEqual('a')
|
expect(template.template).toEqual('a')
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -181,7 +183,7 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType,
|
dirType,
|
||||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||||
'<ng-content select="a"></ng-content>', 'some/module/');
|
'<ng-content select="a"></ng-content>', 'package:some/module/');
|
||||||
expect(template.ngContentSelectors).toEqual(['a']);
|
expect(template.ngContentSelectors).toEqual(['a']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -191,7 +193,7 @@ export function main() {
|
||||||
dirType,
|
dirType,
|
||||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||||
'<ng-content></ng-content><ng-content select></ng-content><ng-content select="*"></ng-content>',
|
'<ng-content></ng-content><ng-content select></ng-content><ng-content select="*"></ng-content>',
|
||||||
'some/module/');
|
'package:some/module/');
|
||||||
expect(template.ngContentSelectors).toEqual(['*', '*', '*']);
|
expect(template.ngContentSelectors).toEqual(['*', '*', '*']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -200,7 +202,7 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType,
|
dirType,
|
||||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||||
'<style>a</style>', 'some/module/');
|
'<style>a</style>', 'package:some/module/');
|
||||||
expect(template.styles).toEqual(['a']);
|
expect(template.styles).toEqual(['a']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -209,7 +211,7 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType,
|
dirType,
|
||||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||||
'<div><style>a</style></div>', 'some/module/');
|
'<div><style>a</style></div>', 'package:some/module/');
|
||||||
expect(template.styles).toEqual(['a']);
|
expect(template.styles).toEqual(['a']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -218,8 +220,8 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType,
|
dirType,
|
||||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||||
'<link rel="stylesheet" href="aUrl">', 'some/module/');
|
'<link rel="stylesheet" href="aUrl">', 'package:some/module/');
|
||||||
expect(template.styleUrls).toEqual(['some/module/aUrl']);
|
expect(template.styleUrls).toEqual(['package:some/module/aUrl']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should collect styleUrls in elements',
|
it('should collect styleUrls in elements',
|
||||||
|
@ -227,8 +229,8 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType,
|
dirType,
|
||||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||||
'<div><link rel="stylesheet" href="aUrl"></div>', 'some/module/');
|
'<div><link rel="stylesheet" href="aUrl"></div>', 'package:some/module/');
|
||||||
expect(template.styleUrls).toEqual(['some/module/aUrl']);
|
expect(template.styleUrls).toEqual(['package:some/module/aUrl']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should ignore link elements with non stylesheet rel attribute',
|
it('should ignore link elements with non stylesheet rel attribute',
|
||||||
|
@ -236,7 +238,7 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType,
|
dirType,
|
||||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||||
'<link href="b" rel="a"></link>', 'some/module/');
|
'<link href="b" rel="a"></link>', 'package:some/module/');
|
||||||
expect(template.styleUrls).toEqual([]);
|
expect(template.styleUrls).toEqual([]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -245,9 +247,9 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType, new CompileTemplateMetadata(
|
dirType, new CompileTemplateMetadata(
|
||||||
{encapsulation: null, styles: ['@import "test.css";'], styleUrls: []}),
|
{encapsulation: null, styles: ['@import "test.css";'], styleUrls: []}),
|
||||||
'', 'some/module/id');
|
'', 'package:some/module/id');
|
||||||
expect(template.styles).toEqual(['']);
|
expect(template.styles).toEqual(['']);
|
||||||
expect(template.styleUrls).toEqual(['some/module/test.css']);
|
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve relative urls in inline styles',
|
it('should resolve relative urls in inline styles',
|
||||||
|
@ -258,9 +260,9 @@ export function main() {
|
||||||
styles: ['.foo{background-image: url(\'double.jpg\');'],
|
styles: ['.foo{background-image: url(\'double.jpg\');'],
|
||||||
styleUrls: []
|
styleUrls: []
|
||||||
}),
|
}),
|
||||||
'', 'some/module/id');
|
'', 'package:some/module/id');
|
||||||
expect(template.styles)
|
expect(template.styles)
|
||||||
.toEqual(['.foo{background-image: url(\'some/module/double.jpg\');']);
|
.toEqual(['.foo{background-image: url(\'package:some/module/double.jpg\');']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve relative style urls in styleUrls',
|
it('should resolve relative style urls in styleUrls',
|
||||||
|
@ -268,9 +270,9 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType, new CompileTemplateMetadata(
|
dirType, new CompileTemplateMetadata(
|
||||||
{encapsulation: null, styles: [], styleUrls: ['test.css']}),
|
{encapsulation: null, styles: [], styleUrls: ['test.css']}),
|
||||||
'', 'some/module/id');
|
'', 'package:some/module/id');
|
||||||
expect(template.styles).toEqual([]);
|
expect(template.styles).toEqual([]);
|
||||||
expect(template.styleUrls).toEqual(['some/module/test.css']);
|
expect(template.styleUrls).toEqual(['package:some/module/test.css']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should normalize ViewEncapsulation.Emulated to ViewEncapsulation.None if there are no stlyes nor stylesheets',
|
it('should normalize ViewEncapsulation.Emulated to ViewEncapsulation.None if there are no stlyes nor stylesheets',
|
||||||
|
@ -278,7 +280,7 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType, new CompileTemplateMetadata(
|
dirType, new CompileTemplateMetadata(
|
||||||
{encapsulation: ViewEncapsulation.Emulated, styles: [], styleUrls: []}),
|
{encapsulation: ViewEncapsulation.Emulated, styles: [], styleUrls: []}),
|
||||||
'', 'some/module/id');
|
'', 'package:some/module/id');
|
||||||
expect(template.encapsulation).toEqual(ViewEncapsulation.None);
|
expect(template.encapsulation).toEqual(ViewEncapsulation.None);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -287,7 +289,8 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType,
|
dirType,
|
||||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||||
'<div ng-non-bindable><ng-content select="a"></ng-content></div>', 'some/module/');
|
'<div ng-non-bindable><ng-content select="a"></ng-content></div>',
|
||||||
|
'package:some/module/');
|
||||||
expect(template.ngContentSelectors).toEqual([]);
|
expect(template.ngContentSelectors).toEqual([]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -296,7 +299,7 @@ export function main() {
|
||||||
var template = normalizer.normalizeLoadedTemplate(
|
var template = normalizer.normalizeLoadedTemplate(
|
||||||
dirType,
|
dirType,
|
||||||
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}),
|
||||||
'<div ng-non-bindable><style>div {color:red}</style></div>', 'some/module/');
|
'<div ng-non-bindable><style>div {color:red}</style></div>', 'package:some/module/');
|
||||||
expect(template.styles).toEqual(['div {color:red}']);
|
expect(template.styles).toEqual(['div {color:red}']);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
|
@ -101,8 +101,8 @@ export function main() {
|
||||||
|
|
||||||
PromiseWrapper.then(refPromise, null, (exception) => {
|
PromiseWrapper.then(refPromise, null, (exception) => {
|
||||||
expect(exception).toContainError(
|
expect(exception).toContainError(
|
||||||
`Could not load '${stringify(HelloRootDirectiveIsNotCmp)}' because it is not a component.`);
|
`Could not compile '${stringify(HelloRootDirectiveIsNotCmp)}' because it is not a component.`);
|
||||||
expect(logger.res.join("")).toContain("Could not load");
|
expect(logger.res.join("")).toContain("Could not compile");
|
||||||
async.done();
|
async.done();
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
library angular2.src.transform.di_transformer;
|
library angular2.test.core.change_detection.generator;
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
|
@ -1,752 +1,63 @@
|
||||||
import {
|
import {
|
||||||
AsyncTestCompleter,
|
|
||||||
beforeEach,
|
|
||||||
xdescribe,
|
|
||||||
ddescribe,
|
ddescribe,
|
||||||
describe,
|
describe,
|
||||||
el,
|
xdescribe,
|
||||||
expect,
|
it,
|
||||||
iit,
|
iit,
|
||||||
|
xit,
|
||||||
|
expect,
|
||||||
|
beforeEach,
|
||||||
|
afterEach,
|
||||||
|
AsyncTestCompleter,
|
||||||
inject,
|
inject,
|
||||||
it
|
beforeEachBindings
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
import {SpyRenderCompiler, SpyDirectiveResolver} from '../spies';
|
|
||||||
import {ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
|
||||||
import {Type, isBlank, stringify, isPresent, isArray} from 'angular2/src/core/facade/lang';
|
|
||||||
import {PromiseCompleter, PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
|
|
||||||
|
|
||||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
import {Component, View, bind} from 'angular2/core';
|
||||||
import {AppProtoView} from 'angular2/src/core/compiler/view';
|
import {SpyProtoViewFactory} from '../spies';
|
||||||
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
|
|
||||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
|
||||||
import {PipeResolver} from 'angular2/src/core/compiler/pipe_resolver';
|
|
||||||
import {Attribute, ViewMetadata, Component, Directive, Pipe} from 'angular2/src/core/metadata';
|
|
||||||
import {internalProtoView} from 'angular2/src/core/compiler/view_ref';
|
|
||||||
import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
|
||||||
import {ViewResolver} from 'angular2/src/core/compiler/view_resolver';
|
|
||||||
import {
|
import {
|
||||||
ComponentUrlMapper,
|
CompiledHostTemplate,
|
||||||
RuntimeComponentUrlMapper
|
CompiledTemplate,
|
||||||
} from 'angular2/src/core/compiler/component_url_mapper';
|
BeginComponentCmd
|
||||||
|
} from 'angular2/src/core/compiler/template_commands';
|
||||||
|
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
||||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||||
|
import {reflector, ReflectionInfo} from 'angular2/src/core/reflection/reflection';
|
||||||
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
|
import {AppProtoView} from 'angular2/src/core/compiler/view';
|
||||||
import {AppRootUrl} from 'angular2/src/core/services/app_root_url';
|
|
||||||
import {
|
|
||||||
ProtoViewDto,
|
|
||||||
ViewType,
|
|
||||||
RenderProtoViewRef,
|
|
||||||
ViewDefinition,
|
|
||||||
RenderProtoViewMergeMapping,
|
|
||||||
RenderDirectiveMetadata,
|
|
||||||
DirectiveBinder,
|
|
||||||
RenderElementBinder
|
|
||||||
} from 'angular2/src/core/render/api';
|
|
||||||
// TODO(tbosch): Spys don't support named modules...
|
|
||||||
import {PipeBinding} from 'angular2/src/core/pipes/pipe_binding';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('compiler', function() {
|
describe('Compiler', () => {
|
||||||
var directiveResolver, pipeResolver, tplResolver, renderCompiler, protoViewFactory,
|
var compiler: Compiler;
|
||||||
cmpUrlMapper, rootProtoView;
|
var protoViewFactorySpy;
|
||||||
var renderCompileRequests: any[];
|
var someProtoView;
|
||||||
|
var cht: CompiledHostTemplate;
|
||||||
|
|
||||||
function createCompiler(renderCompileResults: Array<ProtoViewDto | Promise<ProtoViewDto>>,
|
beforeEachBindings(() => {
|
||||||
protoViewFactoryResults: AppProtoView[]) {
|
protoViewFactorySpy = new SpyProtoViewFactory();
|
||||||
var urlResolver = new UrlResolver();
|
someProtoView = new AppProtoView(null, null, null, null, null, null);
|
||||||
renderCompileRequests = [];
|
protoViewFactorySpy.spy('createHost').andReturn(someProtoView);
|
||||||
renderCompileResults = ListWrapper.clone(renderCompileResults);
|
return [bind(ProtoViewFactory).toValue(protoViewFactorySpy), Compiler];
|
||||||
renderCompiler.spy('compile').andCallFake((view) => {
|
|
||||||
renderCompileRequests.push(view);
|
|
||||||
return PromiseWrapper.resolve(ListWrapper.removeAt(renderCompileResults, 0));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
protoViewFactory = new FakeProtoViewFactory(protoViewFactoryResults);
|
beforeEach(inject([Compiler], (_compiler) => {
|
||||||
return new Compiler(directiveResolver, pipeResolver, [SomeDefaultPipe], new CompilerCache(),
|
compiler = _compiler;
|
||||||
tplResolver, cmpUrlMapper, urlResolver, renderCompiler, protoViewFactory,
|
cht = new CompiledHostTemplate(() => new CompiledTemplate(23, null));
|
||||||
new AppRootUrl("http://www.app.com"));
|
reflector.registerType(SomeComponent, new ReflectionInfo([cht]));
|
||||||
}
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
it('should read the template from an annotation', inject([AsyncTestCompleter], (async) => {
|
||||||
directiveResolver = new DirectiveResolver();
|
compiler.compileInHost(SomeComponent)
|
||||||
pipeResolver = new PipeResolver();
|
|
||||||
tplResolver = new FakeViewResolver();
|
|
||||||
cmpUrlMapper = new RuntimeComponentUrlMapper();
|
|
||||||
renderCompiler = new SpyRenderCompiler();
|
|
||||||
renderCompiler.spy('compileHost')
|
|
||||||
.andCallFake((componentId) => {
|
|
||||||
return PromiseWrapper.resolve(
|
|
||||||
createRenderProtoView([createRenderComponentElementBinder(0)], ViewType.HOST));
|
|
||||||
});
|
|
||||||
renderCompiler.spy('mergeProtoViewsRecursively')
|
|
||||||
.andCallFake((protoViewRefs: Array<RenderProtoViewRef | any[]>) => {
|
|
||||||
return PromiseWrapper.resolve(new RenderProtoViewMergeMapping(
|
|
||||||
new MergedRenderProtoViewRef(protoViewRefs), 1, [], 0, [], [], [null]));
|
|
||||||
});
|
|
||||||
// TODO spy on .compile and return RenderProtoViewRef, same for compileHost
|
|
||||||
rootProtoView = createRootProtoView(directiveResolver, MainComponent);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('serialize template', () => {
|
|
||||||
|
|
||||||
function captureTemplate(template: ViewMetadata): Promise<ViewDefinition> {
|
|
||||||
tplResolver.setView(MainComponent, template);
|
|
||||||
var compiler =
|
|
||||||
createCompiler([createRenderProtoView()], [rootProtoView, createProtoView()]);
|
|
||||||
return compiler.compileInHost(MainComponent)
|
|
||||||
.then((_) => {
|
.then((_) => {
|
||||||
expect(renderCompileRequests.length).toBe(1);
|
expect(protoViewFactorySpy.spy('createHost')).toHaveBeenCalledWith(cht);
|
||||||
return renderCompileRequests[0];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function captureDirective(directive): Promise<RenderDirectiveMetadata> {
|
|
||||||
return captureTemplate(new ViewMetadata({template: '<div></div>', directives: [directive]}))
|
|
||||||
.then((renderTpl) => {
|
|
||||||
expect(renderTpl.directives.length).toBe(1);
|
|
||||||
return renderTpl.directives[0];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should fill the componentId', inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureTemplate(new ViewMetadata({template: '<div></div>'}))
|
|
||||||
.then((renderTpl) => {
|
|
||||||
expect(renderTpl.componentId).toEqual(stringify(MainComponent));
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should fill inline template', inject([AsyncTestCompleter], (async) => {
|
it('should clear the cache', () => {
|
||||||
captureTemplate(new ViewMetadata({template: '<div></div>'}))
|
compiler.clearCache();
|
||||||
.then((renderTpl) => {
|
expect(protoViewFactorySpy.spy('clearCache')).toHaveBeenCalled();
|
||||||
expect(renderTpl.template).toEqual('<div></div>');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should fill templateAbsUrl given inline templates',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
|
||||||
captureTemplate(new ViewMetadata({template: '<div></div>'}))
|
|
||||||
.then((renderTpl) => {
|
|
||||||
expect(renderTpl.templateAbsUrl).toEqual('http://www.app.com/cmp/main.js');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should not fill templateAbsUrl given no inline template or template url',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
|
||||||
captureTemplate(new ViewMetadata({template: null, templateUrl: null}))
|
|
||||||
.then((renderTpl) => {
|
|
||||||
expect(renderTpl.templateAbsUrl).toBe(null);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should not fill templateAbsUrl given template url with empty string',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
|
||||||
captureTemplate(new ViewMetadata({template: null, templateUrl: ''}))
|
|
||||||
.then((renderTpl) => {
|
|
||||||
expect(renderTpl.templateAbsUrl).toBe(null);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should not fill templateAbsUrl given template url with blank string',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
|
||||||
captureTemplate(new ViewMetadata({template: null, templateUrl: ' '}))
|
|
||||||
.then((renderTpl) => {
|
|
||||||
expect(renderTpl.templateAbsUrl).toBe(null);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should fill templateAbsUrl given url template', inject([AsyncTestCompleter], (async) => {
|
|
||||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
|
||||||
captureTemplate(new ViewMetadata({templateUrl: 'tpl/main.html'}))
|
|
||||||
.then((renderTpl) => {
|
|
||||||
expect(renderTpl.templateAbsUrl).toEqual('http://www.app.com/cmp/tpl/main.html');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should fill styleAbsUrls given styleUrls', inject([AsyncTestCompleter], (async) => {
|
|
||||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
|
||||||
captureTemplate(new ViewMetadata({styleUrls: ['css/1.css', 'css/2.css']}))
|
|
||||||
.then((renderTpl) => {
|
|
||||||
expect(renderTpl.styleAbsUrls)
|
|
||||||
.toEqual(
|
|
||||||
['http://www.app.com/cmp/css/1.css', 'http://www.app.com/cmp/css/2.css']);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should fill directive.id', inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(MainComponent)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.id).toEqual(stringify(MainComponent));
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should fill directive.selector', inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(MainComponent)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.selector).toEqual('main-comp');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should fill directive.type for components', inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(MainComponent)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.type).toEqual(RenderDirectiveMetadata.COMPONENT_TYPE);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should fill directive.type for dynamic components',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(SomeDynamicComponentDirective)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.type).toEqual(RenderDirectiveMetadata.COMPONENT_TYPE);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should fill directive.type for decorator directives',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(SomeDirective)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.type).toEqual(RenderDirectiveMetadata.DIRECTIVE_TYPE);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set directive.compileChildren to false for other directives',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(MainComponent)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.compileChildren).toEqual(true);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set directive.compileChildren to true for decorator directives',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(SomeDirective)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.compileChildren).toEqual(true);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set directive.compileChildren to false for decorator directives',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(IgnoreChildrenDirective)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.compileChildren).toEqual(false);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set directive.hostListeners', inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(DirectiveWithEvents)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.hostListeners)
|
|
||||||
.toEqual(MapWrapper.createFromStringMap({'someEvent': 'someAction'}));
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set directive.hostProperties', inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(DirectiveWithProperties)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.hostProperties)
|
|
||||||
.toEqual(MapWrapper.createFromStringMap({'someProp': 'someExp'}));
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set directive.bind', inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(DirectiveWithBind)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.inputs).toEqual(['a: b']);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should read @Attribute', inject([AsyncTestCompleter], (async) => {
|
|
||||||
captureDirective(DirectiveWithAttributes)
|
|
||||||
.then((renderDir) => {
|
|
||||||
expect(renderDir.readAttributes).toEqual(['someAttr']);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('call ProtoViewFactory', () => {
|
|
||||||
|
|
||||||
it('should pass the ProtoViewDto', inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var renderProtoView = createRenderProtoView();
|
|
||||||
var expectedProtoView = createProtoView();
|
|
||||||
var compiler = createCompiler([renderProtoView], [rootProtoView, expectedProtoView]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((_) => {
|
|
||||||
var request = protoViewFactory.requests[1];
|
|
||||||
expect(request[1]).toBe(renderProtoView);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should pass the component binding', inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var compiler =
|
|
||||||
createCompiler([createRenderProtoView()], [rootProtoView, createProtoView()]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((_) => {
|
|
||||||
var request = protoViewFactory.requests[1];
|
|
||||||
expect(request[0].key.token).toBe(MainComponent);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should pass the directive bindings', inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(
|
|
||||||
MainComponent,
|
|
||||||
new ViewMetadata({template: '<div></div>', directives: [SomeDirective]}));
|
|
||||||
var compiler =
|
|
||||||
createCompiler([createRenderProtoView()], [rootProtoView, createProtoView()]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((_) => {
|
|
||||||
var request = protoViewFactory.requests[1];
|
|
||||||
var binding = request[2][0];
|
|
||||||
expect(binding.key.token).toBe(SomeDirective);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should pass the pipe bindings', inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent,
|
|
||||||
new ViewMetadata({template: '<div></div>', pipes: [SomePipe]}));
|
|
||||||
var compiler =
|
|
||||||
createCompiler([createRenderProtoView()], [rootProtoView, createProtoView()]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((_) => {
|
|
||||||
var request = protoViewFactory.requests[1];
|
|
||||||
expect(request[3][0].key.token).toBe(SomeDefaultPipe);
|
|
||||||
expect(request[3][1].key.token).toBe(SomePipe);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should use the protoView of the ProtoViewFactory',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var compiler =
|
|
||||||
createCompiler([createRenderProtoView()], [rootProtoView, createProtoView()]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((protoViewRef) => {
|
|
||||||
expect(internalProtoView(protoViewRef)).toBe(rootProtoView);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should load nested components', inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
tplResolver.setView(NestedComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var mainProtoView =
|
|
||||||
createProtoView([createComponentElementBinder(directiveResolver, NestedComponent)]);
|
|
||||||
var nestedProtoView = createProtoView();
|
|
||||||
var renderPvDtos = [
|
|
||||||
createRenderProtoView([createRenderComponentElementBinder(0)]),
|
|
||||||
createRenderProtoView()
|
|
||||||
];
|
|
||||||
var compiler =
|
|
||||||
createCompiler(renderPvDtos, [rootProtoView, mainProtoView, nestedProtoView]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((protoViewRef) => {
|
|
||||||
expect(originalRenderProtoViewRefs(internalProtoView(protoViewRef)))
|
|
||||||
.toEqual(
|
|
||||||
[rootProtoView.render, [mainProtoView.render, [nestedProtoView.render]]]);
|
|
||||||
expect(internalProtoView(protoViewRef).elementBinders[0].nestedProtoView)
|
|
||||||
.toBe(mainProtoView);
|
|
||||||
expect(mainProtoView.elementBinders[0].nestedProtoView).toBe(nestedProtoView);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should load nested components in viewcontainers', inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
tplResolver.setView(NestedComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var viewportProtoView = createProtoView(
|
|
||||||
[createComponentElementBinder(directiveResolver, NestedComponent)], ViewType.EMBEDDED);
|
|
||||||
var mainProtoView = createProtoView([createViewportElementBinder(viewportProtoView)]);
|
|
||||||
var nestedProtoView = createProtoView();
|
|
||||||
var renderPvDtos = [
|
|
||||||
createRenderProtoView([
|
|
||||||
createRenderViewportElementBinder(
|
|
||||||
createRenderProtoView([createRenderComponentElementBinder(0)], ViewType.EMBEDDED))
|
|
||||||
]),
|
|
||||||
createRenderProtoView()
|
|
||||||
];
|
|
||||||
var compiler =
|
|
||||||
createCompiler(renderPvDtos, [rootProtoView, mainProtoView, nestedProtoView]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((protoViewRef) => {
|
|
||||||
expect(internalProtoView(protoViewRef).elementBinders[0].nestedProtoView)
|
|
||||||
.toBe(mainProtoView);
|
|
||||||
expect(originalRenderProtoViewRefs(internalProtoView(protoViewRef)))
|
|
||||||
.toEqual([rootProtoView.render, [mainProtoView.render, null]]);
|
|
||||||
expect(viewportProtoView.elementBinders[0].nestedProtoView).toBe(nestedProtoView);
|
|
||||||
expect(originalRenderProtoViewRefs(viewportProtoView))
|
|
||||||
.toEqual([viewportProtoView.render, [nestedProtoView.render]]);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should cache compiled host components', inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var mainPv = createProtoView();
|
|
||||||
var compiler = createCompiler([createRenderProtoView([])], [rootProtoView, mainPv]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((protoViewRef) => {
|
|
||||||
expect(internalProtoView(protoViewRef).elementBinders[0].nestedProtoView)
|
|
||||||
.toBe(mainPv);
|
|
||||||
return compiler.compileInHost(MainComponent);
|
|
||||||
})
|
|
||||||
.then((protoViewRef) => {
|
|
||||||
expect(internalProtoView(protoViewRef).elementBinders[0].nestedProtoView)
|
|
||||||
.toBe(mainPv);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should not bind directives for cached components', inject([AsyncTestCompleter], (async) => {
|
|
||||||
// set up the cache with the test proto view
|
|
||||||
var mainPv: AppProtoView = createProtoView();
|
|
||||||
var cache: CompilerCache = new CompilerCache();
|
|
||||||
cache.setHost(MainComponent, mainPv);
|
|
||||||
|
|
||||||
// create the spy resolver
|
|
||||||
var reader: any = new SpyDirectiveResolver();
|
|
||||||
|
|
||||||
// create the compiler
|
|
||||||
var compiler = new Compiler(reader, pipeResolver, [], cache, tplResolver, cmpUrlMapper,
|
|
||||||
new UrlResolver(), renderCompiler, protoViewFactory,
|
|
||||||
new AppRootUrl("http://www.app.com"));
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((protoViewRef) => {
|
|
||||||
// the test should have failed if the resolver was called, so we're good
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should cache compiled nested components', inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
tplResolver.setView(MainComponent2, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
tplResolver.setView(NestedComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var rootProtoView2 = createRootProtoView(directiveResolver, MainComponent2);
|
|
||||||
var mainPv =
|
|
||||||
createProtoView([createComponentElementBinder(directiveResolver, NestedComponent)]);
|
|
||||||
var nestedPv = createProtoView([]);
|
|
||||||
var compiler = createCompiler(
|
|
||||||
[createRenderProtoView(), createRenderProtoView(), createRenderProtoView()],
|
|
||||||
[rootProtoView, mainPv, nestedPv, rootProtoView2, mainPv]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((protoViewRef) => {
|
|
||||||
expect(internalProtoView(protoViewRef)
|
|
||||||
.elementBinders[0]
|
|
||||||
.nestedProtoView.elementBinders[0]
|
|
||||||
.nestedProtoView)
|
|
||||||
.toBe(nestedPv);
|
|
||||||
return compiler.compileInHost(MainComponent2);
|
|
||||||
})
|
|
||||||
.then((protoViewRef) => {
|
|
||||||
expect(internalProtoView(protoViewRef)
|
|
||||||
.elementBinders[0]
|
|
||||||
.nestedProtoView.elementBinders[0]
|
|
||||||
.nestedProtoView)
|
|
||||||
.toBe(nestedPv);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should re-use components being compiled', inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var renderProtoViewCompleter: PromiseCompleter<ProtoViewDto> = PromiseWrapper.completer();
|
|
||||||
var expectedProtoView = createProtoView();
|
|
||||||
var compiler = createCompiler([renderProtoViewCompleter.promise],
|
|
||||||
[rootProtoView, rootProtoView, expectedProtoView]);
|
|
||||||
var result = PromiseWrapper.all([
|
|
||||||
compiler.compileInHost(MainComponent),
|
|
||||||
compiler.compileInHost(MainComponent),
|
|
||||||
renderProtoViewCompleter.promise
|
|
||||||
]);
|
|
||||||
renderProtoViewCompleter.resolve(createRenderProtoView());
|
|
||||||
result.then((protoViewRefs) => {
|
|
||||||
expect(internalProtoView(protoViewRefs[0]).elementBinders[0].nestedProtoView)
|
|
||||||
.toBe(expectedProtoView);
|
|
||||||
expect(internalProtoView(protoViewRefs[1]).elementBinders[0].nestedProtoView)
|
|
||||||
.toBe(expectedProtoView);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should throw on unconditional recursive components',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var mainProtoView =
|
|
||||||
createProtoView([createComponentElementBinder(directiveResolver, MainComponent)]);
|
|
||||||
var compiler =
|
|
||||||
createCompiler([createRenderProtoView([createRenderComponentElementBinder(0)])],
|
|
||||||
[rootProtoView, mainProtoView]);
|
|
||||||
PromiseWrapper.catchError(compiler.compileInHost(MainComponent), (e) => {
|
|
||||||
expect(() => { throw e; })
|
|
||||||
.toThrowError(`Unconditional component cycle in ${stringify(MainComponent)}`);
|
|
||||||
async.done();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should allow recursive components that are connected via an embedded ProtoView',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var viewportProtoView = createProtoView(
|
|
||||||
[createComponentElementBinder(directiveResolver, MainComponent)], ViewType.EMBEDDED);
|
|
||||||
var mainProtoView = createProtoView([createViewportElementBinder(viewportProtoView)]);
|
|
||||||
var renderPvDtos = [
|
|
||||||
createRenderProtoView([
|
|
||||||
createRenderViewportElementBinder(
|
|
||||||
createRenderProtoView([createRenderComponentElementBinder(0)], ViewType.EMBEDDED))
|
|
||||||
]),
|
|
||||||
createRenderProtoView()
|
|
||||||
];
|
|
||||||
var compiler = createCompiler(renderPvDtos, [rootProtoView, mainProtoView]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((protoViewRef) => {
|
|
||||||
expect(internalProtoView(protoViewRef).elementBinders[0].nestedProtoView)
|
|
||||||
.toBe(mainProtoView);
|
|
||||||
expect(mainProtoView.elementBinders[0]
|
|
||||||
.nestedProtoView.elementBinders[0]
|
|
||||||
.nestedProtoView)
|
|
||||||
.toBe(mainProtoView);
|
|
||||||
// In case of a cycle, don't merge the embedded proto views into the component!
|
|
||||||
expect(originalRenderProtoViewRefs(internalProtoView(protoViewRef)))
|
|
||||||
.toEqual([rootProtoView.render, [mainProtoView.render, null]]);
|
|
||||||
expect(originalRenderProtoViewRefs(viewportProtoView))
|
|
||||||
.toEqual([viewportProtoView.render, [mainProtoView.render, null]]);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should throw on recursive components that are connected via an embedded ProtoView with <ng-content>',
|
|
||||||
inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var viewportProtoView =
|
|
||||||
createProtoView([createComponentElementBinder(directiveResolver, MainComponent)],
|
|
||||||
ViewType.EMBEDDED, true);
|
|
||||||
var mainProtoView = createProtoView([createViewportElementBinder(viewportProtoView)]);
|
|
||||||
var renderPvDtos = [
|
|
||||||
createRenderProtoView([
|
|
||||||
createRenderViewportElementBinder(
|
|
||||||
createRenderProtoView([createRenderComponentElementBinder(0)], ViewType.EMBEDDED))
|
|
||||||
]),
|
|
||||||
createRenderProtoView()
|
|
||||||
];
|
|
||||||
var compiler = createCompiler(renderPvDtos, [rootProtoView, mainProtoView]);
|
|
||||||
PromiseWrapper.catchError(compiler.compileInHost(MainComponent), (e) => {
|
|
||||||
expect(() => { throw e; })
|
|
||||||
.toThrowError(
|
|
||||||
`<ng-content> is used within the recursive path of ${stringify(MainComponent)}`);
|
|
||||||
async.done();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should create host proto views', inject([AsyncTestCompleter], (async) => {
|
|
||||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
|
||||||
var rootProtoView = createProtoView(
|
|
||||||
[createComponentElementBinder(directiveResolver, MainComponent)], ViewType.HOST);
|
|
||||||
var mainProtoView = createProtoView();
|
|
||||||
var compiler = createCompiler([createRenderProtoView()], [rootProtoView, mainProtoView]);
|
|
||||||
compiler.compileInHost(MainComponent)
|
|
||||||
.then((protoViewRef) => {
|
|
||||||
expect(internalProtoView(protoViewRef)).toBe(rootProtoView);
|
|
||||||
expect(rootProtoView.elementBinders[0].nestedProtoView).toBe(mainProtoView);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should throw for non component types', () => {
|
|
||||||
var compiler = createCompiler([], []);
|
|
||||||
expect(() => compiler.compileInHost(SomeDirective))
|
|
||||||
.toThrowError(
|
|
||||||
`Could not load '${stringify(SomeDirective)}' because it is not a component.`);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDirectiveBinding(directiveResolver, type): DirectiveBinding {
|
class SomeComponent {}
|
||||||
var annotation = directiveResolver.resolve(type);
|
|
||||||
return DirectiveBinding.createFromType(type, annotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createProtoView(elementBinders = null, type: ViewType = null,
|
|
||||||
isEmbeddedFragment: boolean = false): AppProtoView {
|
|
||||||
if (isBlank(type)) {
|
|
||||||
type = ViewType.COMPONENT;
|
|
||||||
}
|
|
||||||
var pv = new AppProtoView(type, isEmbeddedFragment, new RenderProtoViewRef(), null, null,
|
|
||||||
new Map<string, number>(), null, null);
|
|
||||||
if (isBlank(elementBinders)) {
|
|
||||||
elementBinders = [];
|
|
||||||
}
|
|
||||||
pv.elementBinders = elementBinders;
|
|
||||||
return pv;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createComponentElementBinder(directiveResolver, type): ElementBinder {
|
|
||||||
var binding = createDirectiveBinding(directiveResolver, type);
|
|
||||||
return new ElementBinder(0, null, 0, null, binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createViewportElementBinder(nestedProtoView): ElementBinder {
|
|
||||||
var elBinder = new ElementBinder(0, null, 0, null, null);
|
|
||||||
elBinder.nestedProtoView = nestedProtoView;
|
|
||||||
return elBinder;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createRenderProtoView(elementBinders = null, type: ViewType = null): ProtoViewDto {
|
|
||||||
if (isBlank(type)) {
|
|
||||||
type = ViewType.COMPONENT;
|
|
||||||
}
|
|
||||||
if (isBlank(elementBinders)) {
|
|
||||||
elementBinders = [];
|
|
||||||
}
|
|
||||||
return new ProtoViewDto(
|
|
||||||
{elementBinders: elementBinders, type: type, render: new RenderProtoViewRef()});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createRenderComponentElementBinder(directiveIndex): RenderElementBinder {
|
|
||||||
return new RenderElementBinder(
|
|
||||||
{directives: [new DirectiveBinder({directiveIndex: directiveIndex})]});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createRenderViewportElementBinder(nestedProtoView): RenderElementBinder {
|
|
||||||
return new RenderElementBinder({nestedProtoView: nestedProtoView});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createRootProtoView(directiveResolver, type): AppProtoView {
|
|
||||||
return createProtoView([createComponentElementBinder(directiveResolver, type)], ViewType.HOST);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({selector: 'main-comp'})
|
|
||||||
class MainComponent {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({selector: 'main-comp2'})
|
|
||||||
class MainComponent2 {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({selector: 'nested'})
|
|
||||||
class NestedComponent {
|
|
||||||
}
|
|
||||||
|
|
||||||
class RecursiveComponent {}
|
|
||||||
|
|
||||||
@Component({selector: 'some-dynamic'})
|
|
||||||
class SomeDynamicComponentDirective {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Directive({selector: 'some'})
|
|
||||||
class SomeDirective {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Directive({compileChildren: false})
|
|
||||||
class IgnoreChildrenDirective {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Directive({host: {'(someEvent)': 'someAction'}})
|
|
||||||
class DirectiveWithEvents {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Directive({host: {'[someProp]': 'someExp'}})
|
|
||||||
class DirectiveWithProperties {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Directive({inputs: ['a: b']})
|
|
||||||
class DirectiveWithBind {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Pipe({name: 'some-default-pipe'})
|
|
||||||
class SomeDefaultPipe {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Pipe({name: 'some-pipe'})
|
|
||||||
class SomePipe {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Directive({selector: 'directive-with-accts'})
|
|
||||||
class DirectiveWithAttributes {
|
|
||||||
constructor(@Attribute('someAttr') someAttr: String) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FakeViewResolver extends ViewResolver {
|
|
||||||
_cmpViews = new Map<Type, ViewMetadata>();
|
|
||||||
|
|
||||||
constructor() { super(); }
|
|
||||||
|
|
||||||
resolve(component: Type): ViewMetadata {
|
|
||||||
// returns null for dynamic components
|
|
||||||
return this._cmpViews.has(component) ? this._cmpViews.get(component) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
setView(component: Type, view: ViewMetadata): void { this._cmpViews.set(component, view); }
|
|
||||||
}
|
|
||||||
|
|
||||||
class FakeProtoViewFactory extends ProtoViewFactory {
|
|
||||||
requests: any[][];
|
|
||||||
|
|
||||||
constructor(public results: AppProtoView[]) {
|
|
||||||
super(null);
|
|
||||||
this.requests = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
createAppProtoViews(componentBinding: DirectiveBinding, renderProtoView: ProtoViewDto,
|
|
||||||
directives: DirectiveBinding[], pipes: PipeBinding[]): AppProtoView[] {
|
|
||||||
this.requests.push([componentBinding, renderProtoView, directives, pipes]);
|
|
||||||
return collectEmbeddedPvs(ListWrapper.removeAt(this.results, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MergedRenderProtoViewRef extends RenderProtoViewRef {
|
|
||||||
constructor(public originals: RenderProtoViewRef[]) { super(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
function originalRenderProtoViewRefs(appProtoView: AppProtoView) {
|
|
||||||
return (<MergedRenderProtoViewRef>appProtoView.mergeMapping.renderProtoViewRef).originals;
|
|
||||||
}
|
|
||||||
|
|
||||||
function collectEmbeddedPvs(pv: AppProtoView, target: AppProtoView[] = null): AppProtoView[] {
|
|
||||||
if (isBlank(target)) {
|
|
||||||
target = [];
|
|
||||||
}
|
|
||||||
target.push(pv);
|
|
||||||
pv.elementBinders.forEach(elementBinder => {
|
|
||||||
if (elementBinder.hasEmbeddedProtoView()) {
|
|
||||||
collectEmbeddedPvs(elementBinder.nestedProtoView, target);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
|
@ -111,7 +111,6 @@ export function main() {
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
expect(rootTC.debugElement.nativeElement).toHaveText('Hello World!');
|
expect(rootTC.debugElement.nativeElement).toHaveText('Hello World!');
|
||||||
async.done();
|
async.done();
|
||||||
|
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -431,7 +430,7 @@ export function main() {
|
||||||
tcb.overrideView(
|
tcb.overrideView(
|
||||||
MyComp, new ViewMetadata({
|
MyComp, new ViewMetadata({
|
||||||
template:
|
template:
|
||||||
'<div><template some-viewport var-greeting="some-tmpl"><copy-me>{{greeting}}</copy-me></template></div>',
|
'<template some-viewport var-greeting="some-tmpl"><copy-me>{{greeting}}</copy-me></template>',
|
||||||
directives: [SomeViewport]
|
directives: [SomeViewport]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -440,11 +439,11 @@ export function main() {
|
||||||
|
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
var childNodesOfWrapper = rootTC.debugElement.componentViewChildren;
|
var childNodesOfWrapper = DOM.childNodes(rootTC.debugElement.nativeElement);
|
||||||
// 1 template + 2 copies.
|
// 1 template + 2 copies.
|
||||||
expect(childNodesOfWrapper.length).toBe(3);
|
expect(childNodesOfWrapper.length).toBe(3);
|
||||||
expect(childNodesOfWrapper[1].nativeElement).toHaveText('hello');
|
expect(childNodesOfWrapper[1]).toHaveText('hello');
|
||||||
expect(childNodesOfWrapper[2].nativeElement).toHaveText('again');
|
expect(childNodesOfWrapper[2]).toHaveText('again');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -454,7 +453,7 @@ export function main() {
|
||||||
tcb.overrideView(
|
tcb.overrideView(
|
||||||
MyComp, new ViewMetadata({
|
MyComp, new ViewMetadata({
|
||||||
template:
|
template:
|
||||||
'<div><copy-me template="some-viewport: var greeting=some-tmpl">{{greeting}}</copy-me></div>',
|
'<copy-me template="some-viewport: var greeting=some-tmpl">{{greeting}}</copy-me>',
|
||||||
directives: [SomeViewport]
|
directives: [SomeViewport]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -462,11 +461,11 @@ export function main() {
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
var childNodesOfWrapper = rootTC.debugElement.componentViewChildren;
|
var childNodesOfWrapper = DOM.childNodes(rootTC.debugElement.nativeElement);
|
||||||
// 1 template + 2 copies.
|
// 1 template + 2 copies.
|
||||||
expect(childNodesOfWrapper.length).toBe(3);
|
expect(childNodesOfWrapper.length).toBe(3);
|
||||||
expect(childNodesOfWrapper[1].nativeElement).toHaveText('hello');
|
expect(childNodesOfWrapper[1]).toHaveText('hello');
|
||||||
expect(childNodesOfWrapper[2].nativeElement).toHaveText('again');
|
expect(childNodesOfWrapper[2]).toHaveText('again');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -629,7 +628,7 @@ export function main() {
|
||||||
tcb.overrideView(
|
tcb.overrideView(
|
||||||
MyComp, new ViewMetadata({
|
MyComp, new ViewMetadata({
|
||||||
template:
|
template:
|
||||||
'<div><div *ng-for="var i of [1]"><child-cmp-no-template #cmp></child-cmp-no-template>{{i}}-{{cmp.ctxProp}}</div></div>',
|
'<template ng-for [ng-for-of]="[1]" var-i><child-cmp-no-template #cmp></child-cmp-no-template>{{i}}-{{cmp.ctxProp}}</template>',
|
||||||
directives: [ChildCompNoTemplate, NgFor]
|
directives: [ChildCompNoTemplate, NgFor]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -637,8 +636,8 @@ export function main() {
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
// Get the element at index 1, since index 0 is the <template>.
|
// Get the element at index 2, since index 0 is the <template>.
|
||||||
expect(rootTC.debugElement.componentViewChildren[1].nativeElement)
|
expect(DOM.childNodes(rootTC.debugElement.nativeElement)[2])
|
||||||
.toHaveText("1-hello");
|
.toHaveText("1-hello");
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
|
@ -1217,8 +1216,9 @@ export function main() {
|
||||||
describe("error handling", () => {
|
describe("error handling", () => {
|
||||||
it('should report a meaningful error when a directive is missing annotation',
|
it('should report a meaningful error when a directive is missing annotation',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
tcb = tcb.overrideView(MyComp,
|
tcb = tcb.overrideView(
|
||||||
new ViewMetadata({directives: [SomeDirectiveMissingAnnotation]}));
|
MyComp,
|
||||||
|
new ViewMetadata({template: '', directives: [SomeDirectiveMissingAnnotation]}));
|
||||||
|
|
||||||
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
||||||
expect(e.message).toEqual(
|
expect(e.message).toEqual(
|
||||||
|
@ -1229,19 +1229,20 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should report a meaningful error when a component is missing view annotation',
|
it('should report a meaningful error when a component is missing view annotation',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
PromiseWrapper.catchError(tcb.createAsync(ComponentWithoutView), (e) => {
|
try {
|
||||||
|
tcb.createAsync(ComponentWithoutView);
|
||||||
|
} catch (e) {
|
||||||
expect(e.message).toEqual(
|
expect(e.message).toEqual(
|
||||||
`No View annotation found on component ${stringify(ComponentWithoutView)}`);
|
`No View annotation found on component ${stringify(ComponentWithoutView)}`);
|
||||||
async.done();
|
|
||||||
return null;
|
return null;
|
||||||
});
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should report a meaningful error when a directive is null',
|
it('should report a meaningful error when a directive is null',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
|
||||||
tcb = tcb.overrideView(MyComp, new ViewMetadata({directives: [[null]]}));
|
tcb = tcb.overrideView(MyComp, new ViewMetadata({directives: [[null]], template: ''}));
|
||||||
|
|
||||||
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
||||||
expect(e.message).toEqual(
|
expect(e.message).toEqual(
|
||||||
|
@ -1353,7 +1354,8 @@ export function main() {
|
||||||
|
|
||||||
var undefinedValue;
|
var undefinedValue;
|
||||||
|
|
||||||
tcb = tcb.overrideView(MyComp, new ViewMetadata({directives: [undefinedValue]}));
|
tcb = tcb.overrideView(MyComp,
|
||||||
|
new ViewMetadata({directives: [undefinedValue], template: ''}));
|
||||||
|
|
||||||
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
||||||
expect(e.message).toEqual(
|
expect(e.message).toEqual(
|
||||||
|
@ -1457,7 +1459,7 @@ export function main() {
|
||||||
|
|
||||||
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
||||||
expect(e.message).toEqual(
|
expect(e.message).toEqual(
|
||||||
`Can't bind to 'unknown' since it isn't a known property of the '<div>' element and there are no matching directives with a corresponding property`);
|
`Template parse errors:\nCan't bind to 'unknown' since it isn't a known native property in MyComp > div:nth-child(0)[unknown={{ctxProp}}]`);
|
||||||
async.done();
|
async.done();
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -1516,9 +1518,8 @@ export function main() {
|
||||||
|
|
||||||
describe('logging property updates', () => {
|
describe('logging property updates', () => {
|
||||||
beforeEachBindings(() => [
|
beforeEachBindings(() => [
|
||||||
bind(ChangeDetection)
|
bind(ChangeDetectorGenConfig)
|
||||||
.toValue(
|
.toValue(new ChangeDetectorGenConfig(true, true, true, false))
|
||||||
new DynamicChangeDetection(new ChangeDetectorGenConfig(true, true, true, false)))
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
it('should reflect property values as attributes',
|
it('should reflect property values as attributes',
|
||||||
|
|
|
@ -522,7 +522,8 @@ class OuterWithIndirectNestedComponent {
|
||||||
|
|
||||||
@Component({selector: 'outer'})
|
@Component({selector: 'outer'})
|
||||||
@View({
|
@View({
|
||||||
template: 'OUTER(<inner><ng-content></ng-content></inner>)',
|
template:
|
||||||
|
'OUTER(<inner><ng-content select=".left" class="left"></ng-content><ng-content></ng-content></inner>)',
|
||||||
directives: [forwardRef(() => InnerComponent)]
|
directives: [forwardRef(() => InnerComponent)]
|
||||||
})
|
})
|
||||||
class OuterComponent {
|
class OuterComponent {
|
||||||
|
@ -530,7 +531,8 @@ class OuterComponent {
|
||||||
|
|
||||||
@Component({selector: 'inner'})
|
@Component({selector: 'inner'})
|
||||||
@View({
|
@View({
|
||||||
template: 'INNER(<innerinner><ng-content></ng-content></innerinner>)',
|
template:
|
||||||
|
'INNER(<innerinner><ng-content select=".left" class="left"></ng-content><ng-content></ng-content></innerinner>)',
|
||||||
directives: [forwardRef(() => InnerInnerComponent)]
|
directives: [forwardRef(() => InnerInnerComponent)]
|
||||||
})
|
})
|
||||||
class InnerComponent {
|
class InnerComponent {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import {
|
||||||
|
|
||||||
import {SpyChangeDetection} from '../spies';
|
import {SpyChangeDetection} from '../spies';
|
||||||
import {isBlank, stringify} from 'angular2/src/core/facade/lang';
|
import {isBlank, stringify} from 'angular2/src/core/facade/lang';
|
||||||
import {MapWrapper} from 'angular2/src/core/facade/collection';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChangeDetection,
|
ChangeDetection,
|
||||||
|
@ -24,10 +23,7 @@ import {
|
||||||
} from 'angular2/src/core/change_detection/change_detection';
|
} from 'angular2/src/core/change_detection/change_detection';
|
||||||
import {
|
import {
|
||||||
BindingRecordsCreator,
|
BindingRecordsCreator,
|
||||||
ProtoViewFactory,
|
getChangeDetectorDefinitions
|
||||||
getChangeDetectorDefinitions,
|
|
||||||
createDirectiveVariableBindings,
|
|
||||||
createVariableLocations
|
|
||||||
} from 'angular2/src/core/compiler/proto_view_factory';
|
} from 'angular2/src/core/compiler/proto_view_factory';
|
||||||
import {Component, Directive} from 'angular2/src/core/metadata';
|
import {Component, Directive} from 'angular2/src/core/metadata';
|
||||||
import {Key, Binding} from 'angular2/core';
|
import {Key, Binding} from 'angular2/core';
|
||||||
|
@ -43,18 +39,14 @@ import {
|
||||||
} from 'angular2/src/core/render/api';
|
} from 'angular2/src/core/render/api';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
// TODO(tbosch): add missing tests
|
|
||||||
|
|
||||||
describe('ProtoViewFactory', () => {
|
describe('ProtoViewFactory', () => {
|
||||||
var changeDetection;
|
var changeDetection;
|
||||||
var protoViewFactory: ProtoViewFactory;
|
|
||||||
var directiveResolver;
|
var directiveResolver;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
directiveResolver = new DirectiveResolver();
|
directiveResolver = new DirectiveResolver();
|
||||||
changeDetection = new SpyChangeDetection();
|
changeDetection = new SpyChangeDetection();
|
||||||
changeDetection.prop("generateDetectors", true);
|
changeDetection.prop("generateDetectors", true);
|
||||||
protoViewFactory = new ProtoViewFactory(changeDetection);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function bindDirective(type) {
|
function bindDirective(type) {
|
||||||
|
@ -73,107 +65,6 @@ export function main() {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createAppProtoViews', () => {
|
|
||||||
|
|
||||||
it('should create an AppProtoView for the root render proto view', () => {
|
|
||||||
var varBindings = new Map();
|
|
||||||
varBindings.set('a', 'b');
|
|
||||||
var renderPv = createRenderProtoView([], null, varBindings);
|
|
||||||
var appPvs =
|
|
||||||
protoViewFactory.createAppProtoViews(bindDirective(MainComponent), renderPv, [], []);
|
|
||||||
expect(appPvs[0].variableBindings.get('a')).toEqual('b');
|
|
||||||
expect(appPvs.length).toBe(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("createDirectiveVariableBindings", () => {
|
|
||||||
it("should calculate directive variable bindings", () => {
|
|
||||||
var dvbs = createDirectiveVariableBindings(
|
|
||||||
new RenderElementBinder({
|
|
||||||
variableBindings:
|
|
||||||
MapWrapper.createFromStringMap<string>({"exportName": "templateName"})
|
|
||||||
}),
|
|
||||||
[
|
|
||||||
directiveBinding(
|
|
||||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})}),
|
|
||||||
directiveBinding(
|
|
||||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'otherName'})})
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(dvbs).toEqual(MapWrapper.createFromStringMap<number>({"templateName": 0}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set exportAs to $implicit for component with exportAs = null", () => {
|
|
||||||
var dvbs = createDirectiveVariableBindings(
|
|
||||||
new RenderElementBinder({
|
|
||||||
variableBindings:
|
|
||||||
MapWrapper.createFromStringMap<string>({"$implicit": "templateName"})
|
|
||||||
}),
|
|
||||||
[
|
|
||||||
directiveBinding({
|
|
||||||
metadata: RenderDirectiveMetadata.create(
|
|
||||||
{exportAs: null, type: RenderDirectiveMetadata.COMPONENT_TYPE})
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(dvbs).toEqual(MapWrapper.createFromStringMap<number>({"templateName": 0}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw we no directive exported with this name", () => {
|
|
||||||
expect(() => {
|
|
||||||
createDirectiveVariableBindings(
|
|
||||||
new RenderElementBinder({
|
|
||||||
variableBindings:
|
|
||||||
MapWrapper.createFromStringMap<string>({"someInvalidName": "templateName"})
|
|
||||||
}),
|
|
||||||
[
|
|
||||||
directiveBinding(
|
|
||||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})})
|
|
||||||
]);
|
|
||||||
}).toThrowError(new RegExp("Cannot find directive with exportAs = 'someInvalidName'"));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw when binding to a name exported by two directives", () => {
|
|
||||||
expect(() => {
|
|
||||||
createDirectiveVariableBindings(
|
|
||||||
new RenderElementBinder({
|
|
||||||
variableBindings:
|
|
||||||
MapWrapper.createFromStringMap<string>({"exportName": "templateName"})
|
|
||||||
}),
|
|
||||||
[
|
|
||||||
directiveBinding(
|
|
||||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})}),
|
|
||||||
directiveBinding(
|
|
||||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})})
|
|
||||||
]);
|
|
||||||
}).toThrowError(new RegExp("More than one directive have exportAs = 'exportName'"));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not throw when not binding to a name exported by two directives", () => {
|
|
||||||
expect(() => {
|
|
||||||
createDirectiveVariableBindings(
|
|
||||||
new RenderElementBinder({variableBindings: new Map<string, string>()}), [
|
|
||||||
directiveBinding(
|
|
||||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})}),
|
|
||||||
directiveBinding(
|
|
||||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})})
|
|
||||||
]);
|
|
||||||
}).not.toThrow();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('createVariableLocations', () => {
|
|
||||||
it('should merge the names in the template for all ElementBinders', () => {
|
|
||||||
expect(createVariableLocations([
|
|
||||||
new RenderElementBinder(
|
|
||||||
{variableBindings: MapWrapper.createFromStringMap<string>({"x": "a"})}),
|
|
||||||
new RenderElementBinder(
|
|
||||||
{variableBindings: MapWrapper.createFromStringMap<string>({"y": "b"})})
|
|
||||||
|
|
||||||
])).toEqual(MapWrapper.createFromStringMap<number>({'a': 0, 'b': 1}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('BindingRecordsCreator', () => {
|
describe('BindingRecordsCreator', () => {
|
||||||
var creator: BindingRecordsCreator;
|
var creator: BindingRecordsCreator;
|
||||||
|
|
||||||
|
@ -247,15 +138,6 @@ function createRenderProtoView(elementBinders = null, type: ViewType = null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRenderComponentElementBinder(directiveIndex) {
|
|
||||||
return new RenderElementBinder(
|
|
||||||
{directives: [new DirectiveBinder({directiveIndex: directiveIndex})]});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createRenderViewportElementBinder(nestedProtoView) {
|
|
||||||
return new RenderElementBinder({nestedProtoView: nestedProtoView});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({selector: 'main-comp'})
|
@Component({selector: 'main-comp'})
|
||||||
class MainComponent {
|
class MainComponent {
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ export function main() {
|
||||||
viewManager = new SpyAppViewManager();
|
viewManager = new SpyAppViewManager();
|
||||||
view = new SpyView();
|
view = new SpyView();
|
||||||
view.prop("viewContainers", [null]);
|
view.prop("viewContainers", [null]);
|
||||||
location = new ElementRef(new ViewRef(view), 0, 0, null);
|
location = new ElementRef(new ViewRef(view), 0, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('length', () => {
|
describe('length', () => {
|
||||||
|
|
|
@ -13,15 +13,10 @@ import {
|
||||||
it,
|
it,
|
||||||
xit
|
xit
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
import {SpyRenderer, SpyAppViewPool, SpyAppViewListener} from '../spies';
|
import {SpyRenderer, SpyAppViewPool, SpyAppViewListener, SpyProtoViewFactory} from '../spies';
|
||||||
import {Injector, bind} from 'angular2/core';
|
import {Injector, bind} from 'angular2/core';
|
||||||
|
|
||||||
import {
|
import {AppProtoView, AppView, AppViewContainer} from 'angular2/src/core/compiler/view';
|
||||||
AppProtoView,
|
|
||||||
AppView,
|
|
||||||
AppViewContainer,
|
|
||||||
AppProtoViewMergeMapping
|
|
||||||
} from 'angular2/src/core/compiler/view';
|
|
||||||
import {ProtoViewRef, ViewRef, internalView} from 'angular2/src/core/compiler/view_ref';
|
import {ProtoViewRef, ViewRef, internalView} from 'angular2/src/core/compiler/view_ref';
|
||||||
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
||||||
import {TemplateRef} from 'angular2/src/core/compiler/template_ref';
|
import {TemplateRef} from 'angular2/src/core/compiler/template_ref';
|
||||||
|
@ -54,6 +49,7 @@ export function main() {
|
||||||
var utils: AppViewManagerUtils;
|
var utils: AppViewManagerUtils;
|
||||||
var viewListener;
|
var viewListener;
|
||||||
var viewPool;
|
var viewPool;
|
||||||
|
var linker;
|
||||||
var manager: AppViewManager;
|
var manager: AppViewManager;
|
||||||
var createdRenderViews: RenderViewWithFragments[];
|
var createdRenderViews: RenderViewWithFragments[];
|
||||||
|
|
||||||
|
@ -78,7 +74,8 @@ export function main() {
|
||||||
utils = new AppViewManagerUtils();
|
utils = new AppViewManagerUtils();
|
||||||
viewListener = new SpyAppViewListener();
|
viewListener = new SpyAppViewListener();
|
||||||
viewPool = new SpyAppViewPool();
|
viewPool = new SpyAppViewPool();
|
||||||
manager = new AppViewManager(viewPool, viewListener, utils, renderer);
|
linker = new SpyProtoViewFactory();
|
||||||
|
manager = new AppViewManager(viewPool, viewListener, utils, renderer, linker);
|
||||||
createdRenderViews = [];
|
createdRenderViews = [];
|
||||||
|
|
||||||
renderer.spy('createRootHostView')
|
renderer.spy('createRootHostView')
|
||||||
|
@ -110,6 +107,11 @@ export function main() {
|
||||||
beforeEach(
|
beforeEach(
|
||||||
() => { hostProtoView = createHostPv([createNestedElBinder(createComponentPv())]); });
|
() => { hostProtoView = createHostPv([createNestedElBinder(createComponentPv())]); });
|
||||||
|
|
||||||
|
it('should initialize the ProtoView', () => {
|
||||||
|
manager.createRootHostView(wrapPv(hostProtoView), null, null);
|
||||||
|
expect(linker.spy('initializeProtoViewIfNeeded')).toHaveBeenCalledWith(hostProtoView);
|
||||||
|
});
|
||||||
|
|
||||||
it('should create the view', () => {
|
it('should create the view', () => {
|
||||||
var rootView =
|
var rootView =
|
||||||
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
|
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
|
||||||
|
@ -129,8 +131,8 @@ export function main() {
|
||||||
var rootView =
|
var rootView =
|
||||||
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
|
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
|
||||||
expect(renderer.spy('createRootHostView'))
|
expect(renderer.spy('createRootHostView'))
|
||||||
.toHaveBeenCalledWith(hostProtoView.mergeMapping.renderProtoViewRef,
|
.toHaveBeenCalledWith(hostProtoView.render,
|
||||||
hostProtoView.mergeMapping.renderFragmentCount, 'someComponent');
|
hostProtoView.mergeInfo.embeddedViewCount + 1, 'someComponent');
|
||||||
expect(rootView.render).toBe(createdRenderViews[0].viewRef);
|
expect(rootView.render).toBe(createdRenderViews[0].viewRef);
|
||||||
expect(rootView.renderFragment).toBe(createdRenderViews[0].fragmentRefs[0]);
|
expect(rootView.renderFragment).toBe(createdRenderViews[0].fragmentRefs[0]);
|
||||||
});
|
});
|
||||||
|
@ -139,8 +141,8 @@ export function main() {
|
||||||
var selector = 'someOtherSelector';
|
var selector = 'someOtherSelector';
|
||||||
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), selector, null));
|
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), selector, null));
|
||||||
expect(renderer.spy('createRootHostView'))
|
expect(renderer.spy('createRootHostView'))
|
||||||
.toHaveBeenCalledWith(hostProtoView.mergeMapping.renderProtoViewRef,
|
.toHaveBeenCalledWith(hostProtoView.render,
|
||||||
hostProtoView.mergeMapping.renderFragmentCount, selector);
|
hostProtoView.mergeInfo.embeddedViewCount + 1, selector);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the event dispatcher', () => {
|
it('should set the event dispatcher', () => {
|
||||||
|
@ -182,7 +184,7 @@ export function main() {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createViewInContainer', () => {
|
describe('createEmbeddedViewInContainer', () => {
|
||||||
|
|
||||||
describe('basic functionality', () => {
|
describe('basic functionality', () => {
|
||||||
var hostView: AppView;
|
var hostView: AppView;
|
||||||
|
@ -200,6 +202,11 @@ export function main() {
|
||||||
resetSpies();
|
resetSpies();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should initialize the ProtoView', () => {
|
||||||
|
manager.createEmbeddedViewInContainer(vcRef, 0, templateRef);
|
||||||
|
expect(linker.spy('initializeProtoViewIfNeeded')).toHaveBeenCalledWith(childProtoView);
|
||||||
|
});
|
||||||
|
|
||||||
describe('create the first view', () => {
|
describe('create the first view', () => {
|
||||||
|
|
||||||
it('should create an AppViewContainer if not yet existing', () => {
|
it('should create an AppViewContainer if not yet existing', () => {
|
||||||
|
@ -255,8 +262,8 @@ export function main() {
|
||||||
expect(childView).not.toBe(firstChildView);
|
expect(childView).not.toBe(firstChildView);
|
||||||
expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(childView);
|
expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(childView);
|
||||||
expect(renderer.spy('createView'))
|
expect(renderer.spy('createView'))
|
||||||
.toHaveBeenCalledWith(childProtoView.mergeMapping.renderProtoViewRef,
|
.toHaveBeenCalledWith(childProtoView.render,
|
||||||
childProtoView.mergeMapping.renderFragmentCount);
|
childProtoView.mergeInfo.embeddedViewCount + 1);
|
||||||
expect(childView.render).toBe(createdRenderViews[1].viewRef);
|
expect(childView.render).toBe(createdRenderViews[1].viewRef);
|
||||||
expect(childView.renderFragment).toBe(createdRenderViews[1].fragmentRefs[0]);
|
expect(childView.renderFragment).toBe(createdRenderViews[1].fragmentRefs[0]);
|
||||||
});
|
});
|
||||||
|
@ -306,6 +313,12 @@ export function main() {
|
||||||
|
|
||||||
describe('create a host view', () => {
|
describe('create a host view', () => {
|
||||||
|
|
||||||
|
it('should initialize the ProtoView', () => {
|
||||||
|
var newHostPv = createHostPv([createNestedElBinder(createComponentPv())]);
|
||||||
|
manager.createHostViewInContainer(vcRef, 0, wrapPv(newHostPv), null);
|
||||||
|
expect(linker.spy('initializeProtoViewIfNeeded')).toHaveBeenCalledWith(newHostPv);
|
||||||
|
});
|
||||||
|
|
||||||
it('should always create a new view and not use the embedded view', () => {
|
it('should always create a new view and not use the embedded view', () => {
|
||||||
var newHostPv = createHostPv([createNestedElBinder(createComponentPv())]);
|
var newHostPv = createHostPv([createNestedElBinder(createComponentPv())]);
|
||||||
var newHostView = internalView(
|
var newHostView = internalView(
|
||||||
|
@ -314,8 +327,7 @@ export function main() {
|
||||||
expect(newHostView).not.toBe(hostView.views[2]);
|
expect(newHostView).not.toBe(hostView.views[2]);
|
||||||
expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(newHostView);
|
expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(newHostView);
|
||||||
expect(renderer.spy('createView'))
|
expect(renderer.spy('createView'))
|
||||||
.toHaveBeenCalledWith(newHostPv.mergeMapping.renderProtoViewRef,
|
.toHaveBeenCalledWith(newHostPv.render, newHostPv.mergeInfo.embeddedViewCount + 1);
|
||||||
newHostPv.mergeMapping.renderFragmentCount);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,6 @@ import {
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SpyChangeDetector,
|
SpyChangeDetector,
|
||||||
SpyProtoChangeDetector,
|
|
||||||
SpyProtoElementInjector,
|
SpyProtoElementInjector,
|
||||||
SpyElementInjector,
|
SpyElementInjector,
|
||||||
SpyPreBuiltObjects
|
SpyPreBuiltObjects
|
||||||
|
@ -26,9 +25,8 @@ import {
|
||||||
|
|
||||||
import {Injector, bind} from 'angular2/core';
|
import {Injector, bind} from 'angular2/core';
|
||||||
import {isBlank, isPresent} from 'angular2/src/core/facade/lang';
|
import {isBlank, isPresent} from 'angular2/src/core/facade/lang';
|
||||||
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
|
||||||
|
|
||||||
import {AppProtoView, AppView, AppProtoViewMergeMapping} from 'angular2/src/core/compiler/view';
|
import {AppProtoView, AppView, AppProtoViewMergeInfo} from 'angular2/src/core/compiler/view';
|
||||||
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
|
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
|
||||||
import {
|
import {
|
||||||
DirectiveBinding,
|
DirectiveBinding,
|
||||||
|
@ -208,16 +206,19 @@ export function createInjector() {
|
||||||
function createElementInjector(parent = null) {
|
function createElementInjector(parent = null) {
|
||||||
var host = new SpyElementInjector();
|
var host = new SpyElementInjector();
|
||||||
var elementInjector = new SpyElementInjector();
|
var elementInjector = new SpyElementInjector();
|
||||||
var res = SpyObject.stub(elementInjector,
|
var _preBuiltObjects = null;
|
||||||
{
|
var res = SpyObject.stub(elementInjector, {
|
||||||
'isExportingComponent': false,
|
'isExportingComponent': false,
|
||||||
'isExportingElement': false,
|
'isExportingElement': false,
|
||||||
'getEventEmitterAccessors': [],
|
'getEventEmitterAccessors': [],
|
||||||
'getHostActionAccessors': [],
|
'getHostActionAccessors': [],
|
||||||
'getComponent': new Object(),
|
'getComponent': new Object(),
|
||||||
'getHost': host
|
'getHost': host
|
||||||
},
|
});
|
||||||
{});
|
res.spy('getNestedView').andCallFake(() => _preBuiltObjects.nestedView);
|
||||||
|
res.spy('hydrate')
|
||||||
|
.andCallFake((mperativelyCreatedInjector: Injector, host: ElementInjector,
|
||||||
|
preBuiltObjects: PreBuiltObjects) => { _preBuiltObjects = preBuiltObjects; });
|
||||||
res.prop('parent', parent);
|
res.prop('parent', parent);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -232,7 +233,7 @@ export function createProtoElInjector(parent: ProtoElementInjector = null): Prot
|
||||||
|
|
||||||
export function createEmptyElBinder(parent: ElementBinder = null) {
|
export function createEmptyElBinder(parent: ElementBinder = null) {
|
||||||
var parentPeli = isPresent(parent) ? parent.protoElementInjector : null;
|
var parentPeli = isPresent(parent) ? parent.protoElementInjector : null;
|
||||||
return new ElementBinder(0, null, 0, createProtoElInjector(parentPeli), null);
|
return new ElementBinder(0, null, 0, createProtoElInjector(parentPeli), null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createNestedElBinder(nestedProtoView: AppProtoView) {
|
export function createNestedElBinder(nestedProtoView: AppProtoView) {
|
||||||
|
@ -241,78 +242,35 @@ export function createNestedElBinder(nestedProtoView: AppProtoView) {
|
||||||
var annotation = new DirectiveResolver().resolve(SomeComponent);
|
var annotation = new DirectiveResolver().resolve(SomeComponent);
|
||||||
componentBinding = DirectiveBinding.createFromType(SomeComponent, annotation);
|
componentBinding = DirectiveBinding.createFromType(SomeComponent, annotation);
|
||||||
}
|
}
|
||||||
var binder = new ElementBinder(0, null, 0, createProtoElInjector(), componentBinding);
|
return new ElementBinder(0, null, 0, createProtoElInjector(), componentBinding, nestedProtoView);
|
||||||
binder.nestedProtoView = nestedProtoView;
|
|
||||||
return binder;
|
|
||||||
}
|
|
||||||
|
|
||||||
function countNestedElementBinders(pv: AppProtoView): number {
|
|
||||||
var result = pv.elementBinders.length;
|
|
||||||
pv.elementBinders.forEach(binder => {
|
|
||||||
if (isPresent(binder.nestedProtoView)) {
|
|
||||||
result += countNestedElementBinders(binder.nestedProtoView);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function calcHostElementIndicesByViewIndex(pv: AppProtoView, elementOffset = 0,
|
|
||||||
target: number[] = null): number[] {
|
|
||||||
if (isBlank(target)) {
|
|
||||||
target = [null];
|
|
||||||
}
|
|
||||||
for (var binderIdx = 0; binderIdx < pv.elementBinders.length; binderIdx++) {
|
|
||||||
var binder = pv.elementBinders[binderIdx];
|
|
||||||
if (isPresent(binder.nestedProtoView)) {
|
|
||||||
target.push(elementOffset + binderIdx);
|
|
||||||
calcHostElementIndicesByViewIndex(binder.nestedProtoView,
|
|
||||||
elementOffset + pv.elementBinders.length, target);
|
|
||||||
elementOffset += countNestedElementBinders(binder.nestedProtoView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
function countNestedProtoViews(pv: AppProtoView, target: number[] = null): number[] {
|
|
||||||
if (isBlank(target)) {
|
|
||||||
target = [];
|
|
||||||
}
|
|
||||||
target.push(null);
|
|
||||||
var resultIndex = target.length - 1;
|
|
||||||
var count = 0;
|
|
||||||
for (var binderIdx = 0; binderIdx < pv.elementBinders.length; binderIdx++) {
|
|
||||||
var binder = pv.elementBinders[binderIdx];
|
|
||||||
if (isPresent(binder.nestedProtoView)) {
|
|
||||||
var nextResultIndex = target.length;
|
|
||||||
countNestedProtoViews(binder.nestedProtoView, target);
|
|
||||||
count += target[nextResultIndex] + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
target[resultIndex] = count;
|
|
||||||
return target;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _createProtoView(type: ViewType, binders: ElementBinder[] = null) {
|
function _createProtoView(type: ViewType, binders: ElementBinder[] = null) {
|
||||||
if (isBlank(binders)) {
|
if (isBlank(binders)) {
|
||||||
binders = [];
|
binders = [];
|
||||||
}
|
}
|
||||||
var protoChangeDetector = <any>new SpyProtoChangeDetector();
|
var res = new AppProtoView([], type, true, (_) => new SpyChangeDetector(), new Map<string, any>(),
|
||||||
protoChangeDetector.spy('instantiate').andReturn(new SpyChangeDetector());
|
null);
|
||||||
var res = new AppProtoView(type, null, null, protoChangeDetector, null, null, 0, null);
|
var mergedElementCount = 0;
|
||||||
res.elementBinders = binders;
|
var mergedEmbeddedViewCount = 0;
|
||||||
var mappedElementIndices = ListWrapper.createFixedSize(countNestedElementBinders(res));
|
var mergedViewCount = 1;
|
||||||
for (var i = 0; i < binders.length; i++) {
|
for (var i = 0; i < binders.length; i++) {
|
||||||
var binder = binders[i];
|
var binder = binders[i];
|
||||||
mappedElementIndices[i] = i;
|
|
||||||
binder.protoElementInjector.index = i;
|
binder.protoElementInjector.index = i;
|
||||||
|
mergedElementCount++;
|
||||||
|
var nestedPv = binder.nestedProtoView;
|
||||||
|
if (isPresent(nestedPv)) {
|
||||||
|
mergedElementCount += nestedPv.mergeInfo.elementCount;
|
||||||
|
mergedEmbeddedViewCount += nestedPv.mergeInfo.embeddedViewCount;
|
||||||
|
mergedViewCount += nestedPv.mergeInfo.viewCount;
|
||||||
|
if (nestedPv.type === ViewType.EMBEDDED) {
|
||||||
|
mergedEmbeddedViewCount++;
|
||||||
}
|
}
|
||||||
var hostElementIndicesByViewIndex = calcHostElementIndicesByViewIndex(res);
|
|
||||||
if (type === ViewType.EMBEDDED || type === ViewType.HOST) {
|
|
||||||
res.mergeMapping = new AppProtoViewMergeMapping(
|
|
||||||
new RenderProtoViewMergeMapping(null, hostElementIndicesByViewIndex.length,
|
|
||||||
mappedElementIndices, mappedElementIndices.length, [],
|
|
||||||
hostElementIndicesByViewIndex, countNestedProtoViews(res)));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
var mergeInfo =
|
||||||
|
new AppProtoViewMergeInfo(mergedEmbeddedViewCount, mergedElementCount, mergedViewCount);
|
||||||
|
res.init(null, binders, 0, mergeInfo, new Map<string, number>());
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,10 @@ export function main() {
|
||||||
|
|
||||||
function createViewPool({capacity}): AppViewPool { return new AppViewPool(capacity); }
|
function createViewPool({capacity}): AppViewPool { return new AppViewPool(capacity); }
|
||||||
|
|
||||||
function createProtoView() {
|
function createProtoView() { return new AppProtoView(null, null, null, null, null, null); }
|
||||||
return new AppProtoView(null, null, null, null, null, null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createView(pv) {
|
function createView(pv) {
|
||||||
return new AppView(null, pv, null, null, null, null, new Map<string, any>(), null, null);
|
return new AppView(null, pv, null, null, null, new Map<string, any>(), null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should support multiple AppProtoViews', () => {
|
it('should support multiple AppProtoViews', () => {
|
||||||
|
|
|
@ -51,7 +51,7 @@ class MessageDir {
|
||||||
template: `<div class="child" message="child">
|
template: `<div class="child" message="child">
|
||||||
<span class="childnested" message="nestedchild">Child</span>
|
<span class="childnested" message="nestedchild">Child</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="child">{{childBinding}}</span>`,
|
<span class="child" [inner-html]="childBinding"></span>`,
|
||||||
directives: [MessageDir]
|
directives: [MessageDir]
|
||||||
})
|
})
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -66,7 +66,7 @@ class ChildComp {
|
||||||
template: `<div class="parent" message="parent">
|
template: `<div class="parent" message="parent">
|
||||||
<span class="parentnested" message="nestedparent">Parent</span>
|
<span class="parentnested" message="nestedparent">Parent</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="parent">{{parentBinding}}</span>
|
<span class="parent" [inner-html]="parentBinding"></span>
|
||||||
<child-comp class="child-comp-class"></child-comp>`,
|
<child-comp class="child-comp-class"></child-comp>`,
|
||||||
directives: [ChildComp, MessageDir]
|
directives: [ChildComp, MessageDir]
|
||||||
})
|
})
|
||||||
|
@ -107,9 +107,9 @@ class EventsComp {
|
||||||
|
|
||||||
@Component({selector: 'using-for', viewBindings: [Logger]})
|
@Component({selector: 'using-for', viewBindings: [Logger]})
|
||||||
@View({
|
@View({
|
||||||
template: `<span *ng-for="#thing of stuff">{{thing}}</span>
|
template: `<span *ng-for="#thing of stuff" [inner-html]="thing"></span>
|
||||||
<ul message="list">
|
<ul message="list">
|
||||||
<li *ng-for="#item of stuff">{{item}}</li>
|
<li *ng-for="#item of stuff" [inner-html]="item"></li>
|
||||||
</ul>`,
|
</ul>`,
|
||||||
directives: [NgFor, MessageDir]
|
directives: [NgFor, MessageDir]
|
||||||
})
|
})
|
||||||
|
|
|
@ -41,7 +41,7 @@ export function main() {
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
rootTC.debugElement.componentInstance.items = [['1']];
|
rootTC.debugElement.componentInstance.items = [['1']];
|
||||||
|
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding 1', 1);
|
detectChangesAndCheck(rootTC, '1', 1);
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -58,7 +58,7 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -71,7 +71,7 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo-bar fooBar');
|
detectChangesAndCheck(rootTC, 'foo-bar fooBar');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -83,10 +83,10 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.condition = false;
|
rootTC.debugElement.componentInstance.condition = false;
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding bar');
|
detectChangesAndCheck(rootTC, 'bar');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -99,16 +99,16 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar');
|
detectChangesAndCheck(rootTC, 'foo bar');
|
||||||
|
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'baz', true);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'baz', true);
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar baz');
|
detectChangesAndCheck(rootTC, 'foo bar baz');
|
||||||
|
|
||||||
StringMapWrapper.delete(rootTC.debugElement.componentInstance.objExpr, 'bar');
|
StringMapWrapper.delete(rootTC.debugElement.componentInstance.objExpr, 'bar');
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo baz');
|
detectChangesAndCheck(rootTC, 'foo baz');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -121,13 +121,13 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.objExpr = {foo: true, bar: true};
|
rootTC.debugElement.componentInstance.objExpr = {foo: true, bar: true};
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar');
|
detectChangesAndCheck(rootTC, 'foo bar');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.objExpr = {baz: true};
|
rootTC.debugElement.componentInstance.objExpr = {baz: true};
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding baz');
|
detectChangesAndCheck(rootTC, 'baz');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -140,13 +140,13 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.objExpr = null;
|
rootTC.debugElement.componentInstance.objExpr = null;
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding');
|
detectChangesAndCheck(rootTC, '');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.objExpr = {'foo': false, 'bar': true};
|
rootTC.debugElement.componentInstance.objExpr = {'foo': false, 'bar': true};
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding bar');
|
detectChangesAndCheck(rootTC, 'bar');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -162,7 +162,7 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar foo-bar fooBar');
|
detectChangesAndCheck(rootTC, 'foo bar foo-bar fooBar');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -175,16 +175,16 @@ export function main() {
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
var arrExpr: string[] = rootTC.debugElement.componentInstance.arrExpr;
|
var arrExpr: string[] = rootTC.debugElement.componentInstance.arrExpr;
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
arrExpr.push('bar');
|
arrExpr.push('bar');
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar');
|
detectChangesAndCheck(rootTC, 'foo bar');
|
||||||
|
|
||||||
arrExpr[1] = 'baz';
|
arrExpr[1] = 'baz';
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo baz');
|
detectChangesAndCheck(rootTC, 'foo baz');
|
||||||
|
|
||||||
ListWrapper.remove(rootTC.debugElement.componentInstance.arrExpr, 'baz');
|
ListWrapper.remove(rootTC.debugElement.componentInstance.arrExpr, 'baz');
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -197,10 +197,10 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.arrExpr = ['bar'];
|
rootTC.debugElement.componentInstance.arrExpr = ['bar'];
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding bar');
|
detectChangesAndCheck(rootTC, 'bar');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -213,10 +213,10 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'foo ng-binding');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.arrExpr = ['bar'];
|
rootTC.debugElement.componentInstance.arrExpr = ['bar'];
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar');
|
detectChangesAndCheck(rootTC, 'foo bar');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -231,7 +231,7 @@ export function main() {
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.arrExpr = ['', ' '];
|
rootTC.debugElement.componentInstance.arrExpr = ['', ' '];
|
||||||
detectChangesAndCheck(rootTC, 'foo ng-binding');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -246,7 +246,7 @@ export function main() {
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.arrExpr = [' bar '];
|
rootTC.debugElement.componentInstance.arrExpr = [' bar '];
|
||||||
detectChangesAndCheck(rootTC, 'foo ng-binding bar');
|
detectChangesAndCheck(rootTC, 'foo bar');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -262,7 +262,7 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar foo-bar fooBar');
|
detectChangesAndCheck(rootTC, 'foo bar foo-bar fooBar');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -274,14 +274,14 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.strExpr = 'foo bar';
|
rootTC.debugElement.componentInstance.strExpr = 'foo bar';
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar');
|
detectChangesAndCheck(rootTC, 'foo bar');
|
||||||
|
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.strExpr = 'baz';
|
rootTC.debugElement.componentInstance.strExpr = 'baz';
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding baz');
|
detectChangesAndCheck(rootTC, 'baz');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -294,10 +294,10 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.strExpr = null;
|
rootTC.debugElement.componentInstance.strExpr = null;
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding');
|
detectChangesAndCheck(rootTC, '');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -310,10 +310,10 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'foo ng-binding');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.strExpr = null;
|
rootTC.debugElement.componentInstance.strExpr = null;
|
||||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -327,7 +327,7 @@ export function main() {
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
rootTC.debugElement.componentInstance.strExpr = '';
|
rootTC.debugElement.componentInstance.strExpr = '';
|
||||||
detectChangesAndCheck(rootTC, 'foo ng-binding');
|
detectChangesAndCheck(rootTC, 'foo');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -345,13 +345,13 @@ export function main() {
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||||
detectChangesAndCheck(rootTC, 'init foo ng-binding bar');
|
detectChangesAndCheck(rootTC, 'init foo bar');
|
||||||
|
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
||||||
detectChangesAndCheck(rootTC, 'init ng-binding bar');
|
detectChangesAndCheck(rootTC, 'init bar');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.objExpr = null;
|
rootTC.debugElement.componentInstance.objExpr = null;
|
||||||
detectChangesAndCheck(rootTC, 'init ng-binding foo');
|
detectChangesAndCheck(rootTC, 'init foo');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -365,13 +365,13 @@ export function main() {
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||||
detectChangesAndCheck(rootTC, `{{'init foo'}} ng-binding init foo bar`);
|
detectChangesAndCheck(rootTC, `init foo bar`);
|
||||||
|
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
||||||
detectChangesAndCheck(rootTC, `{{'init foo'}} ng-binding init bar`);
|
detectChangesAndCheck(rootTC, `init bar`);
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.objExpr = null;
|
rootTC.debugElement.componentInstance.objExpr = null;
|
||||||
detectChangesAndCheck(rootTC, `{{'init foo'}} ng-binding init foo`);
|
detectChangesAndCheck(rootTC, `init foo`);
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -385,13 +385,13 @@ export function main() {
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||||
detectChangesAndCheck(rootTC, `init ng-binding foo bar`);
|
detectChangesAndCheck(rootTC, `init foo bar`);
|
||||||
|
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
||||||
detectChangesAndCheck(rootTC, `init ng-binding bar`);
|
detectChangesAndCheck(rootTC, `init bar`);
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.objExpr = null;
|
rootTC.debugElement.componentInstance.objExpr = null;
|
||||||
detectChangesAndCheck(rootTC, `init ng-binding foo`);
|
detectChangesAndCheck(rootTC, `init foo`);
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -405,16 +405,16 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'init foo ng-binding baz');
|
detectChangesAndCheck(rootTC, 'init foo baz');
|
||||||
|
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||||
detectChangesAndCheck(rootTC, 'init foo ng-binding baz bar');
|
detectChangesAndCheck(rootTC, 'init foo baz bar');
|
||||||
|
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
||||||
detectChangesAndCheck(rootTC, 'init ng-binding baz bar');
|
detectChangesAndCheck(rootTC, 'init baz bar');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.condition = false;
|
rootTC.debugElement.componentInstance.condition = false;
|
||||||
detectChangesAndCheck(rootTC, 'init ng-binding bar');
|
detectChangesAndCheck(rootTC, 'init bar');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -427,16 +427,16 @@ export function main() {
|
||||||
tcb.overrideTemplate(TestComponent, template)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
detectChangesAndCheck(rootTC, 'init ng-binding foo');
|
detectChangesAndCheck(rootTC, 'init foo');
|
||||||
|
|
||||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||||
detectChangesAndCheck(rootTC, 'init ng-binding foo bar');
|
detectChangesAndCheck(rootTC, 'init foo bar');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.strExpr = 'baz';
|
rootTC.debugElement.componentInstance.strExpr = 'baz';
|
||||||
detectChangesAndCheck(rootTC, 'init ng-binding bar baz foo');
|
detectChangesAndCheck(rootTC, 'init bar baz foo');
|
||||||
|
|
||||||
rootTC.debugElement.componentInstance.objExpr = null;
|
rootTC.debugElement.componentInstance.objExpr = null;
|
||||||
detectChangesAndCheck(rootTC, 'init ng-binding baz');
|
detectChangesAndCheck(rootTC, 'init baz');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
xit,
|
xit,
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
import {Component, Directive, NgNonBindable, View} from 'angular2/core';
|
import {Component, Directive, View} from 'angular2/core';
|
||||||
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
|
@ -66,7 +66,7 @@ class TestDirective {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'test-cmp'})
|
@Component({selector: 'test-cmp'})
|
||||||
@View({directives: [NgNonBindable, TestDirective]})
|
@View({directives: [TestDirective]})
|
||||||
class TestComponent {
|
class TestComponent {
|
||||||
text: string;
|
text: string;
|
||||||
constructor() { this.text = 'foo'; }
|
constructor() { this.text = 'foo'; }
|
||||||
|
|
|
@ -31,6 +31,7 @@ import {
|
||||||
Validators,
|
Validators,
|
||||||
} from 'angular2/core';
|
} from 'angular2/core';
|
||||||
import {By} from 'angular2/src/core/debug';
|
import {By} from 'angular2/src/core/debug';
|
||||||
|
import {ListWrapper} from 'angular2/src/core/facade/collection';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe("integration tests", () => {
|
describe("integration tests", () => {
|
||||||
|
@ -660,21 +661,18 @@ export function main() {
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
var input = rootTC.debugElement.query(By.css("input")).nativeElement;
|
var input = rootTC.debugElement.query(By.css("input")).nativeElement;
|
||||||
expect(DOM.classList(input))
|
expect(sortedClassList(input)).toEqual(['ng-invalid', 'ng-pristine', 'ng-untouched']);
|
||||||
.toEqual(['ng-binding', 'ng-invalid', 'ng-pristine', 'ng-untouched']);
|
|
||||||
|
|
||||||
dispatchEvent(input, "blur");
|
dispatchEvent(input, "blur");
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
expect(DOM.classList(input))
|
expect(sortedClassList(input)).toEqual(["ng-invalid", "ng-pristine", "ng-touched"]);
|
||||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-touched"]);
|
|
||||||
|
|
||||||
input.value = "updatedValue";
|
input.value = "updatedValue";
|
||||||
dispatchEvent(input, "change");
|
dispatchEvent(input, "change");
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
expect(DOM.classList(input))
|
expect(sortedClassList(input)).toEqual(["ng-dirty", "ng-touched", "ng-valid"]);
|
||||||
.toEqual(["ng-binding", "ng-touched", "ng-dirty", "ng-valid"]);
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -690,21 +688,18 @@ export function main() {
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
var input = rootTC.debugElement.query(By.css("input")).nativeElement;
|
var input = rootTC.debugElement.query(By.css("input")).nativeElement;
|
||||||
expect(DOM.classList(input))
|
expect(sortedClassList(input)).toEqual(["ng-invalid", "ng-pristine", "ng-untouched"]);
|
||||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-untouched"]);
|
|
||||||
|
|
||||||
dispatchEvent(input, "blur");
|
dispatchEvent(input, "blur");
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
expect(DOM.classList(input))
|
expect(sortedClassList(input)).toEqual(["ng-invalid", "ng-pristine", "ng-touched"]);
|
||||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-touched"]);
|
|
||||||
|
|
||||||
input.value = "updatedValue";
|
input.value = "updatedValue";
|
||||||
dispatchEvent(input, "change");
|
dispatchEvent(input, "change");
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
expect(DOM.classList(input))
|
expect(sortedClassList(input)).toEqual(["ng-dirty", "ng-touched", "ng-valid"]);
|
||||||
.toEqual(["ng-binding", "ng-touched", "ng-dirty", "ng-valid"]);
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -718,21 +713,18 @@ export function main() {
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
var input = rootTC.debugElement.query(By.css("input")).nativeElement;
|
var input = rootTC.debugElement.query(By.css("input")).nativeElement;
|
||||||
expect(DOM.classList(input))
|
expect(sortedClassList(input)).toEqual(["ng-invalid", "ng-pristine", "ng-untouched"]);
|
||||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-untouched"]);
|
|
||||||
|
|
||||||
dispatchEvent(input, "blur");
|
dispatchEvent(input, "blur");
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
expect(DOM.classList(input))
|
expect(sortedClassList(input)).toEqual(["ng-invalid", "ng-pristine", "ng-touched"]);
|
||||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-touched"]);
|
|
||||||
|
|
||||||
input.value = "updatedValue";
|
input.value = "updatedValue";
|
||||||
dispatchEvent(input, "change");
|
dispatchEvent(input, "change");
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
|
|
||||||
expect(DOM.classList(input))
|
expect(sortedClassList(input)).toEqual(["ng-dirty", "ng-touched", "ng-valid"]);
|
||||||
.toEqual(["ng-binding", "ng-touched", "ng-dirty", "ng-valid"]);
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -845,3 +837,9 @@ class MyComp {
|
||||||
name: string;
|
name: string;
|
||||||
data: any;
|
data: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sortedClassList(el) {
|
||||||
|
var l = DOM.classList(el);
|
||||||
|
ListWrapper.sort(l);
|
||||||
|
return l;
|
||||||
|
}
|
|
@ -34,27 +34,29 @@ export function main() {
|
||||||
() => { injector = Injector.resolveAndCreate([bind('dep').toValue('dependency')]); });
|
() => { injector = Injector.resolveAndCreate([bind('dep').toValue('dependency')]); });
|
||||||
|
|
||||||
it('should instantiate a pipe', () => {
|
it('should instantiate a pipe', () => {
|
||||||
var proto = new ProtoPipes([PipeBinding.createFromType(PipeA, new Pipe({name: 'a'}))]);
|
var proto =
|
||||||
|
ProtoPipes.fromBindings([PipeBinding.createFromType(PipeA, new Pipe({name: 'a'}))]);
|
||||||
var pipes = new Pipes(proto, injector);
|
var pipes = new Pipes(proto, injector);
|
||||||
|
|
||||||
expect(pipes.get("a").pipe).toBeAnInstanceOf(PipeA);
|
expect(pipes.get("a").pipe).toBeAnInstanceOf(PipeA);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw when no pipe found', () => {
|
it('should throw when no pipe found', () => {
|
||||||
var proto = new ProtoPipes([]);
|
var proto = ProtoPipes.fromBindings([]);
|
||||||
var pipes = new Pipes(proto, injector);
|
var pipes = new Pipes(proto, injector);
|
||||||
expect(() => pipes.get("invalid")).toThrowErrorWith("Cannot find pipe 'invalid'");
|
expect(() => pipes.get("invalid")).toThrowErrorWith("Cannot find pipe 'invalid'");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inject dependencies from the provided injector', () => {
|
it('should inject dependencies from the provided injector', () => {
|
||||||
var proto = new ProtoPipes([PipeBinding.createFromType(PipeB, new Pipe({name: 'b'}))]);
|
var proto =
|
||||||
|
ProtoPipes.fromBindings([PipeBinding.createFromType(PipeB, new Pipe({name: 'b'}))]);
|
||||||
var pipes = new Pipes(proto, injector);
|
var pipes = new Pipes(proto, injector);
|
||||||
expect((<any>pipes.get("b").pipe).dep).toEqual("dependency");
|
expect((<any>pipes.get("b").pipe).dep).toEqual("dependency");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should cache pure pipes', () => {
|
it('should cache pure pipes', () => {
|
||||||
var proto =
|
var proto = ProtoPipes.fromBindings(
|
||||||
new ProtoPipes([PipeBinding.createFromType(PipeA, new Pipe({name: 'a', pure: true}))]);
|
[PipeBinding.createFromType(PipeA, new Pipe({name: 'a', pure: true}))]);
|
||||||
var pipes = new Pipes(proto, injector);
|
var pipes = new Pipes(proto, injector);
|
||||||
|
|
||||||
expect(pipes.get("a").pure).toEqual(true);
|
expect(pipes.get("a").pure).toEqual(true);
|
||||||
|
@ -62,8 +64,8 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT cache impure pipes', () => {
|
it('should NOT cache impure pipes', () => {
|
||||||
var proto =
|
var proto = ProtoPipes.fromBindings(
|
||||||
new ProtoPipes([PipeBinding.createFromType(PipeA, new Pipe({name: 'a', pure: false}))]);
|
[PipeBinding.createFromType(PipeA, new Pipe({name: 'a', pure: false}))]);
|
||||||
var pipes = new Pipes(proto, injector);
|
var pipes = new Pipes(proto, injector);
|
||||||
|
|
||||||
expect(pipes.get("a").pure).toEqual(false);
|
expect(pipes.get("a").pure).toEqual(false);
|
||||||
|
|
|
@ -248,15 +248,11 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (IS_DART) {
|
if (IS_DART) {
|
||||||
describe("moduleId", () => {
|
describe("importUri", () => {
|
||||||
it("should return the moduleId for a type", () => {
|
it("should return the importUri for a type", () => {
|
||||||
expect(reflector.moduleId(TestObjWith00Args))
|
expect(reflector.importUri(TestObjWith00Args)
|
||||||
.toEqual('base/dist/dart/angular2/test/core/reflection/reflector_spec');
|
.endsWith('base/dist/dart/angular2/test/core/reflection/reflector_spec.dart'))
|
||||||
});
|
.toBe(true);
|
||||||
|
|
||||||
it("should return an empty array otherwise", () => {
|
|
||||||
var p = reflector.interfaces(ClassWithDecorators);
|
|
||||||
expect(p).toEqual([]);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,266 +13,22 @@ import {
|
||||||
SpyObject,
|
SpyObject,
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
|
|
||||||
import {MapWrapper} from 'angular2/src/core/facade/collection';
|
// import {MapWrapper} from 'angular2/src/core/facade/collection';
|
||||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
// import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
|
|
||||||
import {DomTestbed, TestRootView, elRef} from './dom_testbed';
|
// import {DomTestbed, TestRootView, elRef} from './dom_testbed';
|
||||||
|
|
||||||
import {
|
// import {
|
||||||
ViewDefinition,
|
// ViewDefinition,
|
||||||
RenderDirectiveMetadata,
|
// RenderDirectiveMetadata,
|
||||||
RenderViewRef,
|
// RenderViewRef,
|
||||||
ViewEncapsulation
|
// ViewEncapsulation
|
||||||
} from 'angular2/src/core/render/api';
|
// } from 'angular2/src/core/render/api';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('DomRenderer integration', () => {
|
describe('DomRenderer integration', () => {
|
||||||
beforeEachBindings(() => [DomTestbed]);
|
it('should work', () => {
|
||||||
|
// TODO
|
||||||
it('should create and destroy root host views while using the given elements in place',
|
|
||||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
|
||||||
tb.compiler.compileHost(someComponent)
|
|
||||||
.then((hostProtoViewDto) => {
|
|
||||||
var view = new TestRootView(
|
|
||||||
tb.renderer.createRootHostView(hostProtoViewDto.render, 0, '#root'));
|
|
||||||
expect(tb.rootEl.parentNode).toBeTruthy();
|
|
||||||
expect(view.hostElement).toEqual(tb.rootEl);
|
|
||||||
|
|
||||||
tb.renderer.detachFragment(view.fragments[0]);
|
|
||||||
tb.renderer.destroyView(view.viewRef);
|
|
||||||
expect(tb.rootEl.parentNode).toBeFalsy();
|
|
||||||
|
|
||||||
async.done();
|
|
||||||
});
|
});
|
||||||
}));
|
|
||||||
|
|
||||||
it('should update text nodes',
|
|
||||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
|
||||||
tb.compileAndMerge(
|
|
||||||
someComponent,
|
|
||||||
[
|
|
||||||
new ViewDefinition(
|
|
||||||
{componentId: 'someComponent', template: '{{a}}', directives: []})
|
|
||||||
])
|
|
||||||
.then((protoViewMergeMappings) => {
|
|
||||||
var rootView = tb.createView(protoViewMergeMappings);
|
|
||||||
|
|
||||||
tb.renderer.setText(rootView.viewRef, 0, 'hello');
|
|
||||||
expect(rootView.hostElement).toHaveText('hello');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should update any element property/attributes/class/style independent of the compilation on the root element and other elements',
|
|
||||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
|
||||||
tb.compileAndMerge(someComponent,
|
|
||||||
[
|
|
||||||
new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '<input [title]="y" style="position:absolute">',
|
|
||||||
directives: []
|
|
||||||
})
|
|
||||||
])
|
|
||||||
.then((protoViewMergeMappings) => {
|
|
||||||
|
|
||||||
var checkSetters = (elr, el) => {
|
|
||||||
tb.renderer.setElementProperty(elr, 'tabIndex', 1);
|
|
||||||
expect((<HTMLInputElement>el).tabIndex).toEqual(1);
|
|
||||||
|
|
||||||
tb.renderer.setElementClass(elr, 'a', true);
|
|
||||||
expect(DOM.hasClass(el, 'a')).toBe(true);
|
|
||||||
tb.renderer.setElementClass(elr, 'a', false);
|
|
||||||
expect(DOM.hasClass(el, 'a')).toBe(false);
|
|
||||||
|
|
||||||
tb.renderer.setElementStyle(elr, 'width', '10px');
|
|
||||||
expect(DOM.getStyle(el, 'width')).toEqual('10px');
|
|
||||||
tb.renderer.setElementStyle(elr, 'width', null);
|
|
||||||
expect(DOM.getStyle(el, 'width')).toEqual('');
|
|
||||||
|
|
||||||
tb.renderer.setElementAttribute(elr, 'someAttr', 'someValue');
|
|
||||||
expect(DOM.getAttribute(el, 'some-attr')).toEqual('someValue');
|
|
||||||
};
|
|
||||||
|
|
||||||
var rootView = tb.createView(protoViewMergeMappings);
|
|
||||||
// root element
|
|
||||||
checkSetters(elRef(rootView.viewRef, 0), rootView.hostElement);
|
|
||||||
// nested elements
|
|
||||||
checkSetters(elRef(rootView.viewRef, 1), DOM.firstChild(rootView.hostElement));
|
|
||||||
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (DOM.supportsDOMEvents()) {
|
|
||||||
it('should call actions on the element independent of the compilation',
|
|
||||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
|
||||||
tb.compileAndMerge(someComponent,
|
|
||||||
[
|
|
||||||
new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '<input [title]="y"></input>',
|
|
||||||
directives: []
|
|
||||||
})
|
|
||||||
])
|
|
||||||
.then((protoViewMergeMappings) => {
|
|
||||||
var rootView = tb.createView(protoViewMergeMappings);
|
|
||||||
|
|
||||||
tb.renderer.invokeElementMethod(elRef(rootView.viewRef, 1), 'setAttribute',
|
|
||||||
['a', 'b']);
|
|
||||||
|
|
||||||
expect(DOM.getAttribute(DOM.childNodes(rootView.hostElement)[0], 'a'))
|
|
||||||
.toEqual('b');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should add and remove fragments',
|
|
||||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
|
||||||
tb.compileAndMerge(someComponent,
|
|
||||||
[
|
|
||||||
new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '<template>hello</template>',
|
|
||||||
directives: []
|
|
||||||
})
|
|
||||||
])
|
|
||||||
.then((protoViewMergeMappings) => {
|
|
||||||
var rootView = tb.createView(protoViewMergeMappings);
|
|
||||||
|
|
||||||
var elr = elRef(rootView.viewRef, 1);
|
|
||||||
expect(rootView.hostElement).toHaveText('');
|
|
||||||
var fragment = rootView.fragments[1];
|
|
||||||
tb.renderer.attachFragmentAfterElement(elr, fragment);
|
|
||||||
expect(rootView.hostElement).toHaveText('hello');
|
|
||||||
tb.renderer.detachFragment(fragment);
|
|
||||||
expect(rootView.hostElement).toHaveText('');
|
|
||||||
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should add and remove empty fragments',
|
|
||||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
|
||||||
tb.compileAndMerge(someComponent,
|
|
||||||
[
|
|
||||||
new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '<template></template><template></template>',
|
|
||||||
directives: []
|
|
||||||
})
|
|
||||||
])
|
|
||||||
.then((protoViewMergeMappings) => {
|
|
||||||
var rootView = tb.createView(protoViewMergeMappings);
|
|
||||||
|
|
||||||
var elr = elRef(rootView.viewRef, 1);
|
|
||||||
expect(rootView.hostElement).toHaveText('');
|
|
||||||
var fragment = rootView.fragments[1];
|
|
||||||
var fragment2 = rootView.fragments[2];
|
|
||||||
tb.renderer.attachFragmentAfterElement(elr, fragment);
|
|
||||||
tb.renderer.attachFragmentAfterFragment(fragment, fragment2);
|
|
||||||
tb.renderer.detachFragment(fragment);
|
|
||||||
tb.renderer.detachFragment(fragment2);
|
|
||||||
expect(rootView.hostElement).toHaveText('');
|
|
||||||
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should handle events', inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
|
||||||
tb.compileAndMerge(someComponent,
|
|
||||||
[
|
|
||||||
new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '<input (change)="doSomething()">',
|
|
||||||
directives: []
|
|
||||||
})
|
|
||||||
])
|
|
||||||
.then((protoViewMergeMappings) => {
|
|
||||||
var rootView = tb.createView(protoViewMergeMappings);
|
|
||||||
|
|
||||||
tb.triggerEvent(elRef(rootView.viewRef, 1), 'change');
|
|
||||||
var eventEntry = rootView.events[0];
|
|
||||||
// bound element index
|
|
||||||
expect(eventEntry[0]).toEqual(1);
|
|
||||||
// event type
|
|
||||||
expect(eventEntry[1]).toEqual('change');
|
|
||||||
// actual event
|
|
||||||
expect((<Map<any, any>>eventEntry[2]).get('$event').type).toEqual('change');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (DOM.supportsNativeShadowDOM()) {
|
|
||||||
describe('native shadow dom support', () => {
|
|
||||||
it('should put the template into a shadow root',
|
|
||||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
|
||||||
tb.compileAndMerge(someComponent,
|
|
||||||
[
|
|
||||||
new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: 'hello',
|
|
||||||
directives: [],
|
|
||||||
encapsulation: ViewEncapsulation.Native
|
|
||||||
})
|
|
||||||
])
|
|
||||||
.then((protoViewMergeMappings) => {
|
|
||||||
var rootView = tb.createView(protoViewMergeMappings);
|
|
||||||
expect(DOM.getShadowRoot(rootView.hostElement)).toHaveText('hello');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should add styles from non native components to shadow roots while the view is not destroyed',
|
|
||||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
|
||||||
tb.compileAndMerge(someComponent,
|
|
||||||
[
|
|
||||||
new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '',
|
|
||||||
directives: [],
|
|
||||||
encapsulation: ViewEncapsulation.Native,
|
|
||||||
styles: ['a {};']
|
|
||||||
})
|
|
||||||
])
|
|
||||||
.then((protoViewMergeMappings) => {
|
|
||||||
var rootView = tb.createView(protoViewMergeMappings);
|
|
||||||
tb.compiler.compile(new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '',
|
|
||||||
directives: [],
|
|
||||||
encapsulation: ViewEncapsulation.None,
|
|
||||||
styles: ['b {};']
|
|
||||||
}))
|
|
||||||
.then(_ => {
|
|
||||||
expect(DOM.getShadowRoot(rootView.hostElement)).toHaveText('a {};b {};');
|
|
||||||
tb.renderer.destroyView(rootView.viewRef);
|
|
||||||
tb.compiler.compile(new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '',
|
|
||||||
directives: [],
|
|
||||||
encapsulation: ViewEncapsulation.None,
|
|
||||||
styles: ['c {};']
|
|
||||||
}))
|
|
||||||
.then(_ => {
|
|
||||||
expect(DOM.getShadowRoot(rootView.hostElement))
|
|
||||||
.toHaveText('a {};b {};');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export var someComponent = RenderDirectiveMetadata.create(
|
|
||||||
{id: 'someComponent', type: RenderDirectiveMetadata.COMPONENT_TYPE, selector: 'some-comp'});
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import 'package:angular2/src/core/compiler/directive_resolver.dart';
|
||||||
import 'package:angular2/src/core/compiler/view.dart';
|
import 'package:angular2/src/core/compiler/view.dart';
|
||||||
import 'package:angular2/src/core/compiler/element_ref.dart';
|
import 'package:angular2/src/core/compiler/element_ref.dart';
|
||||||
import 'package:angular2/src/core/compiler/view_manager.dart';
|
import 'package:angular2/src/core/compiler/view_manager.dart';
|
||||||
|
import 'package:angular2/src/core/compiler/proto_view_factory.dart';
|
||||||
import 'package:angular2/src/core/compiler/view_pool.dart';
|
import 'package:angular2/src/core/compiler/view_pool.dart';
|
||||||
import 'package:angular2/src/core/compiler/view_listener.dart';
|
import 'package:angular2/src/core/compiler/view_listener.dart';
|
||||||
import 'package:angular2/src/core/compiler/element_injector.dart';
|
import 'package:angular2/src/core/compiler/element_injector.dart';
|
||||||
|
@ -91,6 +92,11 @@ class SpyAppViewListener extends SpyObject implements AppViewListener {
|
||||||
noSuchMethod(m) => super.noSuchMethod(m);
|
noSuchMethod(m) => super.noSuchMethod(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@proxy
|
||||||
|
class SpyProtoViewFactory extends SpyObject implements ProtoViewFactory {
|
||||||
|
noSuchMethod(m) => super.noSuchMethod(m);
|
||||||
|
}
|
||||||
|
|
||||||
@proxy
|
@proxy
|
||||||
class SpyProtoElementInjector extends SpyObject implements ProtoElementInjector {
|
class SpyProtoElementInjector extends SpyObject implements ProtoElementInjector {
|
||||||
noSuchMethod(m) => super.noSuchMethod(m);
|
noSuchMethod(m) => super.noSuchMethod(m);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
||||||
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||||
import {AppViewPool} from 'angular2/src/core/compiler/view_pool';
|
import {AppViewPool} from 'angular2/src/core/compiler/view_pool';
|
||||||
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
|
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
|
||||||
|
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||||
import {DomAdapter} from 'angular2/src/core/dom/dom_adapter';
|
import {DomAdapter} from 'angular2/src/core/dom/dom_adapter';
|
||||||
import {ClientMessageBroker} from 'angular2/src/web_workers/shared/client_message_broker';
|
import {ClientMessageBroker} from 'angular2/src/web_workers/shared/client_message_broker';
|
||||||
import {XHR} from 'angular2/src/core/render/xhr';
|
import {XHR} from 'angular2/src/core/render/xhr';
|
||||||
|
@ -76,6 +77,10 @@ export class SpyAppViewListener extends SpyObject {
|
||||||
constructor() { super(AppViewListener); }
|
constructor() { super(AppViewListener); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SpyProtoViewFactory extends SpyObject {
|
||||||
|
constructor() { super(ProtoViewFactory); }
|
||||||
|
}
|
||||||
|
|
||||||
export class SpyProtoElementInjector extends SpyObject {
|
export class SpyProtoElementInjector extends SpyObject {
|
||||||
constructor() { super(ProtoElementInjector); }
|
constructor() { super(ProtoElementInjector); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,10 +152,10 @@ var NG_API = [
|
||||||
'Class:js',
|
'Class:js',
|
||||||
'Compiler',
|
'Compiler',
|
||||||
'Compiler.compileInHost()',
|
'Compiler.compileInHost()',
|
||||||
|
'Compiler.clearCache()',
|
||||||
'Component',
|
'Component',
|
||||||
'Component.bindings',
|
'Component.bindings',
|
||||||
'Component.changeDetection',
|
'Component.changeDetection',
|
||||||
'Component.compileChildren',
|
|
||||||
'Component.outputs',
|
'Component.outputs',
|
||||||
'Component.exportAs',
|
'Component.exportAs',
|
||||||
'Component.host',
|
'Component.host',
|
||||||
|
@ -167,7 +167,6 @@ var NG_API = [
|
||||||
'ComponentMetadata',
|
'ComponentMetadata',
|
||||||
'ComponentMetadata.bindings',
|
'ComponentMetadata.bindings',
|
||||||
'ComponentMetadata.changeDetection',
|
'ComponentMetadata.changeDetection',
|
||||||
'ComponentMetadata.compileChildren',
|
|
||||||
'ComponentMetadata.outputs',
|
'ComponentMetadata.outputs',
|
||||||
'ComponentMetadata.exportAs',
|
'ComponentMetadata.exportAs',
|
||||||
'ComponentMetadata.host',
|
'ComponentMetadata.host',
|
||||||
|
@ -372,7 +371,6 @@ var NG_API = [
|
||||||
'DependencyMetadata.token',
|
'DependencyMetadata.token',
|
||||||
'Directive',
|
'Directive',
|
||||||
'Directive.bindings',
|
'Directive.bindings',
|
||||||
'Directive.compileChildren',
|
|
||||||
'Directive.outputs',
|
'Directive.outputs',
|
||||||
'Directive.exportAs',
|
'Directive.exportAs',
|
||||||
'Directive.host',
|
'Directive.host',
|
||||||
|
@ -382,7 +380,6 @@ var NG_API = [
|
||||||
'Directive.selector',
|
'Directive.selector',
|
||||||
'DirectiveMetadata',
|
'DirectiveMetadata',
|
||||||
'DirectiveMetadata.bindings',
|
'DirectiveMetadata.bindings',
|
||||||
'DirectiveMetadata.compileChildren',
|
|
||||||
'DirectiveMetadata.outputs',
|
'DirectiveMetadata.outputs',
|
||||||
'DirectiveMetadata.exportAs',
|
'DirectiveMetadata.exportAs',
|
||||||
'DirectiveMetadata.host',
|
'DirectiveMetadata.host',
|
||||||
|
@ -720,7 +717,6 @@ var NG_API = [
|
||||||
'NgModel.viewModel',
|
'NgModel.viewModel',
|
||||||
'NgModel.viewModel=',
|
'NgModel.viewModel=',
|
||||||
'NgModel.viewToModelUpdate()',
|
'NgModel.viewToModelUpdate()',
|
||||||
'NgNonBindable',
|
|
||||||
'NgSelectOption',
|
'NgSelectOption',
|
||||||
'NgStyle',
|
'NgStyle',
|
||||||
'NgStyle.doCheck()',
|
'NgStyle.doCheck()',
|
||||||
|
@ -899,6 +895,8 @@ var NG_API = [
|
||||||
'Renderer',
|
'Renderer',
|
||||||
'Renderer.attachFragmentAfterElement()',
|
'Renderer.attachFragmentAfterElement()',
|
||||||
'Renderer.attachFragmentAfterFragment()',
|
'Renderer.attachFragmentAfterFragment()',
|
||||||
|
'Renderer.createProtoView()',
|
||||||
|
'Renderer.registerComponentTemplate()',
|
||||||
'Renderer.createRootHostView()',
|
'Renderer.createRootHostView()',
|
||||||
'Renderer.createView()',
|
'Renderer.createView()',
|
||||||
'Renderer.dehydrateView()',
|
'Renderer.dehydrateView()',
|
||||||
|
@ -967,7 +965,6 @@ var NG_API = [
|
||||||
'UpperCasePipe',
|
'UpperCasePipe',
|
||||||
'UpperCasePipe.transform()',
|
'UpperCasePipe.transform()',
|
||||||
'UrlResolver',
|
'UrlResolver',
|
||||||
'UrlResolver.packagePrefix',
|
|
||||||
'UrlResolver.resolve()',
|
'UrlResolver.resolve()',
|
||||||
'Validators#array()',
|
'Validators#array()',
|
||||||
'Validators#compose()',
|
'Validators#compose()',
|
||||||
|
@ -1129,6 +1126,36 @@ var NG_API = [
|
||||||
'{OnInit}',
|
'{OnInit}',
|
||||||
'{PipeOnDestroy}',
|
'{PipeOnDestroy}',
|
||||||
'{PipeTransform}',
|
'{PipeTransform}',
|
||||||
|
'{RenderBeginCmd}',
|
||||||
|
'{RenderBeginCmd}.isBound',
|
||||||
|
'{RenderBeginCmd}.isBound=',
|
||||||
|
'{RenderBeginCmd}.ngContentIndex',
|
||||||
|
'{RenderBeginCmd}.ngContentIndex=',
|
||||||
|
'{RenderBeginComponentCmd}',
|
||||||
|
'{RenderBeginComponentCmd}.nativeShadow',
|
||||||
|
'{RenderBeginComponentCmd}.nativeShadow=',
|
||||||
|
'{RenderBeginComponentCmd}.templateId',
|
||||||
|
'{RenderBeginComponentCmd}.templateId=',
|
||||||
|
'{RenderBeginElementCmd}',
|
||||||
|
'{RenderBeginElementCmd}.attrNameAndValues',
|
||||||
|
'{RenderBeginElementCmd}.attrNameAndValues=',
|
||||||
|
'{RenderBeginElementCmd}.eventTargetAndNames',
|
||||||
|
'{RenderBeginElementCmd}.eventTargetAndNames=',
|
||||||
|
'{RenderBeginElementCmd}.name',
|
||||||
|
'{RenderBeginElementCmd}.name=',
|
||||||
|
'{RenderCommandVisitor}',
|
||||||
|
'{RenderEmbeddedTemplateCmd}',
|
||||||
|
'{RenderEmbeddedTemplateCmd}.children',
|
||||||
|
'{RenderEmbeddedTemplateCmd}.children=',
|
||||||
|
'{RenderEmbeddedTemplateCmd}.isMerged',
|
||||||
|
'{RenderEmbeddedTemplateCmd}.isMerged=',
|
||||||
|
'{RenderNgContentCmd}',
|
||||||
|
'{RenderNgContentCmd}.ngContentIndex',
|
||||||
|
'{RenderNgContentCmd}.ngContentIndex=',
|
||||||
|
'{RenderTemplateCmd}',
|
||||||
|
'{RenderTextCmd}',
|
||||||
|
'{RenderTextCmd}.value',
|
||||||
|
'{RenderTextCmd}.value=',
|
||||||
'{RenderElementRef}',
|
'{RenderElementRef}',
|
||||||
'{RenderElementRef}.renderBoundElementIndex',
|
'{RenderElementRef}.renderBoundElementIndex',
|
||||||
'{RenderElementRef}.renderBoundElementIndex=',
|
'{RenderElementRef}.renderBoundElementIndex=',
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue