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:
Tobias Bosch
2015-10-01 10:07:49 -07:00
parent 30ca0434a2
commit 76247b7097
124 changed files with 2013 additions and 3451 deletions

View File

@ -189,8 +189,7 @@ function createChangeDefinitions(pvVisitors: ProtoViewVisitor[], componentType:
genConfig: ChangeDetectorGenConfig): ChangeDetectorDefinition[] {
var pvVariableNames = _collectNestedProtoViewsVariableNames(pvVisitors);
return pvVisitors.map(pvVisitor => {
var viewType = pvVisitor.viewIndex === 0 ? 'component' : 'embedded';
var id = _protoViewId(componentType, pvVisitor.viewIndex, viewType);
var id = `${componentType.name}_${pvVisitor.viewIndex}`;
return new ChangeDetectorDefinition(
id, pvVisitor.strategy, pvVariableNames[pvVisitor.viewIndex], pvVisitor.bindingRecords,
pvVisitor.eventRecords, pvVisitor.directiveRecords, genConfig);
@ -207,9 +206,3 @@ function _collectNestedProtoViewsVariableNames(pvVisitors: ProtoViewVisitor[]):
});
return nestedPvVariableNames;
}
function _protoViewId(hostComponentType: CompileTypeMetadata, pvIndex: number, viewType: string):
string {
return `${hostComponentType.name}_${viewType}_${pvIndex}`;
}

View File

@ -16,17 +16,18 @@ import {
import {TemplateAst} from './template_ast';
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';
const ABSTRACT_CHANGE_DETECTOR = "AbstractChangeDetector";
const UTIL = "ChangeDetectionUtil";
var ABSTRACT_CHANGE_DETECTOR_MODULE =
moduleRef('angular2/src/core/change_detection/abstract_change_detector');
var UTIL_MODULE = moduleRef('angular2/src/core/change_detection/change_detection_util');
var PREGEN_PROTO_CHANGE_DETECTOR_MODULE =
moduleRef('angular2/src/core/change_detection/pregen_proto_change_detector');
var ABSTRACT_CHANGE_DETECTOR_MODULE = moduleRef(
`package:angular2/src/core/change_detection/abstract_change_detector${MODULE_SUFFIX}`);
var UTIL_MODULE =
moduleRef(`package:angular2/src/core/change_detection/change_detection_util${MODULE_SUFFIX}`);
var PREGEN_PROTO_CHANGE_DETECTOR_MODULE = moduleRef(
`package:angular2/src/core/change_detection/pregen_proto_change_detector${MODULE_SUFFIX}`);
@Injectable()
export class ChangeDetectionCompiler {
@ -54,24 +55,31 @@ export class ChangeDetectionCompiler {
var changeDetectorDefinitions =
createChangeDetectorDefinitions(componentType, strategy, this._genConfig, parsedTemplate);
var factories = [];
var index = 0;
var sourceParts = changeDetectorDefinitions.map(definition => {
var codegen: any;
var sourcePart;
// TODO(tbosch): move the 2 code generators to the same place, one with .dart and one with .ts
// suffix
// and have the same API for calling them!
if (IS_DART) {
codegen = new Codegen(PREGEN_PROTO_CHANGE_DETECTOR_MODULE);
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)`);
return codegen.toString();
sourcePart = codegen.toString();
} else {
codegen = new ChangeDetectorJITGenerator(
definition, `${UTIL_MODULE}${UTIL}`,
`${ABSTRACT_CHANGE_DETECTOR_MODULE}${ABSTRACT_CHANGE_DETECTOR}`);
factories.push(`function(dispatcher) { return new ${codegen.typeName}(dispatcher); }`);
return codegen.generateSource();
sourcePart = codegen.generateSource();
}
index++;
return sourcePart;
});
return new SourceExpressions(sourceParts, factories);
}

View File

@ -37,10 +37,11 @@ import {
shimContentAttributeExpr,
shimHostAttributeExpr
} from './style_compiler';
import {escapeSingleQuoteString} from './util';
import {escapeSingleQuoteString, MODULE_SUFFIX} from './util';
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';
@ -353,6 +354,6 @@ function codeGenArray(data: any[]): string {
function codeGenDirectivesArray(directives: CompileDirectiveMetadata[]): string {
var expressions = directives.map(
directiveType => `${moduleRef(directiveType.type.moduleId)}${directiveType.type.name}`);
directiveType => `${moduleRef(directiveType.type.moduleUrl)}${directiveType.type.name}`);
return `[${expressions.join(',')}]`;
}

View File

@ -17,6 +17,12 @@ import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
import {TemplateCompiler} from 'angular2/src/compiler/template_compiler';
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[]> {
return [
@ -31,5 +37,9 @@ export function compilerBindings(): Array<Type | Binding | any[]> {
.toValue(
new ChangeDetectorGenConfig(assertionsEnabled(), assertionsEnabled(), false, true)),
TemplateCompiler,
RuntimeCompiler,
bind(Compiler).toAlias(RuntimeCompiler),
DomElementSchemaRegistry,
bind(ElementSchemaRegistry).toAlias(DomElementSchemaRegistry)
];
}

View File

@ -24,22 +24,27 @@ var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
export class CompileTypeMetadata {
runtime: Type;
name: string;
moduleId: string;
constructor({runtime, name, moduleId}: {runtime?: Type, name?: string, moduleId?: string} = {}) {
moduleUrl: string;
isHost: boolean;
constructor({runtime, name, moduleUrl, isHost}:
{runtime?: Type, name?: string, moduleUrl?: string, isHost?: boolean} = {}) {
this.runtime = runtime;
this.name = name;
this.moduleId = moduleId;
this.moduleUrl = moduleUrl;
this.isHost = normalizeBool(isHost);
}
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> {
return {
// Note: Runtime type can't be serialized...
'name': this.name,
'moduleId': this.moduleId
'moduleUrl': this.moduleUrl,
'isHost': this.isHost
};
}
}
@ -248,8 +253,12 @@ export function createHostComponentMeta(componentType: CompileTypeMetadata,
componentSelector: string): CompileDirectiveMetadata {
var template = CssSelector.parse(componentSelector)[0].getMatchingElementTemplate();
return CompileDirectiveMetadata.create({
type: new CompileTypeMetadata(
{runtime: Object, name: `Host${componentType.name}`, moduleId: componentType.moduleId}),
type: new CompileTypeMetadata({
runtime: Object,
name: `Host${componentType.name}`,
moduleUrl: componentType.moduleUrl,
isHost: true
}),
template: new CompileTemplateMetadata(
{template: template, templateUrl: '', styles: [], styleUrls: [], ngContentSelectors: []}),
changeDetection: ChangeDetectionStrategy.Default,

View File

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

View File

@ -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 {reflector} from 'angular2/src/core/reflection/reflection';
import {Injectable} from 'angular2/src/core/di';
import {MODULE_SUFFIX} from './util';
// group 1: "property" from "[property]"
// group 2: "event" from "(event)"
@ -33,7 +34,7 @@ export class RuntimeMetadataResolver {
var meta = this._cache.get(directiveType);
if (isBlank(meta)) {
var directiveAnnotation = this._directiveResolver.resolve(directiveType);
var moduleId = calcModuleId(directiveType, directiveAnnotation);
var moduleUrl = calcModuleUrl(directiveType, directiveAnnotation);
var templateMeta = null;
var changeDetectionStrategy = null;
@ -55,7 +56,7 @@ export class RuntimeMetadataResolver {
isComponent: isPresent(templateMeta),
dynamicLoadable: true,
type: new cpl.CompileTypeMetadata(
{name: stringify(directiveType), moduleId: moduleId, runtime: directiveType}),
{name: stringify(directiveType), moduleUrl: moduleUrl, runtime: directiveType}),
template: templateMeta,
changeDetection: changeDetectionStrategy,
inputs: directiveAnnotation.inputs,
@ -111,10 +112,10 @@ function isValidDirective(value: Type): boolean {
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)) {
return directiveAnnotation.moduleId;
return `package:${directiveAnnotation.moduleId}${MODULE_SUFFIX}`;
} else {
return reflector.moduleId(type);
return reflector.importUri(type);
}
}

View File

@ -2,28 +2,28 @@ import {StringWrapper, isBlank} from 'angular2/src/core/facade/lang';
var MODULE_REGEXP = /#MODULE\[([^\]]*)\]/g;
export function moduleRef(moduleId): string {
return `#MODULE[${moduleId}]`;
export function moduleRef(moduleUrl): string {
return `#MODULE[${moduleUrl}]`;
}
export class SourceModule {
constructor(public moduleId: string, public sourceWithModuleRefs: string) {}
constructor(public moduleUrl: string, public sourceWithModuleRefs: string) {}
getSourceWithImports(): SourceWithImports {
var moduleAliases = {};
var imports: string[][] = [];
var newSource =
StringWrapper.replaceAllMapped(this.sourceWithModuleRefs, MODULE_REGEXP, (match) => {
var moduleId = match[1];
var alias = moduleAliases[moduleId];
var moduleUrl = match[1];
var alias = moduleAliases[moduleUrl];
if (isBlank(alias)) {
if (moduleId == this.moduleId) {
if (moduleUrl == this.moduleUrl) {
alias = '';
} else {
alias = `import${imports.length}`;
imports.push([moduleId, alias]);
imports.push([moduleUrl, alias]);
}
moduleAliases[moduleId] = alias;
moduleAliases[moduleUrl] = alias;
}
return alias.length > 0 ? `${alias}.` : '';
});

View File

@ -14,7 +14,8 @@ import {
codeGenMapArray,
codeGenReplaceAll,
codeGenExportVariable,
codeGenToString
codeGenToString,
MODULE_SUFFIX
} from './util';
import {Injectable} from 'angular2/src/core/di';
@ -56,13 +57,15 @@ export class StyleCompiler {
return this._styleCodeGen(template.styles, template.styleUrls, shim, suffix);
}
compileStylesheetCodeGen(moduleId: string, cssText: string): SourceModule[] {
var styleWithImports = resolveStyleUrls(this._urlResolver, moduleId, cssText);
compileStylesheetCodeGen(stylesheetUrl: string, cssText: string): SourceModule[] {
var styleWithImports = resolveStyleUrls(this._urlResolver, stylesheetUrl, cssText);
return [
this._styleModule(moduleId, false, this._styleCodeGen([styleWithImports.style],
styleWithImports.styleUrls, false, '')),
this._styleModule(moduleId, true, this._styleCodeGen([styleWithImports.style],
styleWithImports.styleUrls, true, ''))
this._styleModule(
stylesheetUrl, false,
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, false, '')),
this._styleModule(
stylesheetUrl, true,
this._styleCodeGen([styleWithImports.style], styleWithImports.styleUrls, true, ''))
];
}
@ -96,28 +99,28 @@ export class StyleCompiler {
expressionSource +=
`[${plainStyles.map( plainStyle => escapeSingleQuoteString(this._shimIfNeeded(plainStyle, shim)) ).join(',')}]`;
for (var i = 0; i < absUrls.length; i++) {
var moduleId = this._shimModuleIdIfNeeded(absUrls[i], shim);
expressionSource += codeGenConcatArray(`${moduleRef(moduleId)}STYLES`);
var moduleUrl = this._createModuleUrl(absUrls[i], shim);
expressionSource += codeGenConcatArray(`${moduleRef(moduleUrl)}STYLES`);
}
expressionSource += `)${suffix}`;
return new SourceExpression([], expressionSource);
}
private _styleModule(moduleId: string, shim: boolean,
private _styleModule(stylesheetUrl: string, shim: boolean,
expression: SourceExpression): SourceModule {
var moduleSource = `
${expression.declarations.join('\n')}
${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 {
return shim ? this._shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR) : style;
}
private _shimModuleIdIfNeeded(moduleId: string, shim: boolean): string {
return shim ? `${moduleId}.shim` : moduleId;
private _createModuleUrl(stylesheetUrl: string, shim: boolean): string {
return shim ? `${stylesheetUrl}.shim${MODULE_SUFFIX}` : `${stylesheetUrl}${MODULE_SUFFIX}`;
}
}

View File

@ -26,7 +26,13 @@ import {RuntimeMetadataResolver} from './runtime_metadata';
import {APP_ID} from 'angular2/src/core/render/dom/dom_tokens';
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';
@Injectable()
@ -164,51 +170,54 @@ export class TemplateCompiler {
});
}
compileTemplatesCodeGen(moduleId: string,
components: NormalizedComponentWithViewDirectives[]): SourceModule {
compileTemplatesCodeGen(components: NormalizedComponentWithViewDirectives[]): SourceModule {
if (components.length === 0) {
throw new BaseException('No components given');
}
var declarations = [];
var templateArguments = [];
var componentMetas: CompileDirectiveMetadata[] = [];
var isHost: boolean[] = [];
var templateIdVariable = 'templateId';
var appIdVariable = 'appId';
components.forEach(componentWithDirs => {
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
assertComponent(compMeta);
componentMetas.push(compMeta);
isHost.push(false);
this._processTemplateCodeGen(compMeta, appIdVariable, templateIdVariable,
<CompileDirectiveMetadata[]>componentWithDirs.directives,
declarations, templateArguments);
if (compMeta.dynamicLoadable) {
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
componentMetas.push(hostMeta);
isHost.push(true);
this._processTemplateCodeGen(hostMeta, appIdVariable, templateIdVariable, [compMeta],
declarations, templateArguments);
}
});
ListWrapper.forEachWithIndex(componentMetas, (compMeta: CompileDirectiveMetadata,
index: number) => {
var templateDataFn = codeGenValueFn([templateIdVariable, appIdVariable],
var templateDataFn = codeGenValueFn([appIdVariable, templateIdVariable],
`[${(<any[]>templateArguments[index]).join(',')}]`);
var compiledTemplateExpr =
`new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledTemplate(${TEMPLATE_COMMANDS_MODULE_REF}nextTemplateId(),${templateDataFn})`;
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 =
`new ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${codeGenValueFn([], compiledTemplateExpr)})`;
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${factoryName})`;
} else {
variableValueExpr = compiledTemplateExpr;
}
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[] {
return this._styleCompiler.compileStylesheetCodeGen(moduleId, cssText);
compileStylesheetCodeGen(stylesheetUrl: string, cssText: string): SourceModule[] {
return this._styleCompiler.compileStylesheetCodeGen(stylesheetUrl, cssText);
}
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata, appIdExpr: string,
@ -248,8 +257,9 @@ function templateVariableName(type: CompileTypeMetadata): string {
return `${type.name}Template`;
}
function templateModuleName(moduleId: string): string {
return `${moduleId}.template`;
function templateModuleUrl(moduleUrl: string): string {
var urlWithoutSuffix = moduleUrl.substring(0, moduleUrl.length - MODULE_SUFFIX.length);
return `${urlWithoutSuffix}.template${MODULE_SUFFIX}`;
}
function addAll(source: any[], target: any[]) {
@ -259,5 +269,5 @@ function addAll(source: any[], target: any[]) {
}
function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string {
return `${moduleRef(templateModuleName(nestedCompType.type.moduleId))}${templateVariableName(nestedCompType.type)}`;
return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateVariableName(nestedCompType.type)}`;
}

View File

@ -34,9 +34,9 @@ export class TemplateNormalizer {
template: CompileTemplateMetadata): Promise<CompileTemplateMetadata> {
if (isPresent(template.template)) {
return PromiseWrapper.resolve(this.normalizeLoadedTemplate(
directiveType, template, template.template, directiveType.moduleId));
directiveType, template, template.template, directiveType.moduleUrl));
} 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)
.then(templateContent => this.normalizeLoadedTemplate(directiveType, template,
templateContent, sourceAbsUrl));
@ -55,7 +55,7 @@ export class TemplateNormalizer {
var allStyleAbsUrls =
visitor.styleUrls.map(url => this._urlResolver.resolve(templateAbsUrl, url))
.concat(templateMeta.styleUrls.map(
url => this._urlResolver.resolve(directiveType.moduleId, url)));
url => this._urlResolver.resolve(directiveType.moduleUrl, url)));
var allResolvedStyles = allStyles.map(style => {
var styleWithImports = resolveStyleUrls(this._urlResolver, templateAbsUrl, style);

View File

@ -7,6 +7,8 @@ var DOUBLE_QUOTE_ESCAPE_STRING_RE = /"|\\|\n|\$/g;
export var IS_DART = !isJsObject({});
export var MODULE_SUFFIX = IS_DART ? '.dart' : '.js';
export function camelCaseToDashCase(input: string): string {
return StringWrapper.replaceAllMapped(input, CAMEL_CASE_REGEXP,
(m) => { return '-' + m[1].toLowerCase(); });
@ -43,8 +45,9 @@ function escapeString(input: string, re: RegExp): string {
});
}
export function codeGenExportVariable(name: string): string {
return IS_DART ? `var ${name} = ` : `var ${name} = exports['${name}'] = `;
export function codeGenExportVariable(name: string, isConst: boolean = false): string {
var declaration = isConst ? `const ${name}` : `var ${name}`;
return IS_DART ? `${declaration} = ` : `${declaration} = exports['${name}'] = `;
}
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) {
return `(${params.join(',')}) => ${value}`;
return `${fnName}(${params.join(',')}) => ${value}`;
} else {
return `function(${params.join(',')}) { return ${value}; }`;
return `function ${fnName}(${params.join(',')}) { return ${value}; }`;
}
}

View File

@ -7,6 +7,7 @@ import 'package:angular2/src/core/reflection/reflection_capabilities.dart'
show ReflectionCapabilities;
import 'application_common.dart';
import 'package:angular2/src/compiler/compiler.dart';
import 'package:angular2/src/core/compiler/dynamic_component_loader.dart';
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,
[List componentInjectableBindings]) {
reflector.reflectionCapabilities = new ReflectionCapabilities();
return commonBootstrap(appComponentType, componentInjectableBindings);
var bindings = [compilerBindings()];
if (componentInjectableBindings != null) {
bindings.add(componentInjectableBindings);
}
return commonBootstrap(appComponentType, bindings);
}

View File

@ -1,6 +1,13 @@
// 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 {platform, commonBootstrap as bootstrap} from './application_common';
export {platform} from './application_common';
export {
PlatformRef,
ApplicationRef,
@ -9,3 +16,14 @@ export {
platformCommon,
platformBindings
} 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);
}

View File

@ -18,7 +18,6 @@ import {
import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {internalView} from 'angular2/src/core/compiler/view_ref';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
import {
Parser,
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 {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
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 {ViewResolver} from './compiler/view_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 {UrlResolver} from 'angular2/src/core/services/url_resolver';
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.
@ -95,15 +97,14 @@ export function applicationCommonBindings(): Array<Type | Binding | any[]> {
bestChangeDetection = new JitChangeDetection();
}
return [
compilerBindings(),
ProtoViewFactory,
Compiler,
APP_ID_RANDOM_BINDING,
AppViewPool,
bind(APP_VIEW_POOL_CAPACITY).toValue(10000),
AppViewManager,
AppViewManagerUtils,
AppViewListener,
Compiler,
CompilerCache,
ProtoViewFactory,
ViewResolver,
DEFAULT_PIPES,
bind(IterableDiffers).toValue(defaultIterableDiffers),

View File

@ -1,21 +1,3 @@
library angular2.src.core.bootstrap;
import 'dart:async';
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);
}
export './application.dart' show bootstrap;

View File

@ -1,4 +1,4 @@
// Note: This file only exists so that Dart users can import
// bootstrap from angular2/bootstrap. JS users should import
// from angular2/core.
export {commonBootstrap as bootstrap} from './application_common';
export {bootstrap} from './application';

View File

@ -1,95 +1,13 @@
import {Binding, resolveForwardRef, Injectable, Inject} from 'angular2/src/core/di';
import {DEFAULT_PIPES_TOKEN} from 'angular2/src/core/pipes';
import {
Type,
isBlank,
isType,
isPresent,
normalizeBlank,
stringify,
isArray,
isPromise
} from 'angular2/src/core/facade/lang';
import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
import {Injectable} from 'angular2/src/core/di';
import {Type, isBlank, stringify} from 'angular2/src/core/facade/lang';
import {BaseException} from 'angular2/src/core/facade/exceptions';
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
* can later be used to create and render a Component instance.
@ -99,271 +17,36 @@ export class CompilerCache {
*/
@Injectable()
export class Compiler {
private _compiling = new Map<Type, Promise<AppProtoView>>();
private _appUrl: string;
private _defaultPipes: Type[];
/**
* @private
*/
constructor(private _directiveResolver: DirectiveResolver, private _pipeResolver: PipeResolver,
@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;
}
constructor(private _protoViewFactory: ProtoViewFactory) {}
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> {
var r = wtfStartTimeRange('Compiler#compile()', stringify(componentType));
var hostAppProtoView = this._compilerCache.getHost(componentType);
var hostPvPromise;
if (isPresent(hostAppProtoView)) {
hostPvPromise = PromiseWrapper.resolve(hostAppProtoView);
} else {
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;
});
}
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(
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
var metadatas = reflector.annotations(componentType);
var compiledHostTemplate = null;
for (var i = 0; i < metadatas.length; i++) {
var metadata = metadatas[i];
if (metadata instanceof CompiledHostTemplate) {
compiledHostTemplate = metadata;
break;
}
}
var boundDirectives = this._removeDuplicatedDirectives(
directives.map(directive => this._bindDirective(directive)));
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[] {
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,
componentPath: Map<Type, AppProtoView>): Promise<AppProtoView> {
var nestedPVPromises = [];
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) {
if (isBlank(compiledHostTemplate)) {
throw new BaseException(
`Could not load '${stringify(directiveBinding.key.token)}' because it is not a component.`);
`No precompiled template for component ${stringify(componentType)} found`);
}
return PromiseWrapper.resolve(this._createProtoView(compiledHostTemplate));
}
private _createProtoView(compiledHostTemplate: CompiledHostTemplate): ProtoViewRef {
return this._protoViewFactory.createHost(compiledHostTemplate).ref;
}
clearCache() { this._protoViewFactory.clearCache(); }
}
export function internalCreateProtoView(compiler: Compiler,
compiledHostTemplate: CompiledHostTemplate): ProtoViewRef {
return (<any>compiler)._createProtoView(compiledHostTemplate);
}

View File

@ -119,7 +119,6 @@ export class DirectiveResolver {
bindings: dm.bindings,
exportAs: dm.exportAs,
moduleId: dm.moduleId,
compileChildren: dm.compileChildren,
queries: mergedQueries,
changeDetection: dm.changeDetection,
viewBindings: dm.viewBindings
@ -134,7 +133,6 @@ export class DirectiveResolver {
bindings: dm.bindings,
exportAs: dm.exportAs,
moduleId: dm.moduleId,
compileChildren: dm.compileChildren,
queries: mergedQueries
});
}

View File

@ -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 * as eiModule from './element_injector';
import {DirectiveBinding} from './element_injector';
import * as viewModule from './view';
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,
public protoElementInjector: eiModule.ProtoElementInjector,
public componentDirective: DirectiveBinding) {
public componentDirective: DirectiveBinding,
public nestedProtoView: viewModule.AppProtoView) {
if (isBlank(index)) {
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);
}
}

View File

@ -170,7 +170,7 @@ export class DirectiveBinding extends ResolvedBinding {
type: meta instanceof ComponentMetadata ? RenderDirectiveMetadata.COMPONENT_TYPE :
RenderDirectiveMetadata.DIRECTIVE_TYPE,
selector: meta.selector,
compileChildren: meta.compileChildren,
compileChildren: true,
outputs: meta.outputs,
host: isPresent(meta.host) ? MapWrapper.createFromStringMap(meta.host) : null,
inputs: meta.inputs,
@ -214,6 +214,7 @@ export class DirectiveBinding extends ResolvedBinding {
// TODO(rado): benchmark and consider rolling in as ElementInjector fields.
export class PreBuiltObjects {
nestedView: viewModule.AppView = null;
constructor(public viewManager: avmModule.AppViewManager, public view: viewModule.AppView,
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());
}
getNestedView(): viewModule.AppView { return this._preBuiltObjects.nestedView; }
getView(): viewModule.AppView { return this._preBuiltObjects.view; }
directParent(): ElementInjector { return this._proto.distanceToParent < 2 ? this.parent : null; }

View File

@ -33,6 +33,7 @@ export class ElementRef implements RenderElementRef {
/**
* @private
*
* TODO(tbosch): remove this when the new compiler lands
* Index of the element inside the `RenderViewRef`.
*
* This is used internally by the Angular framework to locate elements.
@ -42,11 +43,10 @@ export class ElementRef implements RenderElementRef {
/**
* @private
*/
constructor(parentView: ViewRef, boundElementIndex: number, renderBoundElementIndex: number,
private _renderer: Renderer) {
constructor(parentView: ViewRef, boundElementIndex: number, private _renderer: Renderer) {
this.parentView = parentView;
this.boundElementIndex = boundElementIndex;
this.renderBoundElementIndex = renderBoundElementIndex;
this.renderBoundElementIndex = boundElementIndex;
}
/**

View File

@ -1,8 +1,5 @@
import {Injectable} from 'angular2/src/core/di';
import {ListWrapper, MapWrapper} from 'angular2/src/core/facade/collection';
import {StringWrapper, isPresent, isBlank, assertionsEnabled} from 'angular2/src/core/facade/lang';
import {BaseException} from 'angular2/src/core/facade/exceptions';
import {isPresent, isBlank, Type, isArray, isNumber} from 'angular2/src/core/facade/lang';
import {reflector} from 'angular2/src/core/reflection/reflection';
import {
@ -17,23 +14,340 @@ import {
ASTWithSource
} 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 {
RenderDirectiveMetadata,
RenderElementBinder,
PropertyBindingType,
DirectiveBinder,
ProtoViewDto,
ViewType
ViewType,
RenderProtoViewRef
} 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 {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 {
_directiveRecordsMap = new Map<number, DirectiveRecord>();
_directiveRecordsMap: Map<number, DirectiveRecord> = new Map<number, DirectiveRecord>();
getEventBindingRecords(elementBinders: RenderElementBinder[],
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
* 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,
pvWithIndex: RenderProtoViewWithIndex): string {
var typeString;
@ -329,36 +586,6 @@ function _protoViewId(hostComponentMetadata: RenderDirectiveMetadata,
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[]):
string[][] {
var nestedPvVariableNames = ListWrapper.createFixedSize(nestedPvsWithIndex.length);
@ -382,150 +609,7 @@ function _createVariableNames(parentVariableNames: string[], renderProtoView): s
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 {
constructor(public renderProtoView: ProtoViewDto, public index: number,
public parentIndex: number, public boundElementIndex: number) {}
}
class ParentProtoElementInjectorWithDistance {
constructor(public protoElementInjector: ProtoElementInjector, public distance: number) {}
}

View File

@ -52,5 +52,7 @@ export class TemplateRef {
/**
* 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);
}
}

View File

@ -33,45 +33,12 @@ import {ViewRef, ProtoViewRef, internalView} from './view_ref';
import {ElementRef} from './element_ref';
import {ProtoPipes} from 'angular2/src/core/pipes/pipes';
import {camelCaseToDashCase} from 'angular2/src/core/render/dom/util';
import {TemplateCmd} from './template_commands';
export {DebugContext} from 'angular2/src/core/change_detection/interfaces';
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 {
// The order in this list matches the DOM order.
views: AppView[] = [];
@ -109,7 +76,6 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
ref: ViewRef;
changeDetector: ChangeDetector = null;
/**
* The context against which data-binding expressions in this view are evaluated against.
* This is always a component instance.
@ -125,10 +91,10 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
locals: Locals;
constructor(public renderer: renderApi.Renderer, public proto: AppProtoView,
public mainMergeMapping: AppProtoViewMergeMapping, public viewOffset: number,
public elementOffset: number, public textOffset: number,
public viewOffset: number, public elementOffset: number, public textOffset: number,
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.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 {
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;
}
var templateName = this.proto.variableBindings.get(contextName);
var templateName = this.proto.templateVariableBindings.get(contextName);
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
notifyOnBinding(b: BindingTarget, currentValue: any): void {
if (b.isTextNode()) {
this.renderer.setText(
this.render, this.mainMergeMapping.renderTextIndices[b.elementIndex + this.textOffset],
currentValue);
this.renderer.setText(this.render, b.elementIndex + this.textOffset, currentValue);
} else {
var elementRef = this.elementRefs[this.elementOffset + b.elementIndex];
if (b.isElementProperty()) {
@ -226,13 +190,14 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
}
getNestedView(boundElementIndex: number): AppView {
var viewIndex = this.mainMergeMapping.nestedViewIndicesByElementIndex[boundElementIndex];
return isPresent(viewIndex) ? this.views[viewIndex] : null;
var eli = this.elementInjectors[boundElementIndex];
return isPresent(eli) ? eli.getNestedView() : null;
}
getHostElement(): ElementRef {
var boundElementIndex = this.mainMergeMapping.hostElementIndicesByViewIndex[this.viewOffset];
return isPresent(boundElementIndex) ? this.elementRefs[boundElementIndex] : null;
getContainerElement(): ElementRef {
return isPresent(this.containerElementInjector) ?
this.containerElementInjector.getElementRef() :
null;
}
getDebugContext(elementIndex: number, directiveIndex: DirectiveIndex): DebugContext {
@ -241,11 +206,11 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
var hasRefForIndex = offsettedIndex < this.elementRefs.length;
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 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 injector = isPresent(ei) ? ei.getInjector() : null;
@ -269,10 +234,9 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
}
// implementation of RenderEventDispatcher#dispatchRenderEvent
dispatchRenderEvent(renderElementIndex: number, eventName: string,
dispatchRenderEvent(boundElementIndex: number, eventName: string,
locals: Map<string, any>): boolean {
var elementRef =
this.elementRefs[this.mainMergeMapping.renderInverseElementIndices[renderElementIndex]];
var elementRef = this.elementRefs[boundElementIndex];
var view = internalView(elementRef.parentView);
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 {
elementBinders: ElementBinder[] = [];
protoLocals = new Map<string, any>();
mergeMapping: AppProtoViewMergeMapping;
ref: ProtoViewRef;
protoLocals: Map<string, any>;
constructor(public type: renderApi.ViewType, public isEmbeddedFragment: boolean,
public render: renderApi.RenderProtoViewRef,
public protoChangeDetector: ProtoChangeDetector,
public variableBindings: Map<string, string>,
public variableLocations: Map<string, number>, public textBindingCount: number,
public pipes: ProtoPipes) {
elementBinders: ElementBinder[] = null;
mergeInfo: AppProtoViewMergeInfo = null;
variableLocations: Map<string, number> = null;
textBindingCount = null;
render: renderApi.RenderProtoViewRef = null;
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);
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); });
}
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,
protoElementInjector: ProtoElementInjector,
componentDirective: DirectiveBinding = null): ElementBinder {
var elBinder = new ElementBinder(this.elementBinders.length, parent, distanceToParent,
protoElementInjector, componentDirective);
this.elementBinders.push(elBinder);
return elBinder;
}
}
isInitialized(): boolean { return isPresent(this.elementBinders); }
}

View File

@ -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 {BaseException} from 'angular2/src/core/facade/exceptions';
import * as viewModule from './view';
@ -17,6 +24,7 @@ import {AppViewManagerUtils} from './view_manager_utils';
import {AppViewPool} from './view_pool';
import {AppViewListener} from './view_listener';
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
import {ProtoViewFactory} from './proto_view_factory';
/**
* Service exposing low level API for creating, moving and destroying Views.
@ -26,11 +34,15 @@ import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
*/
@Injectable()
export class AppViewManager {
private _protoViewFactory: ProtoViewFactory;
/**
* @private
*/
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.
@ -138,13 +150,13 @@ export class AppViewManager {
injector: Injector): HostViewRef {
var s = this._createRootHostViewScope();
var hostProtoView: viewModule.AppProtoView = internalProtoView(hostProtoViewRef);
this._protoViewFactory.initializeProtoViewIfNeeded(hostProtoView);
var hostElementSelector = overrideSelector;
if (isBlank(hostElementSelector)) {
hostElementSelector = hostProtoView.elementBinders[0].componentDirective.metadata.selector;
}
var renderViewWithFragments = this._renderer.createRootHostView(
hostProtoView.mergeMapping.renderProtoViewRef,
hostProtoView.mergeMapping.renderFragmentCount, hostElementSelector);
hostProtoView.render, hostProtoView.mergeInfo.embeddedViewCount + 1, hostElementSelector);
var hostView = this._createMainView(hostProtoView, renderViewWithFragments);
this._renderer.hydrateView(hostView.render);
@ -196,6 +208,7 @@ export class AppViewManager {
if (protoView.type !== ViewType.EMBEDDED) {
throw new BaseException('This method can only be called with embedded ProtoViews!');
}
this._protoViewFactory.initializeProtoViewIfNeeded(protoView);
return wtfLeave(s, this._createViewInContainer(viewContainerLocation, index, protoView,
templateRef.elementRef, null));
}
@ -226,6 +239,7 @@ export class AppViewManager {
if (protoView.type !== ViewType.HOST) {
throw new BaseException('This method can only be called with host ProtoViews!');
}
this._protoViewFactory.initializeProtoViewIfNeeded(protoView);
return wtfLeave(
s, this._createViewInContainer(viewContainerLocation, index, protoView,
viewContainerLocation, imperativelyCreatedInjector));
@ -345,8 +359,8 @@ export class AppViewManager {
var view = this._viewPool.getView(protoView);
if (isBlank(view)) {
view = this._createMainView(
protoView, this._renderer.createView(protoView.mergeMapping.renderProtoViewRef,
protoView.mergeMapping.renderFragmentCount));
protoView,
this._renderer.createView(protoView.render, protoView.mergeInfo.embeddedViewCount + 1));
}
return view;
}
@ -385,8 +399,7 @@ export class AppViewManager {
}
var viewContainers = view.viewContainers;
var startViewOffset = view.viewOffset;
var endViewOffset =
view.viewOffset + view.mainMergeMapping.nestedViewCountByViewIndex[view.viewOffset];
var endViewOffset = view.viewOffset + view.proto.mergeInfo.viewCount - 1;
var elementOffset = view.elementOffset;
for (var viewIdx = startViewOffset; viewIdx <= endViewOffset; viewIdx++) {
var currView = view.views[viewIdx];

View File

@ -3,7 +3,6 @@ import {ListWrapper, MapWrapper, Map, StringMapWrapper} from 'angular2/src/core/
import * as eli from './element_injector';
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
import * as viewModule from './view';
import {internalView} from './view_ref';
import * as avmModule from './view_manager';
import {ElementRef} from './element_ref';
import {TemplateRef} from './template_ref';
@ -27,42 +26,52 @@ export class AppViewManagerUtils {
var renderFragments = renderViewWithFragments.fragmentRefs;
var renderView = renderViewWithFragments.viewRef;
var elementCount = mergedParentViewProto.mergeMapping.renderElementIndices.length;
var viewCount = mergedParentViewProto.mergeMapping.nestedViewCountByViewIndex[0] + 1;
var elementCount = mergedParentViewProto.mergeInfo.elementCount;
var viewCount = mergedParentViewProto.mergeInfo.viewCount;
var elementRefs: ElementRef[] = ListWrapper.createFixedSize(elementCount);
var viewContainers = 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 elementOffset = 0;
var textOffset = 0;
var fragmentIdx = 0;
var containerElementIndicesByViewIndex: number[] = ListWrapper.createFixedSize(viewCount);
for (var viewOffset = 0; viewOffset < viewCount; viewOffset++) {
var hostElementIndex =
mergedParentViewProto.mergeMapping.hostElementIndicesByViewIndex[viewOffset];
var parentView = isPresent(hostElementIndex) ?
internalView(elementRefs[hostElementIndex].parentView) :
null;
var containerElementIndex = containerElementIndicesByViewIndex[viewOffset];
var containerElementInjector =
isPresent(containerElementIndex) ? elementInjectors[containerElementIndex] : null;
var parentView =
isPresent(containerElementInjector) ? preBuiltObjects[containerElementIndex].view : null;
var protoView =
isPresent(hostElementIndex) ?
parentView.proto.elementBinders[hostElementIndex - parentView.elementOffset]
isPresent(containerElementIndex) ?
parentView.proto.elementBinders[containerElementIndex - parentView.elementOffset]
.nestedProtoView :
mergedParentViewProto;
var renderFragment = null;
if (viewOffset === 0 || protoView.type === ViewType.EMBEDDED) {
renderFragment = renderFragments[fragmentIdx++];
}
var currentView = new viewModule.AppView(
renderer, protoView, mergedParentViewProto.mergeMapping, viewOffset, elementOffset,
textOffset, protoView.protoLocals, renderView, renderFragment);
var currentView = new viewModule.AppView(renderer, protoView, viewOffset, elementOffset,
textOffset, protoView.protoLocals, renderView,
renderFragment, containerElementInjector);
views[viewOffset] = currentView;
if (isPresent(containerElementIndex)) {
preBuiltObjects[containerElementIndex].nestedView = currentView;
}
var rootElementInjectors = [];
var nestedViewOffset = viewOffset + 1;
for (var binderIdx = 0; binderIdx < protoView.elementBinders.length; binderIdx++) {
var binder = protoView.elementBinders[binderIdx];
var boundElementIndex = elementOffset + binderIdx;
var elementInjector = null;
if (isPresent(binder.nestedProtoView) && binder.nestedProtoView.isMergable) {
containerElementIndicesByViewIndex[nestedViewOffset] = boundElementIndex;
nestedViewOffset += binder.nestedProtoView.mergeInfo.viewCount;
}
// elementInjectors and rootElementInjectors
var protoElementInjector = binder.protoElementInjector;
if (isPresent(protoElementInjector)) {
@ -78,19 +87,20 @@ export class AppViewManagerUtils {
elementInjectors[boundElementIndex] = elementInjector;
// elementRefs
var el = new ElementRef(
currentView.ref, boundElementIndex,
mergedParentViewProto.mergeMapping.renderElementIndices[boundElementIndex], renderer);
var el = new ElementRef(currentView.ref, boundElementIndex, renderer);
elementRefs[el.boundElementIndex] = el;
// preBuiltObjects
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] =
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);
if (isPresent(parentView) && protoView.type === ViewType.COMPONENT) {
parentView.changeDetector.addShadowDomChild(currentView.changeDetector);
@ -166,20 +176,19 @@ export class AppViewManagerUtils {
_hydrateView(initView: viewModule.AppView, imperativelyCreatedInjector: Injector,
hostElementInjector: eli.ElementInjector, context: Object, parentLocals: Locals) {
var viewIdx = initView.viewOffset;
var endViewOffset = viewIdx + initView.mainMergeMapping.nestedViewCountByViewIndex[viewIdx];
var endViewOffset = viewIdx + initView.proto.mergeInfo.viewCount - 1;
while (viewIdx <= endViewOffset) {
var currView = initView.views[viewIdx];
var currProtoView = currView.proto;
if (currView !== initView && currView.proto.type === ViewType.EMBEDDED) {
// Don't hydrate components of embedded fragment views.
viewIdx += initView.mainMergeMapping.nestedViewCountByViewIndex[viewIdx] + 1;
viewIdx += currView.proto.mergeInfo.viewCount;
} else {
if (currView !== initView) {
// hydrate a nested component view
imperativelyCreatedInjector = null;
parentLocals = null;
var hostElementIndex = initView.mainMergeMapping.hostElementIndicesByViewIndex[viewIdx];
hostElementInjector = initView.elementInjectors[hostElementIndex];
hostElementInjector = currView.containerElementInjector;
context = hostElementInjector.getComponent();
}
currView.context = context;
@ -233,8 +242,7 @@ export class AppViewManagerUtils {
}
dehydrateView(initView: viewModule.AppView) {
var endViewOffset = initView.viewOffset +
initView.mainMergeMapping.nestedViewCountByViewIndex[initView.viewOffset];
var endViewOffset = initView.viewOffset + initView.proto.mergeInfo.viewCount - 1;
for (var viewIdx = initView.viewOffset; viewIdx <= endViewOffset; viewIdx++) {
var currView = initView.views[viewIdx];
if (currView.hydrated()) {

View File

@ -1,3 +0,0 @@
library angular2.di_transformer_dart;
export '../../transform/di_transformer.dart';

View File

@ -8,19 +8,16 @@ import {CONST_EXPR, Type} from './facade/lang';
import {NgClass} from './directives/ng_class';
import {NgFor} from './directives/ng_for';
import {NgIf} from './directives/ng_if';
import {NgNonBindable} from './directives/ng_non_bindable';
import {NgStyle} from './directives/ng_style';
import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
export {NgClass} from './directives/ng_class';
export {NgFor} from './directives/ng_for';
export {NgIf} from './directives/ng_if';
export {NgNonBindable} from './directives/ng_non_bindable';
export {NgStyle} from './directives/ng_style';
export {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
export * from './directives/observable_list_diff';
/**
* A collection of Angular core directives that are likely to be used in each and every Angular
* application.
@ -65,5 +62,5 @@ export * from './directives/observable_list_diff';
* }
* ```
*/
export const CORE_DIRECTIVES: Type[] = CONST_EXPR(
[NgClass, NgFor, NgIf, NgNonBindable, NgStyle, NgSwitch, NgSwitchWhen, NgSwitchDefault]);
export const CORE_DIRECTIVES: Type[] =
CONST_EXPR([NgClass, NgFor, NgIf, NgStyle, NgSwitch, NgSwitchWhen, NgSwitchDefault]);

View File

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

View File

@ -6,6 +6,12 @@ import 'package:html/dom.dart';
import 'dom_adapter.dart';
import 'emulated_css.dart';
const _attrToPropMap = const {
'innerHtml': 'innerHTML',
'readonly': 'readOnly',
'tabindex': 'tabIndex',
};
abstract class AbstractHtml5LibAdapter implements DomAdapter {
hasProperty(element, String name) {
// This is needed for serverside compile to generate the right getters/setters.
@ -23,12 +29,9 @@ abstract class AbstractHtml5LibAdapter implements DomAdapter {
throw 'not implemented';
@override
final attrToPropMap = const {
'innerHtml': 'innerHTML',
'readonly': 'readOnly',
'tabindex': 'tabIndex',
};
get attrToPropMap => _attrToPropMap;
@override
set attrToPropMap(value) {
throw 'readonly';
}

View File

@ -117,6 +117,7 @@ export abstract class DomAdapter {
abstract cssToRules(css: string): any[];
abstract supportsDOMEvents(): boolean;
abstract supportsNativeShadowDOM(): boolean;
abstract supportsUnprefixedCssAnimation(): boolean;
abstract getGlobalEventTarget(target: string): any;
abstract getHistory(): History;
abstract getLocation(): Location;

View File

@ -70,6 +70,10 @@ export abstract class GenericBrowserDomAdapter extends DomAdapter {
supportsNativeShadowDOM(): boolean {
return isFunction((<any>this.defaultDoc().body).createShadowRoot);
}
supportsUnprefixedCssAnimation(): boolean {
return isPresent(this.defaultDoc().body.style) &&
isPresent(this.defaultDoc().body.style.animationName);
}
getAnimationPrefix(): string {
return isPresent(this._animationPrefix) ? this._animationPrefix : "";
}

View File

@ -1,452 +1,25 @@
library angular2.dom.htmlAdapter;
import 'abstract_html_adapter.dart';
import 'dom_adapter.dart';
import 'package:html/parser.dart' as parser;
import 'package:html/dom.dart';
import 'dart:io';
class Html5LibDomAdapter implements DomAdapter {
class Html5LibDomAdapter extends AbstractHtml5LibAdapter {
static void makeCurrent() {
setRootDomAdapter(new Html5LibDomAdapter());
}
hasProperty(element, String name) {
// This is needed for serverside compile to generate the right getters/setters.
// TODO: change this once we have property schema support.
// Attention: Keep this in sync with browser_adapter.dart!
return true;
logError(errorMessage) {
stderr.writeln('${errorMessage}');
}
void setProperty(Element element, String name, Object value) =>
throw 'not implemented';
getProperty(Element element, String name) => throw 'not implemented';
invoke(Element element, String methodName, List args) =>
throw 'not implemented';
logError(error) {
stderr.writeln('${error}');
log(message) {
stdout.writeln('${message}');
}
log(error) {
stdout.writeln('${error}');
}
logGroup(error) {
stdout.writeln('${error}');
logGroup(message) {
stdout.writeln('${message}');
}
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';
}
}

View File

@ -1,11 +1,9 @@
var parse5 = require('parse5');
var parse5 = require('parse5/index');
var parser = new parse5.Parser(parse5.TreeAdapters.htmlparser2);
var serializer = new parse5.Serializer(parse5.TreeAdapters.htmlparser2);
var treeAdapter = parser.treeAdapter;
var cssParse = require('css').parse;
var url = require('url');
var cssParse = require('css/lib/parse/index');
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
import {DomAdapter, setRootDomAdapter} from './dom_adapter';
@ -487,7 +485,7 @@ export class Parse5DomAdapter extends DomAdapter {
if (href == null) {
el.href = baseUrl;
} else {
el.href = url.resolve(baseUrl, href);
el.href = baseUrl + '/../' + href;
}
}
_buildRules(parsedRules, css?) {
@ -546,6 +544,12 @@ export class Parse5DomAdapter extends DomAdapter {
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'; }
resetBaseElement(): void { throw 'not implemented'; }
getHistory(): History { throw 'not implemented'; }

View File

@ -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() {}
}

View File

@ -17,8 +17,7 @@ class Directive extends DirectiveMetadata {
const Directive({String selector, List<String> inputs,
List<String> outputs, Map<String, String> host,
List bindings, String exportAs, String moduleId,
Map<String, dynamic> queries,
bool compileChildren: true})
Map<String, dynamic> queries})
: super(
selector: selector,
inputs: inputs,
@ -27,8 +26,7 @@ class Directive extends DirectiveMetadata {
bindings: bindings,
exportAs: exportAs,
moduleId: moduleId,
queries: queries,
compileChildren: compileChildren);
queries: queries);
}
/**
@ -39,7 +37,7 @@ class Component extends ComponentMetadata {
List<String> outputs, Map<String, String> host,
List bindings, String exportAs, String moduleId,
Map<String, dynamic> queries,
bool compileChildren, List viewBindings, ChangeDetectionStrategy changeDetection})
List viewBindings, ChangeDetectionStrategy changeDetection})
: super(
selector: selector,
inputs: inputs,
@ -48,7 +46,6 @@ class Component extends ComponentMetadata {
bindings: bindings,
exportAs: exportAs,
moduleId: moduleId,
compileChildren: compileChildren,
viewBindings: viewBindings,
queries: queries,
changeDetection: changeDetection);

View File

@ -153,7 +153,6 @@ export interface DirectiveFactory {
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
queries?: StringMap<string, any>
}): DirectiveDecorator;
new (obj: {
@ -164,7 +163,6 @@ export interface DirectiveFactory {
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
queries?: StringMap<string, any>
}): DirectiveMetadata;
}
@ -221,7 +219,6 @@ export interface ComponentFactory {
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
queries?: StringMap<string, any>,
viewBindings?: any[],
changeDetection?: ChangeDetectionStrategy,
@ -234,7 +231,6 @@ export interface ComponentFactory {
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
queries?: StringMap<string, any>,
viewBindings?: any[],
changeDetection?: ChangeDetectionStrategy,

View File

@ -622,12 +622,6 @@ export class DirectiveMetadata extends InjectableMetadata {
*/
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
* children.
@ -744,10 +738,7 @@ export class DirectiveMetadata extends InjectableMetadata {
*/
queries: StringMap<string, any>;
constructor({
selector, inputs, outputs, host, bindings, exportAs, moduleId, queries,
compileChildren = true,
}: {
constructor({selector, inputs, outputs, host, bindings, exportAs, moduleId, queries}: {
selector?: string,
inputs?: string[],
outputs?: string[],
@ -755,8 +746,7 @@ export class DirectiveMetadata extends InjectableMetadata {
bindings?: any[],
exportAs?: string,
moduleId?: string,
queries?: StringMap<string, any>,
compileChildren?: boolean,
queries?: StringMap<string, any>
} = {}) {
super();
this.selector = selector;
@ -766,7 +756,6 @@ export class DirectiveMetadata extends InjectableMetadata {
this.exportAs = exportAs;
this.moduleId = moduleId;
this.queries = queries;
this.compileChildren = compileChildren;
this.bindings = bindings;
}
}
@ -868,20 +857,18 @@ export class ComponentMetadata extends DirectiveMetadata {
viewBindings: any[];
constructor({selector, inputs, outputs, host, exportAs, moduleId, bindings, viewBindings,
changeDetection = ChangeDetectionStrategy.Default, queries, compileChildren = true}:
{
selector?: string,
inputs?: string[],
outputs?: string[],
host?: StringMap<string, string>,
bindings?: any[],
exportAs?: string,
moduleId?: string,
compileChildren?: boolean,
viewBindings?: any[],
queries?: StringMap<string, any>,
changeDetection?: ChangeDetectionStrategy,
} = {}) {
changeDetection = ChangeDetectionStrategy.Default, queries}: {
selector?: string,
inputs?: string[],
outputs?: string[],
host?: StringMap<string, string>,
bindings?: any[],
exportAs?: string,
moduleId?: string,
viewBindings?: any[],
queries?: StringMap<string, any>,
changeDetection?: ChangeDetectionStrategy,
} = {}) {
super({
selector: selector,
inputs: inputs,
@ -890,8 +877,7 @@ export class ComponentMetadata extends DirectiveMetadata {
exportAs: exportAs,
moduleId: moduleId,
bindings: bindings,
queries: queries,
compileChildren: compileChildren
queries: queries
});
this.changeDetection = changeDetection;

View File

@ -13,12 +13,19 @@ import {PipeBinding} from './pipe_binding';
import * as cd from 'angular2/src/core/change_detection/pipes';
export class ProtoPipes {
/**
* Map of {@link PipeMetadata} names to {@link PipeMetadata} implementations.
*/
config: StringMap<string, PipeBinding> = {};
static fromBindings(bindings: PipeBinding[]): ProtoPipes {
var config = {};
bindings.forEach(b => config[b.name] = b);
return new ProtoPipes(config);
}
constructor(bindings: PipeBinding[]) { bindings.forEach(b => this.config[b.name] = b); }
constructor(
/**
* Map of {@link PipeMetadata} names to {@link PipeMetadata} implementations.
*/
public config: StringMap<string, PipeBinding>) {
this.config = config;
}
get(name: string): PipeBinding {
var binding = this.config[name];

View File

@ -11,8 +11,5 @@ export interface PlatformReflectionCapabilities {
getter(name: string): GetterFn;
setter(name: string): SetterFn;
method(name: string): MethodFn;
// TODO(tbosch): remove this method after the new compiler is done
// (and ComponentUrlMapper as well).
importUri(type: Type): string;
moduleId(type: Type): string;
}

View File

@ -322,11 +322,4 @@ class ReflectionCapabilities implements PlatformReflectionCapabilities {
String importUri(Type type) {
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('.'));
}
}

View File

@ -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.
importUri(type: Type): string { return './'; }
moduleId(type: Type): string { return './'; }
}

View File

@ -152,8 +152,6 @@ export class Reflector {
_containsReflectionInfo(typeOrFunc) { return this._injectableInfo.has(typeOrFunc); }
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 {

View File

@ -11,5 +11,13 @@ export {
ViewDefinition,
DOCUMENT,
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';

View File

@ -453,6 +453,16 @@ export interface RenderElementRef {
}
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.
* Note that the fragmentCount needs to be passed in so that we can create a result

View File

@ -1,22 +1,19 @@
import {Inject, Injectable, OpaqueToken} from 'angular2/src/core/di';
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 {DOM} from 'angular2/src/core/dom/dom_adapter';
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 {
NG_BINDING_CLASS_SELECTOR,
NG_BINDING_CLASS,
cloneAndQueryProtoView,
camelCaseToDashCase
} from './util';
import {WtfScopeFn, wtfLeave, wtfCreateScope} from '../../profile/profile';
import {
@ -25,65 +22,80 @@ import {
RenderViewRef,
RenderElementRef,
RenderFragmentRef,
RenderViewWithFragments
RenderViewWithFragments,
RenderTemplateCmd,
RenderEventDispatcher
} from '../api';
import {TemplateCloner} from './template_cloner';
import {DOCUMENT} from './dom_tokens';
const REFLECT_PREFIX: string = 'ng-reflect-';
import {createRenderView, NodeFactory} from '../view_factory';
import {DefaultRenderView, DefaultRenderFragmentRef, DefaultProtoViewRef} from '../view';
import {camelCaseToDashCase} from './util';
@Injectable()
export class DomRenderer extends Renderer {
_document;
export class DomRenderer implements Renderer, NodeFactory<Node> {
private _componentCmds: Map<number, RenderTemplateCmd[]> = new Map<number, RenderTemplateCmd[]>();
private _document;
/**
* @private
*/
constructor(private _eventManager: EventManager,
private _domSharedStylesHost: DomSharedStylesHost, private _animate: AnimationBuilder,
private _templateCloner: TemplateCloner, @Inject(DOCUMENT) document) {
super();
@Inject(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()');
createRootHostView(hostProtoViewRef: RenderProtoViewRef, fragmentCount: number,
hostElementSelector: string): RenderViewWithFragments {
var s = this._createRootHostViewScope();
var hostProtoView = resolveInternalDomProtoView(hostProtoViewRef);
var element = DOM.querySelector(this._document, hostElementSelector);
if (isBlank(element)) {
wtfLeave(s);
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()');
createView(protoViewRef: RenderProtoViewRef, fragmentCount: number): RenderViewWithFragments {
var s = this._createViewScope();
var protoView = resolveInternalDomProtoView(protoViewRef);
return wtfLeave(s, this._createView(protoView, null));
return wtfLeave(s, this._createView(protoViewRef, 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) {
var view = resolveInternalDomView(viewRef);
var elementBinders = view.proto.elementBinders;
for (var i = 0; i < elementBinders.length; i++) {
var binder = elementBinders[i];
if (binder.hasNativeShadowRoot) {
this._domSharedStylesHost.removeHost(DOM.getShadowRoot(view.boundElements[i]));
}
var view = <DefaultRenderView<Node>>viewRef;
var sdRoots = view.nativeShadowRoots;
for (var i = 0; i < sdRoots.length; i++) {
this._domSharedStylesHost.removeHost(sdRoots[i]);
}
}
getNativeElementSync(location: RenderElementRef): any {
if (isBlank(location.renderBoundElementIndex)) {
return null;
}
return resolveInternalDomView(location.renderView)
.boundElements[location.renderBoundElementIndex];
}
@ -144,9 +156,6 @@ export class DomRenderer extends Renderer {
}
attachFragmentAfterElement(elementRef: RenderElementRef, fragmentRef: RenderFragmentRef) {
if (isBlank(elementRef.renderBoundElementIndex)) {
return;
}
var parentView = resolveInternalDomView(elementRef.renderView);
var element = parentView.boundElements[elementRef.renderBoundElementIndex];
var nodes = resolveInternalDomFragment(fragmentRef);
@ -164,153 +173,100 @@ export class DomRenderer extends Renderer {
wtfLeave(s);
}
hydrateView(viewRef: RenderViewRef) {
var view = resolveInternalDomView(viewRef);
if (view.hydrated) throw new BaseException('The view is already hydrated.');
view.hydrated = true;
hydrateView(viewRef: RenderViewRef) { resolveInternalDomView(viewRef).hydrate(); }
// add global events
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) { resolveInternalDomView(viewRef).dehydrate(); }
createTemplateAnchor(attrNameAndValues: string[]): Node {
return this.createElement('script', attrNameAndValues);
}
createElement(name: string, attrNameAndValues: string[]): Node {
var el = DOM.createElement(name);
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]);
}
}
dehydrateView(viewRef: RenderViewRef) {
var view = resolveInternalDomView(viewRef);
// remove global events
for (var i = 0; i < view.eventHandlerRemovers.length; i++) {
view.eventHandlerRemovers[i]();
}
view.eventHandlerRemovers = null;
view.hydrated = false;
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 {
if (isBlank(location.renderBoundElementIndex)) {
return;
}
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):
void {
if (isBlank(location.renderBoundElementIndex)) {
return;
}
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 {
if (isBlank(location.renderBoundElementIndex)) {
return;
}
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 {
if (isBlank(location.renderBoundElementIndex)) {
return;
}
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 {
if (isBlank(location.renderBoundElementIndex)) {
return;
}
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 {
if (isBlank(textNodeIndex)) {
return;
}
var view = resolveInternalDomView(viewRef);
DOM.setText(view.boundTextNodes[textNodeIndex], text);
}
_setEventDispatcherScope = wtfCreateScope('DomRenderer#setEventDispatcher()');
setEventDispatcher(viewRef: RenderViewRef, dispatcher: any /*api.EventDispatcher*/): void {
var s = this._setEventDispatcherScope();
var view = resolveInternalDomView(viewRef);
view.eventDispatcher = dispatcher;
wtfLeave(s);
setEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher): void {
resolveInternalDomView(viewRef).setEventDispatcher(dispatcher);
}
}
_createView(protoView: DomProtoView, inplaceElement: HTMLElement): RenderViewWithFragments {
var clonedProtoView = cloneAndQueryProtoView(this._templateCloner, protoView, true);
function resolveInternalDomView(viewRef: RenderViewRef): DefaultRenderView<Node> {
return <DefaultRenderView<Node>>viewRef;
}
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(
new DomViewRef(view), clonedProtoView.fragments.map(nodes => new DomFragmentRef(nodes)));
}
_createEventListener(view, element, elementIndex, eventName, eventLocals) {
this._eventManager.addEventListener(
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 resolveInternalDomFragment(fragmentRef: RenderFragmentRef): Node[] {
return (<DefaultRenderFragmentRef<Node>>fragmentRef).nodes;
}
function moveNodesAfterSibling(sibling, nodes) {
@ -318,7 +274,7 @@ function moveNodesAfterSibling(sibling, nodes) {
for (var i = 0; i < nodes.length; 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;
}
}
function decoratePreventDefault(eventHandler: Function): Function {
return (event) => {
var allowDefaultBehavior = eventHandler(event);
if (!allowDefaultBehavior) {
// TODO(tbosch): move preventDefault into event plugins...
DOM.preventDefault(event);
}
};
}

View File

@ -1,9 +1,11 @@
import {Injectable} from 'angular2/src/core/di';
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
import {StringMapWrapper} from 'angular2/src/core/facade/collection';
import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {ElementSchemaRegistry} from './element_schema_registry';
@Injectable()
export class DomElementSchemaRegistry extends ElementSchemaRegistry {
private _protoElements = new Map<string, Element>();

View File

@ -6,13 +6,13 @@ import 'package:angular2/src/core/di.dart' show Injectable;
class UrlResolver {
/// This will be the location where 'package:' Urls will resolve. Default is
/// '/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
/// prefixed location.
const UrlResolver.withUrlPrefix(this.packagePrefix);
const UrlResolver.withUrlPrefix(this._packagePrefix);
/**
* Resolves the `url` given the `baseUrl`:
@ -30,7 +30,7 @@ class UrlResolver {
Uri uri = Uri.parse(url);
if (uri.scheme == 'package') {
return '$packagePrefix/${uri.path}';
return '$_packagePrefix/${uri.path}';
}
if (uri.isAbsolute) return uri.toString();

View File

@ -32,7 +32,6 @@ export class MockDirectiveResolver extends DirectiveResolver {
bindings: bindings,
exportAs: dm.exportAs,
moduleId: dm.moduleId,
compileChildren: dm.compileChildren,
queries: dm.queries,
changeDetection: dm.changeDetection,
viewBindings: viewBindings
@ -47,7 +46,6 @@ export class MockDirectiveResolver extends DirectiveResolver {
bindings: bindings,
exportAs: dm.exportAs,
moduleId: dm.moduleId,
compileChildren: dm.compileChildren,
queries: dm.queries
});
}

View File

@ -3,7 +3,7 @@ import {DEFAULT_PIPES} from 'angular2/src/core/pipes';
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
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 {
Parser,
@ -13,7 +13,8 @@ import {
IterableDiffers,
defaultIterableDiffers,
KeyValueDiffers,
defaultKeyValueDiffers
defaultKeyValueDiffers,
ChangeDetectorGenConfig
} from 'angular2/src/core/change_detection/change_detection';
import {ExceptionHandler} from 'angular2/src/core/facade/exceptions';
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 {AppViewManager} from 'angular2/src/core/compiler/view_manager';
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 {
DomRenderer,
@ -109,6 +109,7 @@ function _getAppBindings() {
return [
compilerBindings(),
bind(ChangeDetectorGenConfig).toValue(new ChangeDetectorGenConfig(true, true, false, true)),
bind(DOCUMENT).toValue(appDoc),
DomRenderer,
bind(Renderer).toAlias(DomRenderer),
@ -120,15 +121,13 @@ function _getAppBindings() {
bind(ElementSchemaRegistry).toValue(new DomElementSchemaRegistry()),
DomSharedStylesHost,
bind(SharedStylesHost).toAlias(DomSharedStylesHost),
ProtoViewFactory,
AppViewPool,
AppViewManager,
AppViewManagerUtils,
Serializer,
ELEMENT_PROBE_BINDINGS,
bind(APP_VIEW_POOL_CAPACITY).toValue(500),
Compiler,
CompilerCache,
ProtoViewFactory,
bind(DirectiveResolver).toClass(MockDirectiveResolver),
bind(ViewResolver).toClass(MockViewResolver),
DEFAULT_PIPES,

View File

@ -1,9 +1,75 @@
import {CONST_EXPR} from "angular2/src/core/facade/lang";
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 class WebWorkerElementRef implements RenderElementRef {
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);
}
}

View File

@ -3,7 +3,6 @@
* You should not use these channels in your application code.
*/
export const SETUP_CHANNEL = "ng-WebWorkerSetup";
export const RENDER_COMPILER_CHANNEL = "ng-RenderCompiler";
export const RENDERER_CHANNEL = "ng-Renderer";
export const XHR_CHANNEL = "ng-XHR";
export const EVENT_CHANNEL = "ng-events";

View File

@ -12,41 +12,33 @@ export class RenderProtoViewRefStore {
constructor(@Inject(ON_WEB_WORKER) onWebworker) { this._onWebworker = onWebworker; }
storeRenderProtoViewRef(ref: RenderProtoViewRef): number {
if (this._lookupByProtoView.has(ref)) {
return this._lookupByProtoView.get(ref);
} else {
this._lookupByIndex.set(this._nextIndex, ref);
this._lookupByProtoView.set(ref, this._nextIndex);
return this._nextIndex++;
}
allocate(): RenderProtoViewRef {
var index = this._nextIndex++;
var result = new WebWorkerRenderProtoViewRef(index);
this.store(result, index);
return result;
}
retreiveRenderProtoViewRef(index: number): RenderProtoViewRef {
return this._lookupByIndex.get(index);
store(ref: RenderProtoViewRef, index: number): void {
this._lookupByProtoView.set(ref, index);
this._lookupByIndex.set(index, ref);
}
deserialize(index: number): RenderProtoViewRef {
if (index == null) {
return null;
}
if (this._onWebworker) {
return new WebWorkerRenderProtoViewRef(index);
} else {
return this.retreiveRenderProtoViewRef(index);
}
return this._lookupByIndex.get(index);
}
serialize(ref: RenderProtoViewRef): number {
if (ref == null) {
return null;
}
if (this._onWebworker) {
return (<WebWorkerRenderProtoViewRef>ref).refNumber;
} else {
return this.storeRenderProtoViewRef(ref);
return this._lookupByProtoView.get(ref);
}
}
}

View File

@ -29,9 +29,26 @@ import {
RenderElementRef,
ViewType,
ViewEncapsulation,
PropertyBindingType
PropertyBindingType,
RenderTemplateCmd,
RenderCommandVisitor,
RenderTextCmd,
RenderNgContentCmd,
RenderBeginElementCmd,
RenderBeginComponentCmd,
RenderEmbeddedTemplateCmd
} 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 {Parser} from "angular2/src/core/change_detection/parser/parser";
import {Injectable} from "angular2/src/core/di";
@ -109,6 +126,8 @@ export class Serializer {
return this._serializeElementPropertyBinding(obj);
} else if (type == EventBinding) {
return this._serializeEventBinding(obj);
} else if (type == WebWorkerTemplateCmd) {
return serializeTemplateCmd(obj);
} else {
throw new BaseException("No serializer for " + type.toString());
}
@ -153,6 +172,8 @@ export class Serializer {
return this._deserializeEventBinding(map);
} else if (type == ElementPropertyBinding) {
return this._deserializeElementPropertyBinding(map);
} else if (type == WebWorkerTemplateCmd) {
return deserializeTemplateCmd(map);
} else {
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))),
];

View File

@ -18,7 +18,7 @@ import {
DomEventsPlugin,
EVENT_MANAGER_PLUGINS
} 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 {KeyEventsPlugin} from 'angular2/src/core/render/dom/events/key_events';
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 {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
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 {ViewLoader} from 'angular2/src/core/render/dom/compiler/view_loader';
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 {WebWorkerApplication} from 'angular2/src/web_workers/ui/impl';
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 {MessageBasedXHRImpl} from 'angular2/src/web_workers/ui/xhr_impl';
import {WebWorkerSetup} from 'angular2/src/web_workers/ui/setup';
@ -111,14 +109,12 @@ function _injectorBindings(): any[] {
bind(ElementSchemaRegistry).toValue(new DomElementSchemaRegistry()),
RenderViewWithFragmentsStore,
RenderProtoViewRefStore,
ProtoViewFactory,
AppViewPool,
bind(APP_VIEW_POOL_CAPACITY).toValue(10000),
AppViewManager,
AppViewManagerUtils,
AppViewListener,
Compiler,
CompilerCache,
ProtoViewFactory,
ViewResolver,
DEFAULT_PIPES,
bind(ChangeDetection).toValue(bestChangeDetection),
@ -138,7 +134,6 @@ function _injectorBindings(): any[] {
bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl),
WebWorkerApplication,
WebWorkerSetup,
MessageBasedRenderCompiler,
MessageBasedXHRImpl,
MessageBasedRenderer,
ServiceMessageBrokerFactory,

View File

@ -77,7 +77,6 @@ Map<String, dynamic> serializeKeyboardEvent(dynamic e) {
serialized['eventPhase'] = e.eventPhase;
serialized['keyCode'] = e.keyCode;
serialized['keyLocation'] = e.keyLocation;
serialized['layer'] = serializePoint(e.layer);
serialized['location'] = e.location;
serialized['repeat'] = e.repeat;
serialized['shiftKey'] = e.shiftKey;

View File

@ -12,7 +12,6 @@ import {Injectable} from 'angular2/src/core/di';
import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter';
import {wtfInit} from 'angular2/src/core/profile/wtf_init';
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 {MessageBasedXHRImpl} from 'angular2/src/web_workers/ui/xhr_impl';
import {
@ -35,7 +34,6 @@ export function bootstrapUICommon(bus: MessageBus): WebWorkerApplication {
bus.attachToZone(zone);
return zone.run(() => {
var injector = createInjector(zone, bus);
injector.get(MessageBasedRenderCompiler).start();
injector.get(MessageBasedRenderer).start();
injector.get(MessageBasedXHRImpl).start();
injector.get(WebWorkerSetup).start();

View File

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

View File

@ -5,13 +5,15 @@ import {
RenderViewRef,
RenderFragmentRef,
RenderProtoViewRef,
Renderer
Renderer,
RenderTemplateCmd
} 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 {Type} from 'angular2/src/core/facade/lang';
import {bind} from './bind';
import {EventDispatcher} from 'angular2/src/web_workers/ui/event_dispatcher';
import {RenderProtoViewRefStore} from 'angular2/src/web_workers/shared/render_proto_view_ref_store';
import {
RenderViewWithFragmentsStore
} 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 {
constructor(private _brokerFactory: ServiceMessageBrokerFactory, private _bus: MessageBus,
private _serializer: Serializer,
private _renderProtoViewRefStore: RenderProtoViewRefStore,
private _renderViewWithFragmentsStore: RenderViewWithFragmentsStore,
private _renderer: Renderer) {}
start(): void {
var broker = this._brokerFactory.createMessageBroker(RENDERER_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",
[RenderProtoViewRef, PRIMITIVE, PRIMITIVE, PRIMITIVE],
bind(this._createRootHostView, this));
@ -64,6 +72,11 @@ export class MessageBasedRenderer {
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,
startIndex: number) {
var renderViewWithFragments = this._renderer.createRootHostView(ref, fragmentCount, selector);

View File

@ -9,6 +9,7 @@ import "package:angular2/src/core/compiler/dynamic_component_loader.dart" show C
import "dart:isolate";
import "dart:async";
import 'dart:core';
import 'package:angular2/src/core/dom/webworker_adapter.dart';
/**
* Bootstrapping a Webworker Application
@ -24,6 +25,7 @@ import 'dart:core';
Future<ComponentRef> bootstrapWebWorker(
SendPort replyTo, Type appComponentType,
[List<dynamic> componentInjectableBindings = null]) {
WebWorkerDomAdapter.makeCurrent();
ReceivePort rPort = new ReceivePort();
var sink = new WebWorkerMessageBusSink(replyTo, rPort);
var source = new IsolateMessageBusSource(rPort);

View File

@ -10,6 +10,7 @@ import {Promise} from 'angular2/src/core/facade/async';
import {bootstrapWebWorkerCommon} from "angular2/src/web_workers/worker/application_common";
import {ComponentRef} from "angular2/src/core/compiler/dynamic_component_loader";
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)
interface PostMessageInterface {
@ -29,6 +30,7 @@ var _postMessage: PostMessageInterface = <any>postMessage;
export function bootstrapWebWorker(
appComponentType: Type, componentInjectableBindings: Array<Type | Binding | any[]> = null):
Promise<ComponentRef> {
Parse5DomAdapter.makeCurrent();
var sink = new PostMessageBusSink({
postMessage: (message: any, transferrables?:[ArrayBuffer]) => {
console.log("Sending", message);

View File

@ -14,7 +14,7 @@ import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/core/facad
import {XHR} from 'angular2/src/core/render/xhr';
import {WebWorkerXHRImpl} from 'angular2/src/web_workers/worker/xhr_impl';
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 {ClientMessageBrokerFactory} from 'angular2/src/web_workers/shared/client_message_broker';
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 {ComponentRef} from 'angular2/src/core/compiler/dynamic_component_loader';
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
@ -86,13 +87,12 @@ class PrintLogger {
function webWorkerBindings(appComponentType, bus: MessageBus, initData: StringMap<string, any>):
Array<Type | Binding | any[]> {
return [
compilerBindings(),
Serializer,
bind(MessageBus).toValue(bus),
ClientMessageBrokerFactory,
WebWorkerRenderer,
bind(Renderer).toAlias(WebWorkerRenderer),
WebWorkerCompiler,
bind(RenderCompiler).toAlias(WebWorkerCompiler),
bind(ON_WEB_WORKER).toValue(true),
RenderViewWithFragmentsStore,
RenderProtoViewRefStore,

View File

@ -10,9 +10,9 @@ import {
RenderEventDispatcher,
RenderProtoViewMergeMapping,
RenderViewWithFragments,
RenderFragmentRef
RenderFragmentRef,
RenderTemplateCmd
} from 'angular2/src/core/render/api';
import {Promise, PromiseWrapper} from "angular2/src/core/facade/async";
import {
ClientMessageBroker,
ClientMessageBrokerFactory,
@ -21,69 +21,45 @@ import {
} from "angular2/src/web_workers/shared/client_message_broker";
import {isPresent, print} from "angular2/src/core/facade/lang";
import {Injectable} from "angular2/src/core/di";
import {RenderProtoViewRefStore} from 'angular2/src/web_workers/shared/render_proto_view_ref_store';
import {
RenderViewWithFragmentsStore,
WebWorkerRenderViewRef
} from 'angular2/src/web_workers/shared/render_view_with_fragments_store';
import {WebWorkerElementRef} from 'angular2/src/web_workers/shared/api';
import {
RENDER_COMPILER_CHANNEL,
RENDERER_CHANNEL
} from 'angular2/src/web_workers/shared/messaging_api';
import {WebWorkerElementRef, WebWorkerTemplateCmd} from 'angular2/src/web_workers/shared/api';
import {RENDERER_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
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()
export class WebWorkerRenderer implements Renderer {
private _messageBroker;
constructor(messageBrokerFactory: ClientMessageBrokerFactory,
private _renderProtoViewRefStore: RenderProtoViewRefStore,
private _renderViewStore: RenderViewWithFragmentsStore,
private _eventDispatcher: WebWorkerEventDispatcher) {
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.
* Note that the fragmentCount needs to be passed in so that we can create a result