feat(compiler): implement style encapsulation for new view engine (#14518)

Included refactoring:
- splits the `RendererV2` into a `RendererFactoryV2` and a `RendererV2`
- makes the `DebugRendererV2` a private class in `@angular/core`
- remove `setBindingDebugInfo` from `RendererV2`, but rename `RendererV2.setText` to 
  `RendererV2.setValue` and allow it on comments and text nodes.

Part of #14013
This commit is contained in:
Tobias Bosch 2017-02-16 13:55:55 -08:00 committed by Igor Minar
parent ba17dcbf2b
commit 0fa3895d5b
38 changed files with 828 additions and 595 deletions

View File

@ -101,11 +101,12 @@ export class AotCompiler {
}); });
// compile components // compile components
const compViewVars = this._compileComponent(
compMeta, ngModule, ngModule.transitiveModule.directives,
stylesCompileResults.componentStylesheet, fileSuffix, statements);
exportedVars.push( exportedVars.push(
this._compileComponentFactory(compMeta, ngModule, fileSuffix, statements), this._compileComponentFactory(compMeta, ngModule, fileSuffix, statements),
this._compileComponent( compViewVars.viewClassVar, compViewVars.compRenderTypeVar);
compMeta, ngModule, ngModule.transitiveModule.directives,
stylesCompileResults.componentStylesheet, fileSuffix, statements));
}); });
if (statements.length > 0) { if (statements.length > 0) {
const srcModule = this._codegenSourceModule( const srcModule = this._codegenSourceModule(
@ -175,8 +176,10 @@ export class AotCompiler {
const hostType = this._metadataResolver.getHostComponentType(compMeta.type.reference); const hostType = this._metadataResolver.getHostComponentType(compMeta.type.reference);
const hostMeta = createHostComponentMeta( const hostMeta = createHostComponentMeta(
hostType, compMeta, this._metadataResolver.getHostComponentViewClass(hostType)); hostType, compMeta, this._metadataResolver.getHostComponentViewClass(hostType));
const hostViewFactoryVar = this._compileComponent( const hostViewFactoryVar =
hostMeta, ngModule, [compMeta.type], null, fileSuffix, targetStatements); this._compileComponent(
hostMeta, ngModule, [compMeta.type], null, fileSuffix, targetStatements)
.viewClassVar;
const compFactoryVar = componentFactoryName(compMeta.type.reference); const compFactoryVar = componentFactoryName(compMeta.type.reference);
targetStatements.push( targetStatements.push(
o.variable(compFactoryVar) o.variable(compFactoryVar)
@ -198,7 +201,8 @@ export class AotCompiler {
private _compileComponent( private _compileComponent(
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata, compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata,
directiveIdentifiers: CompileIdentifierMetadata[], componentStyles: CompiledStylesheet, directiveIdentifiers: CompileIdentifierMetadata[], componentStyles: CompiledStylesheet,
fileSuffix: string, targetStatements: o.Statement[]): string { fileSuffix: string,
targetStatements: o.Statement[]): {viewClassVar: string, compRenderTypeVar: string} {
const parsedAnimations = this._animationParser.parseComponent(compMeta); const parsedAnimations = this._animationParser.parseComponent(compMeta);
const directives = const directives =
directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference)); directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
@ -219,7 +223,10 @@ export class AotCompiler {
} }
compiledAnimations.forEach(entry => targetStatements.push(...entry.statements)); compiledAnimations.forEach(entry => targetStatements.push(...entry.statements));
targetStatements.push(...viewResult.statements); targetStatements.push(...viewResult.statements);
return viewResult.viewClassVar; return {
viewClassVar: viewResult.viewClassVar,
compRenderTypeVar: viewResult.componentRenderTypeVar
};
} }
private _codgenStyles( private _codgenStyles(

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ChangeDetectionStrategy, ComponentFactory, SchemaMetadata, Type, ViewEncapsulation} from '@angular/core'; import {ChangeDetectionStrategy, ComponentFactory, ComponentRenderTypeV2, SchemaMetadata, Type, ViewEncapsulation} from '@angular/core';
import {StaticSymbol} from './aot/static_symbol'; import {StaticSymbol} from './aot/static_symbol';
import {ListWrapper} from './facade/collection'; import {ListWrapper} from './facade/collection';
@ -15,6 +15,7 @@ import {LifecycleHooks, reflector} from './private_import_core';
import {CssSelector} from './selector'; import {CssSelector} from './selector';
import {splitAtColon} from './util'; import {splitAtColon} from './util';
// group 0: "[prop] or (event) or @trigger" // group 0: "[prop] or (event) or @trigger"
// group 1: "prop" from "[prop]" // group 1: "prop" from "[prop]"
// group 2: "event" from "(event)" // group 2: "event" from "(event)"
@ -116,6 +117,10 @@ export function viewClassName(compType: any, embeddedTemplateIndex: number): str
return `View_${identifierName({reference: compType})}_${embeddedTemplateIndex}`; return `View_${identifierName({reference: compType})}_${embeddedTemplateIndex}`;
} }
export function componentRenderTypeName(compType: any): string {
return `RenderType_${identifierName({reference: compType})}`;
}
export function hostViewClassName(compType: any): string { export function hostViewClassName(compType: any): string {
return `HostView_${identifierName({reference: compType})}`; return `HostView_${identifierName({reference: compType})}`;
} }
@ -310,6 +315,7 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
template: CompileTemplateSummary; template: CompileTemplateSummary;
wrapperType: StaticSymbol|ProxyClass; wrapperType: StaticSymbol|ProxyClass;
componentViewType: StaticSymbol|ProxyClass; componentViewType: StaticSymbol|ProxyClass;
componentRenderType: StaticSymbol|ComponentRenderTypeV2;
componentFactory: StaticSymbol|ComponentFactory<any>; componentFactory: StaticSymbol|ComponentFactory<any>;
} }
@ -320,7 +326,7 @@ export class CompileDirectiveMetadata {
static create( static create(
{isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host, {isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
providers, viewProviders, queries, viewQueries, entryComponents, template, wrapperType, providers, viewProviders, queries, viewQueries, entryComponents, template, wrapperType,
componentViewType, componentFactory}: { componentViewType, componentRenderType, componentFactory}: {
isHost?: boolean, isHost?: boolean,
type?: CompileTypeMetadata, type?: CompileTypeMetadata,
isComponent?: boolean, isComponent?: boolean,
@ -338,6 +344,7 @@ export class CompileDirectiveMetadata {
template?: CompileTemplateMetadata, template?: CompileTemplateMetadata,
wrapperType?: StaticSymbol|ProxyClass, wrapperType?: StaticSymbol|ProxyClass,
componentViewType?: StaticSymbol|ProxyClass, componentViewType?: StaticSymbol|ProxyClass,
componentRenderType?: StaticSymbol|ComponentRenderTypeV2,
componentFactory?: StaticSymbol|ComponentFactory<any>, componentFactory?: StaticSymbol|ComponentFactory<any>,
} = {}): CompileDirectiveMetadata { } = {}): CompileDirectiveMetadata {
const hostListeners: {[key: string]: string} = {}; const hostListeners: {[key: string]: string} = {};
@ -392,6 +399,7 @@ export class CompileDirectiveMetadata {
template, template,
wrapperType, wrapperType,
componentViewType, componentViewType,
componentRenderType,
componentFactory, componentFactory,
}); });
} }
@ -416,12 +424,14 @@ export class CompileDirectiveMetadata {
wrapperType: StaticSymbol|ProxyClass; wrapperType: StaticSymbol|ProxyClass;
componentViewType: StaticSymbol|ProxyClass; componentViewType: StaticSymbol|ProxyClass;
componentRenderType: StaticSymbol|ComponentRenderTypeV2;
componentFactory: StaticSymbol|ComponentFactory<any>; componentFactory: StaticSymbol|ComponentFactory<any>;
constructor({isHost, type, isComponent, selector, exportAs, constructor({isHost, type, isComponent, selector, exportAs,
changeDetection, inputs, outputs, hostListeners, hostProperties, changeDetection, inputs, outputs, hostListeners, hostProperties,
hostAttributes, providers, viewProviders, queries, viewQueries, hostAttributes, providers, viewProviders, queries, viewQueries,
entryComponents, template, wrapperType, componentViewType, componentFactory}: { entryComponents, template, wrapperType, componentViewType, componentRenderType,
componentFactory}: {
isHost?: boolean, isHost?: boolean,
type?: CompileTypeMetadata, type?: CompileTypeMetadata,
isComponent?: boolean, isComponent?: boolean,
@ -441,6 +451,7 @@ export class CompileDirectiveMetadata {
template?: CompileTemplateMetadata, template?: CompileTemplateMetadata,
wrapperType?: StaticSymbol|ProxyClass, wrapperType?: StaticSymbol|ProxyClass,
componentViewType?: StaticSymbol|ProxyClass, componentViewType?: StaticSymbol|ProxyClass,
componentRenderType?: StaticSymbol|ComponentRenderTypeV2,
componentFactory?: StaticSymbol|ComponentFactory<any>, componentFactory?: StaticSymbol|ComponentFactory<any>,
} = {}) { } = {}) {
this.isHost = !!isHost; this.isHost = !!isHost;
@ -463,6 +474,7 @@ export class CompileDirectiveMetadata {
this.wrapperType = wrapperType; this.wrapperType = wrapperType;
this.componentViewType = componentViewType; this.componentViewType = componentViewType;
this.componentRenderType = componentRenderType;
this.componentFactory = componentFactory; this.componentFactory = componentFactory;
} }
@ -487,6 +499,7 @@ export class CompileDirectiveMetadata {
template: this.template && this.template.toSummary(), template: this.template && this.template.toSummary(),
wrapperType: this.wrapperType, wrapperType: this.wrapperType,
componentViewType: this.componentViewType, componentViewType: this.componentViewType,
componentRenderType: this.componentRenderType,
componentFactory: this.componentFactory componentFactory: this.componentFactory
}; };
} }
@ -521,7 +534,9 @@ export function createHostComponentMeta(
viewProviders: [], viewProviders: [],
queries: [], queries: [],
viewQueries: [], viewQueries: [],
componentViewType: hostViewType componentViewType: hostViewType,
componentRenderType:
{id: '__Host__', encapsulation: ViewEncapsulation.None, styles: [], data: {}}
}); });
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation, ɵAnimationGroupPlayer, ɵAnimationKeyframe, ɵAnimationSequencePlayer, ɵAnimationStyles, ɵAnimationTransition, ɵAppView, ɵChangeDetectorStatus, ɵCodegenComponentFactoryResolver, ɵComponentRef_, ɵDebugAppView, ɵDebugContext, ɵNgModuleInjector, ɵNoOpAnimationPlayer, ɵStaticNodeDebugInfo, ɵTemplateRef_, ɵValueUnwrapper, ɵViewContainer, ɵViewType, ɵbalanceAnimationKeyframes, ɵclearStyles, ɵcollectAndResolveStyles, ɵdevModeEqual, ɵprepareFinalAnimationStyles, ɵreflector, ɵregisterModuleFactory, ɵrenderStyles, ɵviewEngine, ɵview_utils} from '@angular/core'; import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ComponentRenderTypeV2, ElementRef, Injector, LOCALE_ID, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation, ɵAnimationGroupPlayer, ɵAnimationKeyframe, ɵAnimationSequencePlayer, ɵAnimationStyles, ɵAnimationTransition, ɵAppView, ɵChangeDetectorStatus, ɵCodegenComponentFactoryResolver, ɵComponentRef_, ɵDebugAppView, ɵDebugContext, ɵNgModuleInjector, ɵNoOpAnimationPlayer, ɵStaticNodeDebugInfo, ɵTemplateRef_, ɵValueUnwrapper, ɵViewContainer, ɵViewType, ɵbalanceAnimationKeyframes, ɵclearStyles, ɵcollectAndResolveStyles, ɵdevModeEqual, ɵprepareFinalAnimationStyles, ɵreflector, ɵregisterModuleFactory, ɵrenderStyles, ɵviewEngine, ɵview_utils} from '@angular/core';
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata'; import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
@ -380,6 +380,12 @@ export class Identifiers {
member: 'unwrapValue', member: 'unwrapValue',
runtime: ɵviewEngine.unwrapValue runtime: ɵviewEngine.unwrapValue
}; };
static createComponentRenderTypeV2: IdentifierSpec = {
name: 'ɵviewEngine',
moduleUrl: CORE,
member: 'createComponentRenderTypeV2',
runtime: ɵviewEngine.createComponentRenderTypeV2
};
} }
export function assetUrl(pkg: string, path: string = null, type: string = 'src'): string { export function assetUrl(pkg: string, path: string = null, type: string = 'src'): string {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Compiler, ComponentFactory, Inject, Injector, ModuleWithComponentFactories, NgModuleFactory, Type} from '@angular/core'; import {Compiler, ComponentFactory, ComponentRenderTypeV2, Inject, Injector, ModuleWithComponentFactories, NgModuleFactory, Type} from '@angular/core';
import {AnimationCompiler} from '../animation/animation_compiler'; import {AnimationCompiler} from '../animation/animation_compiler';
import {AnimationParser} from '../animation/animation_parser'; import {AnimationParser} from '../animation/animation_parser';
@ -133,11 +133,11 @@ export class JitCompiler implements Compiler {
const compileResult = this._ngModuleCompiler.compile(moduleMeta, extraProviders); const compileResult = this._ngModuleCompiler.compile(moduleMeta, extraProviders);
if (!this._compilerConfig.useJit) { if (!this._compilerConfig.useJit) {
ngModuleFactory = ngModuleFactory =
interpretStatements(compileResult.statements, compileResult.ngModuleFactoryVar); interpretStatements(compileResult.statements, [compileResult.ngModuleFactoryVar])[0];
} else { } else {
ngModuleFactory = jitStatements( ngModuleFactory = jitStatements(
`/${identifierName(moduleMeta.type)}/module.ngfactory.js`, compileResult.statements, `/${identifierName(moduleMeta.type)}/module.ngfactory.js`, compileResult.statements,
compileResult.ngModuleFactoryVar); [compileResult.ngModuleFactoryVar])[0];
} }
this._compiledNgModuleCache.set(moduleMeta.type.reference, ngModuleFactory); this._compiledNgModuleCache.set(moduleMeta.type.reference, ngModuleFactory);
} }
@ -252,11 +252,12 @@ export class JitCompiler implements Compiler {
const statements = compileResult.statements; const statements = compileResult.statements;
let directiveWrapperClass: any; let directiveWrapperClass: any;
if (!this._compilerConfig.useJit) { if (!this._compilerConfig.useJit) {
directiveWrapperClass = interpretStatements(statements, compileResult.dirWrapperClassVar); directiveWrapperClass =
interpretStatements(statements, [compileResult.dirWrapperClassVar])[0];
} else { } else {
directiveWrapperClass = jitStatements( directiveWrapperClass = jitStatements(
`/${identifierName(moduleMeta.type)}/${identifierName(dirMeta.type)}/wrapper.ngfactory.js`, `/${identifierName(moduleMeta.type)}/${identifierName(dirMeta.type)}/wrapper.ngfactory.js`,
statements, compileResult.dirWrapperClassVar); statements, [compileResult.dirWrapperClassVar])[0];
} }
(<ProxyClass>dirMeta.wrapperType).setDelegate(directiveWrapperClass); (<ProxyClass>dirMeta.wrapperType).setDelegate(directiveWrapperClass);
this._compiledDirectiveWrapperCache.set(dirMeta.type.reference, directiveWrapperClass); this._compiledDirectiveWrapperCache.set(dirMeta.type.reference, directiveWrapperClass);
@ -290,14 +291,18 @@ export class JitCompiler implements Compiler {
.concat(...compiledAnimations.map(ca => ca.statements)) .concat(...compiledAnimations.map(ca => ca.statements))
.concat(compileResult.statements); .concat(compileResult.statements);
let viewClass: any; let viewClass: any;
let componentRenderType: any;
if (!this._compilerConfig.useJit) { if (!this._compilerConfig.useJit) {
viewClass = interpretStatements(statements, compileResult.viewClassVar); [viewClass, componentRenderType] = interpretStatements(
statements, [compileResult.viewClassVar, compileResult.componentRenderTypeVar]);
} else { } else {
viewClass = jitStatements( const sourceUrl =
`/${identifierName(template.ngModule.type)}/${identifierName(template.compType)}/${template.isHost?'host':'component'}.ngfactory.js`, `/${identifierName(template.ngModule.type)}/${identifierName(template.compType)}/${template.isHost?'host':'component'}.ngfactory.js`;
statements, compileResult.viewClassVar); [viewClass, componentRenderType] = jitStatements(
sourceUrl, statements,
[compileResult.viewClassVar, compileResult.componentRenderTypeVar]);
} }
template.compiled(viewClass); template.compiled(viewClass, componentRenderType);
} }
private _resolveStylesCompileResult( private _resolveStylesCompileResult(
@ -315,10 +320,10 @@ export class JitCompiler implements Compiler {
externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>): string[] { externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>): string[] {
this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl); this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl);
if (!this._compilerConfig.useJit) { if (!this._compilerConfig.useJit) {
return interpretStatements(result.statements, result.stylesVar); return interpretStatements(result.statements, [result.stylesVar])[0];
} else { } else {
return jitStatements( return jitStatements(
`/${result.meta.moduleUrl}.ngstyle.js`, result.statements, result.stylesVar); `/${result.meta.moduleUrl}.ngstyle.js`, result.statements, [result.stylesVar])[0];
} }
} }
} }
@ -332,9 +337,12 @@ class CompiledTemplate {
public compMeta: CompileDirectiveMetadata, public ngModule: CompileNgModuleMetadata, public compMeta: CompileDirectiveMetadata, public ngModule: CompileNgModuleMetadata,
public directives: CompileIdentifierMetadata[]) {} public directives: CompileIdentifierMetadata[]) {}
compiled(viewClass: Function) { compiled(viewClass: Function, componentRenderType: any) {
this._viewClass = viewClass; this._viewClass = viewClass;
(<ProxyClass>this.compMeta.componentViewType).setDelegate(viewClass); (<ProxyClass>this.compMeta.componentViewType).setDelegate(viewClass);
for (let prop in componentRenderType) {
(<any>this.compMeta.componentRenderType)[prop] = componentRenderType[prop];
}
this.isCompiled = true; this.isCompiled = true;
} }
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, Attribute, ChangeDetectionStrategy, Component, ComponentFactory, Directive, Host, Inject, Injectable, InjectionToken, ModuleWithProviders, Optional, Provider, Query, SchemaMetadata, Self, SkipSelf, Type, resolveForwardRef} from '@angular/core'; import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, Attribute, ChangeDetectionStrategy, Component, ComponentFactory, ComponentRenderTypeV2, Directive, Host, Inject, Injectable, InjectionToken, ModuleWithProviders, Optional, Provider, Query, SchemaMetadata, Self, SkipSelf, Type, resolveForwardRef} from '@angular/core';
import {StaticSymbol, StaticSymbolCache} from './aot/static_symbol'; import {StaticSymbol, StaticSymbolCache} from './aot/static_symbol';
import {ngfactoryFilePath} from './aot/util'; import {ngfactoryFilePath} from './aot/util';
@ -131,6 +131,17 @@ export class CompileMetadataResolver {
} }
} }
private getComponentRenderType(dirType: any): StaticSymbol|ComponentRenderTypeV2 {
if (dirType instanceof StaticSymbol) {
return this._staticSymbolCache.get(
ngfactoryFilePath(dirType.filePath), cpl.componentRenderTypeName(dirType));
} else {
// returning an object as proxy,
// that we fill later during runtime compilation.
return <any>{};
}
}
private getComponentFactory(selector: string, dirType: any): StaticSymbol|ComponentFactory<any> { private getComponentFactory(selector: string, dirType: any): StaticSymbol|ComponentFactory<any> {
if (dirType instanceof StaticSymbol) { if (dirType instanceof StaticSymbol) {
return this._staticSymbolCache.get( return this._staticSymbolCache.get(
@ -235,6 +246,7 @@ export class CompileMetadataResolver {
entryComponents: metadata.entryComponents, entryComponents: metadata.entryComponents,
wrapperType: metadata.wrapperType, wrapperType: metadata.wrapperType,
componentViewType: metadata.componentViewType, componentViewType: metadata.componentViewType,
componentRenderType: metadata.componentRenderType,
componentFactory: metadata.componentFactory, componentFactory: metadata.componentFactory,
template: templateMetadata template: templateMetadata
}); });
@ -372,6 +384,8 @@ export class CompileMetadataResolver {
wrapperType: this.getDirectiveWrapperClass(directiveType), wrapperType: this.getDirectiveWrapperClass(directiveType),
componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) : componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
undefined, undefined,
componentRenderType:
nonNormalizedTemplateMetadata ? this.getComponentRenderType(directiveType) : undefined,
componentFactory: nonNormalizedTemplateMetadata ? componentFactory: nonNormalizedTemplateMetadata ?
this.getComponentFactory(selector, directiveType) : this.getComponentFactory(selector, directiveType) :
undefined undefined

View File

@ -12,8 +12,9 @@ import {isPresent} from '../facade/lang';
import * as o from './output_ast'; import * as o from './output_ast';
import {debugOutputAstAsTypeScript} from './ts_emitter'; import {debugOutputAstAsTypeScript} from './ts_emitter';
export function interpretStatements(statements: o.Statement[], resultVar: string): any { export function interpretStatements(statements: o.Statement[], resultVars: string[]): any[] {
const stmtsWithReturn = statements.concat([new o.ReturnStatement(o.variable(resultVar))]); const stmtsWithReturn = statements.concat(
[new o.ReturnStatement(o.literalArr(resultVars.map(resultVar => o.variable(resultVar))))]);
const ctx = new _ExecutionContext(null, null, null, new Map<string, any>()); const ctx = new _ExecutionContext(null, null, null, new Map<string, any>());
const visitor = new StatementInterpreter(); const visitor = new StatementInterpreter();
const result = visitor.visitAllStatements(stmtsWithReturn, ctx); const result = visitor.visitAllStatements(stmtsWithReturn, ctx);

View File

@ -13,9 +13,9 @@ import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
import * as o from './output_ast'; import * as o from './output_ast';
function evalExpression( function evalExpression(
sourceUrl: string, expr: string, ctx: EmitterVisitorContext, vars: {[key: string]: any}): any { sourceUrl: string, ctx: EmitterVisitorContext, vars: {[key: string]: any}): any {
const fnBody = const fnBody =
`${ctx.toSource()}\nreturn ${expr}\n//# sourceURL=${sourceUrl}\n${ctx.toSourceMapGenerator().toJsComment()}`; `${ctx.toSource()}\n//# sourceURL=${sourceUrl}\n${ctx.toSourceMapGenerator().toJsComment()}`;
const fnArgNames: string[] = []; const fnArgNames: string[] = [];
const fnArgValues: any[] = []; const fnArgValues: any[] = [];
for (const argName in vars) { for (const argName in vars) {
@ -26,11 +26,13 @@ function evalExpression(
} }
export function jitStatements( export function jitStatements(
sourceUrl: string, statements: o.Statement[], resultVar: string): any { sourceUrl: string, statements: o.Statement[], resultVars: string[]): any[] {
const converter = new JitEmitterVisitor(); const converter = new JitEmitterVisitor();
const ctx = EmitterVisitorContext.createRoot([resultVar]); const ctx = EmitterVisitorContext.createRoot(resultVars);
converter.visitAllStatements(statements, ctx); const returnStmt =
return evalExpression(sourceUrl, resultVar, ctx, converter.getArgs()); new o.ReturnStatement(o.literalArr(resultVars.map(resultVar => o.variable(resultVar))));
converter.visitAllStatements(statements.concat([returnStmt]), ctx);
return evalExpression(sourceUrl, ctx, converter.getArgs());
} }
class JitEmitterVisitor extends AbstractJsEmitterVisitor { class JitEmitterVisitor extends AbstractJsEmitterVisitor {

View File

@ -7,7 +7,7 @@
*/ */
import {AnimationEntryCompileResult} from '../animation/animation_compiler'; import {AnimationEntryCompileResult} from '../animation/animation_compiler';
import {CompileDirectiveMetadata, CompilePipeSummary, tokenName, viewClassName} from '../compile_metadata'; import {CompileDirectiveMetadata, CompilePipeSummary, componentRenderTypeName, tokenName, viewClassName} from '../compile_metadata';
import {EventHandlerVars, LegacyNameResolver} from '../compiler_util/expression_converter'; import {EventHandlerVars, LegacyNameResolver} from '../compiler_util/expression_converter';
import {CompilerConfig} from '../config'; import {CompilerConfig} from '../config';
import {isPresent} from '../facade/lang'; import {isPresent} from '../facade/lang';
@ -70,6 +70,7 @@ export class CompileView implements LegacyNameResolver {
public pipes: CompilePipe[] = []; public pipes: CompilePipe[] = [];
public locals = new Map<string, o.Expression>(); public locals = new Map<string, o.Expression>();
public className: string; public className: string;
public renderComponentTypeName: string;
public classType: o.Type; public classType: o.Type;
public classExpr: o.ReadVarExpr; public classExpr: o.ReadVarExpr;
@ -102,6 +103,7 @@ export class CompileView implements LegacyNameResolver {
this.viewType = getViewType(component, viewIndex); this.viewType = getViewType(component, viewIndex);
this.className = viewClassName(component.type.reference, viewIndex); this.className = viewClassName(component.type.reference, viewIndex);
this.renderComponentTypeName = componentRenderTypeName(component.type.reference);
this.classType = o.expressionType(o.variable(this.className)); this.classType = o.expressionType(o.variable(this.className));
this.classExpr = o.variable(this.className); this.classExpr = o.variable(this.className);
if (this.viewType === ViewType.COMPONENT || this.viewType === ViewType.HOST) { if (this.viewType === ViewType.COMPONENT || this.viewType === ViewType.HOST) {

View File

@ -386,7 +386,7 @@ function createViewTopLevelStmts(view: CompileView, targetStatements: o.Statemen
const renderCompTypeVar: o.ReadVarExpr = const renderCompTypeVar: o.ReadVarExpr =
o.variable(`renderType_${identifierName(view.component.type)}`); // fix highlighting: ` o.variable(view.renderComponentTypeName); // fix highlighting: `
if (view.viewIndex === 0) { if (view.viewIndex === 0) {
let templateUrlInfo: string; let templateUrlInfo: string;
if (view.component.template.templateUrl == identifierModuleUrl(view.component.type)) { if (view.component.template.templateUrl == identifierModuleUrl(view.component.type)) {

View File

@ -25,6 +25,7 @@ export {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDep
export class ViewCompileResult { export class ViewCompileResult {
constructor( constructor(
public statements: o.Statement[], public viewClassVar: string, public statements: o.Statement[], public viewClassVar: string,
public componentRenderTypeVar: string,
public dependencies: public dependencies:
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {} Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {}
} }
@ -50,6 +51,7 @@ export class ViewCompiler {
bindView(view, template, this._schemaRegistry); bindView(view, template, this._schemaRegistry);
finishView(view, statements); finishView(view, statements);
return new ViewCompileResult(statements, view.classExpr.name, dependencies); return new ViewCompileResult(
statements, view.classExpr.name, view.renderComponentTypeName, dependencies);
} }
} }

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ChangeDetectionStrategy} from '@angular/core'; import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
import {AnimationEntryCompileResult} from '../animation/animation_compiler'; import {AnimationEntryCompileResult} from '../animation/animation_compiler';
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CompileProviderMetadata, CompileTokenMetadata, CompileTypeMetadata, identifierModuleUrl, identifierName, tokenReference} from '../compile_metadata'; import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CompileProviderMetadata, CompileTokenMetadata, CompileTypeMetadata, componentRenderTypeName, identifierModuleUrl, identifierName, tokenReference, viewClassName} from '../compile_metadata';
import {BuiltinConverter, BuiltinConverterFactory, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter'; import {BuiltinConverter, BuiltinConverterFactory, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {CompilerConfig} from '../config'; import {CompilerConfig} from '../config';
import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast'; import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast';
@ -20,7 +20,6 @@ import {convertValueToOutputAst} from '../output/value_util';
import {LifecycleHooks, viewEngine} from '../private_import_core'; import {LifecycleHooks, viewEngine} from '../private_import_core';
import {ElementSchemaRegistry} from '../schema/element_schema_registry'; import {ElementSchemaRegistry} from '../schema/element_schema_registry';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, ProviderAstType, QueryMatch, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast'; import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, ProviderAstType, QueryMatch, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {ViewEncapsulationEnum} from '../view_compiler/constants';
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency, ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler'; import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency, ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
const CLASS_ATTR = 'class'; const CLASS_ATTR = 'class';
@ -44,19 +43,33 @@ export class ViewCompilerNext extends ViewCompiler {
let embeddedViewCount = 0; let embeddedViewCount = 0;
const staticQueryIds = findStaticQueryIds(template); const staticQueryIds = findStaticQueryIds(template);
const statements: o.Statement[] = [];
const renderComponentVar = o.variable(componentRenderTypeName(component.type.reference));
statements.push(
renderComponentVar
.set(o.importExpr(createIdentifier(Identifiers.createComponentRenderTypeV2)).callFn([
new o.LiteralMapExpr([
new o.LiteralMapEntry('encapsulation', o.literal(component.template.encapsulation)),
new o.LiteralMapEntry('styles', styles),
// TODO: copy this from the @Component directive...
new o.LiteralMapEntry('data', o.literalMap([])),
])
]))
.toDeclStmt());
const viewBuilderFactory = (parent: ViewBuilder): ViewBuilder => { const viewBuilderFactory = (parent: ViewBuilder): ViewBuilder => {
const embeddedViewIndex = embeddedViewCount++; const embeddedViewIndex = embeddedViewCount++;
const viewName = `view_${compName}_${embeddedViewIndex}`; const viewName = viewClassName(component.type.reference, embeddedViewIndex);
return new ViewBuilder(parent, viewName, usedPipes, staticQueryIds, viewBuilderFactory); return new ViewBuilder(parent, viewName, usedPipes, staticQueryIds, viewBuilderFactory);
}; };
const visitor = viewBuilderFactory(null); const visitor = viewBuilderFactory(null);
visitor.visitAll([], template); visitor.visitAll([], template);
const statements: o.Statement[] = [];
statements.push(...visitor.build(component)); statements.push(...visitor.build(component));
return new ViewCompileResult(statements, visitor.viewName, []); return new ViewCompileResult(statements, visitor.viewName, renderComponentVar.name, []);
} }
} }
@ -458,9 +471,11 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
} }
}); });
let compRenderType = o.NULL_EXPR;
let compView = o.NULL_EXPR; let compView = o.NULL_EXPR;
if (directiveAst.directive.isComponent) { if (directiveAst.directive.isComponent) {
compView = o.importExpr({reference: directiveAst.directive.componentViewType}); compView = o.importExpr({reference: directiveAst.directive.componentViewType});
compRenderType = o.importExpr({reference: directiveAst.directive.componentRenderType});
} }
const inputDefs = directiveAst.inputs.map((inputAst, inputIndex) => { const inputDefs = directiveAst.inputs.map((inputAst, inputIndex) => {
@ -507,7 +522,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
o.literal(flags), queryMatchExprs.length ? o.literalArr(queryMatchExprs) : o.NULL_EXPR, o.literal(flags), queryMatchExprs.length ? o.literalArr(queryMatchExprs) : o.NULL_EXPR,
o.literal(childCount), providerExpr, depsExpr, o.literal(childCount), providerExpr, depsExpr,
inputDefs.length ? new o.LiteralMapExpr(inputDefs) : o.NULL_EXPR, inputDefs.length ? new o.LiteralMapExpr(inputDefs) : o.NULL_EXPR,
outputDefs.length ? new o.LiteralMapExpr(outputDefs) : o.NULL_EXPR, compView outputDefs.length ? new o.LiteralMapExpr(outputDefs) : o.NULL_EXPR, compView, compRenderType
]); ]);
this.nodeDefs[nodeIndex] = nodeDef; this.nodeDefs[nodeIndex] = nodeDef;

View File

@ -93,8 +93,6 @@ export const __core_private__: {
makeDecorator: typeof decorators.makeDecorator, makeDecorator: typeof decorators.makeDecorator,
DebugDomRootRenderer: typeof debug.DebugDomRootRenderer, DebugDomRootRenderer: typeof debug.DebugDomRootRenderer,
_DebugDomRootRenderer: debug.DebugDomRootRenderer, _DebugDomRootRenderer: debug.DebugDomRootRenderer,
DebugDomRendererV2: typeof debug.DebugDomRendererV2,
_DebugDomRendererV2: debug.DebugDomRendererV2,
Console: typeof console.Console, Console: typeof console.Console,
_Console: console.Console, _Console: console.Console,
reflector: typeof reflection.reflector, reflector: typeof reflection.reflector,
@ -158,7 +156,6 @@ export const __core_private__: {
ReflectionCapabilities: reflection_capabilities.ReflectionCapabilities, ReflectionCapabilities: reflection_capabilities.ReflectionCapabilities,
makeDecorator: decorators.makeDecorator, makeDecorator: decorators.makeDecorator,
DebugDomRootRenderer: debug.DebugDomRootRenderer, DebugDomRootRenderer: debug.DebugDomRootRenderer,
DebugDomRendererV2: debug.DebugDomRendererV2,
Console: console.Console, Console: console.Console,
reflector: reflection.reflector, reflector: reflection.reflector,
Reflector: reflection.Reflector, Reflector: reflection.Reflector,

View File

@ -10,7 +10,7 @@ import {AnimationKeyframe} from '../animation/animation_keyframe';
import {AnimationPlayer} from '../animation/animation_player'; import {AnimationPlayer} from '../animation/animation_player';
import {AnimationStyles} from '../animation/animation_styles'; import {AnimationStyles} from '../animation/animation_styles';
import {isPresent} from '../facade/lang'; import {isPresent} from '../facade/lang';
import {RenderComponentType, RenderDebugInfo, Renderer, RendererV2, RootRenderer} from '../render/api'; import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from './debug_node'; import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from './debug_node';
@ -156,151 +156,3 @@ export class DebugDomRenderer implements Renderer {
element, startingStyles, keyframes, duration, delay, easing, previousPlayers); element, startingStyles, keyframes, duration, delay, easing, previousPlayers);
} }
} }
export class DebugDomRendererV2 implements RendererV2 {
constructor(private _delegate: RendererV2) {}
createElement(name: string, namespace?: string, debugInfo?: any): any {
const el = this._delegate.createElement(name, namespace, debugInfo);
const debugEl = new DebugElement(el, null, debugInfo);
debugEl.name = name;
indexDebugNode(debugEl);
return el;
}
createComment(value: string, debugInfo?: any): any {
const comment = this._delegate.createComment(value, debugInfo);
const debugEl = new DebugNode(comment, null, debugInfo);
indexDebugNode(debugEl);
return comment;
}
createText(value: string, debugInfo?: any): any {
const text = this._delegate.createText(value, debugInfo);
const debugEl = new DebugNode(text, null, debugInfo);
indexDebugNode(debugEl);
return text;
}
appendChild(parent: any, newChild: any): void {
const debugEl = getDebugNode(parent);
const debugChildEl = getDebugNode(newChild);
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
debugEl.addChild(debugChildEl);
}
this._delegate.appendChild(parent, newChild);
}
insertBefore(parent: any, newChild: any, refChild: any): void {
const debugEl = getDebugNode(parent);
const debugChildEl = getDebugNode(newChild);
const debugRefEl = getDebugNode(refChild);
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
debugEl.insertBefore(debugRefEl, debugChildEl);
}
this._delegate.insertBefore(parent, newChild, refChild);
}
removeChild(parent: any, oldChild: any): void {
const debugEl = getDebugNode(parent);
const debugChildEl = getDebugNode(oldChild);
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
debugEl.removeChild(debugChildEl);
}
this._delegate.removeChild(parent, oldChild);
}
selectRootElement(selectorOrNode: string|any, debugInfo?: any): any {
const el = this._delegate.selectRootElement(selectorOrNode, debugInfo);
const debugEl = new DebugElement(el, null, debugInfo);
indexDebugNode(debugEl);
return el;
}
parentNode(node: any): any { return this._delegate.parentNode(node); }
nextSibling(node: any): any { return this._delegate.nextSibling(node); }
setAttribute(el: any, name: string, value: string, namespace?: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
const fullName = namespace ? namespace + ':' + name : name;
debugEl.attributes[fullName] = value;
}
this._delegate.setAttribute(el, name, value, namespace);
}
removeAttribute(el: any, name: string, namespace?: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
const fullName = namespace ? namespace + ':' + name : name;
debugEl.attributes[fullName] = null;
}
this._delegate.removeAttribute(el, name, namespace);
}
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {
this._delegate.setBindingDebugInfo(el, propertyName, propertyValue);
}
removeBindingDebugInfo(el: any, propertyName: string): void {
this._delegate.removeBindingDebugInfo(el, propertyName);
}
addClass(el: any, name: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
debugEl.classes[name] = true;
}
this._delegate.addClass(el, name);
}
removeClass(el: any, name: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
debugEl.classes[name] = false;
}
this._delegate.removeClass(el, name);
}
setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean):
void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
debugEl.styles[style] = value;
}
this._delegate.setStyle(el, style, value, hasVendorPrefix, hasImportant);
}
removeStyle(el: any, style: string, hasVendorPrefix: boolean): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
debugEl.styles[style] = null;
}
this._delegate.removeStyle(el, style, hasVendorPrefix);
}
setProperty(el: any, name: string, value: any): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
debugEl.properties[name] = value;
}
this._delegate.setProperty(el, name, value);
}
setText(node: any, value: string): void { this._delegate.setText(node, value); }
listen(
target: 'document'|'windows'|'body'|any, eventName: string,
callback: (event: any) => boolean): () => void {
if (typeof target !== 'string') {
const debugEl = getDebugNode(target);
if (debugEl) {
debugEl.listeners.push(new EventListener(eventName, callback));
}
}
return this._delegate.listen(target, eventName, callback);
}
}

View File

@ -7,4 +7,4 @@
*/ */
// Public API for render // Public API for render
export {RENDERER_V2_DIRECT, RenderComponentType, Renderer, RendererV2, RootRenderer} from './render/api'; export {ComponentRenderTypeV2, RenderComponentType, Renderer, RendererFactoryV2, RendererV2, RootRenderer} from './render/api';

View File

@ -12,13 +12,6 @@ import {AnimationStyles} from '../../src/animation/animation_styles';
import {InjectionToken, Injector} from '../di'; import {InjectionToken, Injector} from '../di';
import {ViewEncapsulation} from '../metadata/view'; import {ViewEncapsulation} from '../metadata/view';
/**
* Provide a concrete implementation of {@link RendererV2}
*
* @experimental
*/
export const RENDERER_V2_DIRECT = new InjectionToken<RendererV2>('Renderer V2');
/** /**
* @experimental * @experimental
*/ */
@ -98,56 +91,6 @@ export abstract class Renderer {
previousPlayers?: AnimationPlayer[]): AnimationPlayer; previousPlayers?: AnimationPlayer[]): AnimationPlayer;
} }
/**
* @experimental
*/
export abstract class RendererV2 {
abstract createElement(name: string, namespace?: string, debugInfo?: RenderDebugContext): any;
abstract createComment(value: string, debugInfo?: RenderDebugContext): any;
abstract createText(value: string, debugInfo?: RenderDebugContext): any;
abstract appendChild(parent: any, newChild: any): void;
abstract insertBefore(parent: any, newChild: any, refChild: any): void;
abstract removeChild(parent: any, oldChild: any): void;
abstract selectRootElement(selectorOrNode: string|any, debugInfo?: RenderDebugContext): any;
/**
* Attention: On WebWorkers, this will always return a value,
* as we are asking for a result synchronously. I.e.
* the caller can't rely on checking whether this is null or not.
*/
abstract parentNode(node: any): any;
/**
* Attention: On WebWorkers, this will always return a value,
* as we are asking for a result synchronously. I.e.
* the caller can't rely on checking whether this is null or not.
*/
abstract nextSibling(node: any): any;
abstract setAttribute(el: any, name: string, value: string, namespace?: string): void;
abstract removeAttribute(el: any, name: string, namespace?: string): void;
abstract setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void;
abstract removeBindingDebugInfo(el: any, propertyName: string): void;
abstract addClass(el: any, name: string): void;
abstract removeClass(el: any, name: string): void;
abstract setStyle(
el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean): void;
abstract removeStyle(el: any, style: string, hasVendorPrefix: boolean): void;
abstract setProperty(el: any, name: string, value: any): void;
abstract setText(node: any, value: string): void;
abstract listen(
target: 'window'|'document'|'body'|any, eventName: string,
callback: (event: any) => boolean): () => void;
}
export abstract class RenderDebugContext {
abstract get injector(): Injector;
abstract get component(): any;
abstract get providerTokens(): any[];
abstract get references(): {[key: string]: any};
abstract get context(): any;
abstract get source(): string;
abstract get componentRenderElement(): any;
abstract get renderNode(): any;
}
/** /**
* Injectable service that provides a low-level interface for modifying the UI. * Injectable service that provides a low-level interface for modifying the UI.
* *
@ -164,3 +107,64 @@ export abstract class RenderDebugContext {
export abstract class RootRenderer { export abstract class RootRenderer {
abstract renderComponent(componentType: RenderComponentType): Renderer; abstract renderComponent(componentType: RenderComponentType): Renderer;
} }
/**
* @experimental
*/
export interface ComponentRenderTypeV2 {
id: string;
encapsulation: ViewEncapsulation;
styles: (string|any[])[];
data: {[kind: string]: any[]};
}
/**
* @experimental
*/
export abstract class RendererFactoryV2 {
abstract createRenderer(hostElement: any, type: ComponentRenderTypeV2): RendererV2;
}
/**
* @experimental
*/
export abstract class RendererV2 {
abstract destroy(): void;
abstract createElement(name: string, namespace?: string): any;
abstract createComment(value: string): any;
abstract createText(value: string): any;
/**
* This property is allowed to be null / undefined,
* in which case the view engine won't call it.
* This is used as a performance optimization for production mode.
*/
destroyNode: (node: any) => void | null;
abstract appendChild(parent: any, newChild: any): void;
abstract insertBefore(parent: any, newChild: any, refChild: any): void;
abstract removeChild(parent: any, oldChild: any): void;
abstract selectRootElement(selectorOrNode: string|any): any;
/**
* Attention: On WebWorkers, this will always return a value,
* as we are asking for a result synchronously. I.e.
* the caller can't rely on checking whether this is null or not.
*/
abstract parentNode(node: any): any;
/**
* Attention: On WebWorkers, this will always return a value,
* as we are asking for a result synchronously. I.e.
* the caller can't rely on checking whether this is null or not.
*/
abstract nextSibling(node: any): any;
abstract setAttribute(el: any, name: string, value: string, namespace?: string): void;
abstract removeAttribute(el: any, name: string, namespace?: string): void;
abstract addClass(el: any, name: string): void;
abstract removeClass(el: any, name: string): void;
abstract setStyle(
el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean): void;
abstract removeStyle(el: any, style: string, hasVendorPrefix: boolean): void;
abstract setProperty(el: any, name: string, value: any): void;
abstract setValue(node: any, value: string): void;
abstract listen(
target: 'window'|'document'|'body'|any, eventName: string,
callback: (event: any) => boolean): () => void;
}

View File

@ -132,7 +132,7 @@ export function elementDef(
export function createElement(view: ViewData, renderHost: any, def: NodeDef): ElementData { export function createElement(view: ViewData, renderHost: any, def: NodeDef): ElementData {
const elDef = def.element; const elDef = def.element;
const rootSelectorOrNode = view.root.selectorOrNode; const rootSelectorOrNode = view.root.selectorOrNode;
const renderer = view.root.renderer; const renderer = view.renderer;
let el: any; let el: any;
if (view.parent || !rootSelectorOrNode) { if (view.parent || !rootSelectorOrNode) {
if (elDef.name) { if (elDef.name) {
@ -240,7 +240,7 @@ function setElementAttribute(
const securityContext = binding.securityContext; const securityContext = binding.securityContext;
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value; let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
renderValue = renderValue != null ? renderValue.toString() : null; renderValue = renderValue != null ? renderValue.toString() : null;
const renderer = view.root.renderer; const renderer = view.renderer;
// TODO(vicb): move the namespace to the node definition // TODO(vicb): move the namespace to the node definition
const nsAndName = splitNamespace(name); const nsAndName = splitNamespace(name);
if (value != null) { if (value != null) {
@ -251,7 +251,7 @@ function setElementAttribute(
} }
function setElementClass(view: ViewData, renderNode: any, name: string, value: boolean) { function setElementClass(view: ViewData, renderNode: any, name: string, value: boolean) {
const renderer = view.root.renderer; const renderer = view.renderer;
if (value) { if (value) {
renderer.addClass(renderNode, name); renderer.addClass(renderNode, name);
} else { } else {
@ -271,7 +271,7 @@ function setElementStyle(
} else { } else {
renderValue = null; renderValue = null;
} }
const renderer = view.root.renderer; const renderer = view.renderer;
if (renderValue != null) { if (renderValue != null) {
renderer.setStyle(renderNode, name, renderValue, false, false); renderer.setStyle(renderNode, name, renderValue, false, false);
} else { } else {
@ -283,7 +283,7 @@ function setElementProperty(
view: ViewData, binding: BindingDef, renderNode: any, name: string, value: any) { view: ViewData, binding: BindingDef, renderNode: any, name: string, value: any) {
const securityContext = binding.securityContext; const securityContext = binding.securityContext;
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value; let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
view.root.renderer.setProperty(renderNode, name, renderValue); view.renderer.setProperty(renderNode, name, renderValue);
} }
const NS_PREFIX_RE = /^:([^:]+):(.+)$/; const NS_PREFIX_RE = /^:([^:]+):(.+)$/;

View File

@ -14,7 +14,7 @@ export {queryDef} from './query';
export {createComponentFactory} from './refs'; export {createComponentFactory} from './refs';
export {initServicesIfNeeded} from './services'; export {initServicesIfNeeded} from './services';
export {textDef} from './text'; export {textDef} from './text';
export {elementEventFullName, nodeValue, rootRenderNodes, unwrapValue} from './util'; export {createComponentRenderTypeV2, elementEventFullName, nodeValue, rootRenderNodes, unwrapValue} from './util';
export {viewDef} from './view'; export {viewDef} from './view';
export {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach'; export {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';

View File

@ -11,13 +11,15 @@ import {Injector} from '../di';
import {ElementRef} from '../linker/element_ref'; import {ElementRef} from '../linker/element_ref';
import {TemplateRef} from '../linker/template_ref'; import {TemplateRef} from '../linker/template_ref';
import {ViewContainerRef} from '../linker/view_container_ref'; import {ViewContainerRef} from '../linker/view_container_ref';
import * as v1renderer from '../render/api'; import {ViewEncapsulation} from '../metadata/view';
import {ComponentRenderTypeV2, RenderComponentType as RenderComponentTypeV1, Renderer as RendererV1, RendererFactoryV2, RendererV2, RootRenderer as RootRendererV1} from '../render/api';
import {createChangeDetectorRef, createInjector, createTemplateRef, createViewContainerRef} from './refs'; import {createChangeDetectorRef, createInjector, createTemplateRef, createViewContainerRef} from './refs';
import {BindingDef, BindingType, DepDef, DepFlags, DirectiveOutputDef, DisposableFn, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderType, QueryBindingType, QueryDef, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewState, asElementData, asProviderData} from './types'; import {BindingDef, BindingType, DepDef, DepFlags, DirectiveOutputDef, DisposableFn, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderType, QueryBindingType, QueryDef, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewState, asElementData, asProviderData} from './types';
import {checkAndUpdateBinding, dispatchEvent, filterQueryId, isComponentView, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util'; import {checkAndUpdateBinding, dispatchEvent, filterQueryId, isComponentView, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
const RendererV1TokenKey = tokenKey(v1renderer.Renderer); const RendererV1TokenKey = tokenKey(RendererV1);
const RendererV2TokenKey = tokenKey(RendererV2);
const ElementRefTokenKey = tokenKey(ElementRef); const ElementRefTokenKey = tokenKey(ElementRef);
const ViewContainerRefTokenKey = tokenKey(ViewContainerRef); const ViewContainerRefTokenKey = tokenKey(ViewContainerRef);
const TemplateRefTokenKey = tokenKey(TemplateRef); const TemplateRefTokenKey = tokenKey(TemplateRef);
@ -29,7 +31,8 @@ const NOT_CREATED = new Object();
export function directiveDef( export function directiveDef(
flags: NodeFlags, matchedQueries: [string | number, QueryValueType][], childCount: number, flags: NodeFlags, matchedQueries: [string | number, QueryValueType][], childCount: number,
ctor: any, deps: ([DepFlags, any] | any)[], props?: {[name: string]: [number, string]}, ctor: any, deps: ([DepFlags, any] | any)[], props?: {[name: string]: [number, string]},
outputs?: {[name: string]: string}, component?: () => ViewDefinition): NodeDef { outputs?: {[name: string]: string}, component?: () => ViewDefinition,
componentRenderType?: ComponentRenderTypeV2): NodeDef {
const bindings: BindingDef[] = []; const bindings: BindingDef[] = [];
if (props) { if (props) {
for (let prop in props) { for (let prop in props) {
@ -50,7 +53,7 @@ export function directiveDef(
} }
return _def( return _def(
NodeType.Directive, flags, matchedQueries, childCount, ProviderType.Class, ctor, ctor, deps, NodeType.Directive, flags, matchedQueries, childCount, ProviderType.Class, ctor, ctor, deps,
bindings, outputDefs, component); bindings, outputDefs, component, componentRenderType);
} }
export function pipeDef(flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef { export function pipeDef(flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef {
@ -67,8 +70,13 @@ export function _def(
type: NodeType, flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][], type: NodeType, flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
childCount: number, providerType: ProviderType, token: any, value: any, childCount: number, providerType: ProviderType, token: any, value: any,
deps: ([DepFlags, any] | any)[], bindings?: BindingDef[], outputs?: DirectiveOutputDef[], deps: ([DepFlags, any] | any)[], bindings?: BindingDef[], outputs?: DirectiveOutputDef[],
component?: () => ViewDefinition): NodeDef { component?: () => ViewDefinition, componentRenderType?: ComponentRenderTypeV2): NodeDef {
const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl); const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl);
// This is needed as the jit compiler always uses an empty hash as default ComponentRenderTypeV2,
// which is not filled for host views.
if (componentRenderType && componentRenderType.encapsulation == null) {
componentRenderType = null;
}
if (!outputs) { if (!outputs) {
outputs = []; outputs = [];
} }
@ -111,7 +119,7 @@ export function _def(
type: providerType, type: providerType,
token, token,
tokenKey: tokenKey(token), value, tokenKey: tokenKey(token), value,
deps: depDefs, outputs, component deps: depDefs, outputs, component, componentRenderType
}, },
text: undefined, text: undefined,
pureExpression: undefined, pureExpression: undefined,
@ -328,16 +336,19 @@ export function resolveDep(
if (elDef) { if (elDef) {
switch (tokenKey) { switch (tokenKey) {
case RendererV1TokenKey: { case RendererV1TokenKey: {
let compView = view; const compView = findCompView(view, elDef, allowPrivateServices);
while (compView && !isComponentView(compView)) { const compDef = compView.parentNodeDef;
compView = compView.parent; const rootRendererV1: RootRendererV1 = view.root.injector.get(RootRendererV1);
}
const rootRenderer: v1renderer.RootRenderer =
view.root.injector.get(v1renderer.RootRenderer);
// Note: Don't fill in the styles as they have been installed already! // Note: Don't fill in the styles as they have been installed already via the RendererV2!
return rootRenderer.renderComponent(new v1renderer.RenderComponentType( const compRenderType = compDef.provider.componentRenderType;
view.def.component.id, '', 0, view.def.component.encapsulation, [], {})); return rootRendererV1.renderComponent(new RenderComponentTypeV1(
compRenderType ? compRenderType.id : '0', '', 0,
compRenderType ? compRenderType.encapsulation : ViewEncapsulation.None, [], {}));
}
case RendererV2TokenKey: {
const compView = findCompView(view, elDef, allowPrivateServices);
return compView.renderer;
} }
case ElementRefTokenKey: case ElementRefTokenKey:
return new ElementRef(asElementData(view, elDef.index).renderElement); return new ElementRef(asElementData(view, elDef.index).renderElement);
@ -350,15 +361,7 @@ export function resolveDep(
break; break;
} }
case ChangeDetectorRefTokenKey: { case ChangeDetectorRefTokenKey: {
let cdView: ViewData; let cdView = findCompView(view, elDef, allowPrivateServices);
if (allowPrivateServices) {
cdView = asProviderData(view, elDef.element.component.index).componentView;
} else {
cdView = view;
while (cdView.parent && !isComponentView(cdView)) {
cdView = cdView.parent;
}
}
return createChangeDetectorRef(cdView); return createChangeDetectorRef(cdView);
} }
case InjectorRefTokenKey: case InjectorRefTokenKey:
@ -383,6 +386,19 @@ export function resolveDep(
return startView.root.injector.get(depDef.token, notFoundValue); return startView.root.injector.get(depDef.token, notFoundValue);
} }
function findCompView(view: ViewData, elDef: NodeDef, allowPrivateServices: boolean) {
let compView: ViewData;
if (allowPrivateServices) {
compView = asProviderData(view, elDef.element.component.index).componentView;
} else {
compView = view;
while (compView.parent && !isComponentView(compView)) {
compView = compView.parent;
}
}
return compView;
}
function checkAndUpdateProp( function checkAndUpdateProp(
view: ViewData, providerData: ProviderData, def: NodeDef, bindingIdx: number, value: any, view: ViewData, providerData: ProviderData, def: NodeDef, bindingIdx: number, value: any,
changes: SimpleChanges): SimpleChanges { changes: SimpleChanges): SimpleChanges {

View File

@ -201,8 +201,9 @@ export function createInjector(view: ViewData, elDef: NodeDef): Injector {
class Injector_ implements Injector { class Injector_ implements Injector {
constructor(private view: ViewData, private elDef: NodeDef) {} constructor(private view: ViewData, private elDef: NodeDef) {}
get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any { get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any {
const allowPrivateServices = !!this.elDef.element.component;
return Services.resolveDep( return Services.resolveDep(
this.view, this.elDef, true, {flags: DepFlags.None, token, tokenKey: tokenKey(token)}, this.view, this.elDef, allowPrivateServices,
notFoundValue); {flags: DepFlags.None, token, tokenKey: tokenKey(token)}, notFoundValue);
} }
} }

View File

@ -7,8 +7,9 @@
*/ */
import {isDevMode} from '../application_ref'; import {isDevMode} from '../application_ref';
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node';
import {Injector} from '../di'; import {Injector} from '../di';
import {RendererV2} from '../render/api'; import {ComponentRenderTypeV2, RendererFactoryV2, RendererV2} from '../render/api';
import {Sanitizer, SecurityContext} from '../security'; import {Sanitizer, SecurityContext} from '../security';
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors'; import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
@ -87,52 +88,59 @@ function createDebugServices() {
function createProdRootView( function createProdRootView(
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: string | any, injector: Injector, projectableNodes: any[][], rootSelectorOrNode: string | any,
def: ViewDefinition, context?: any): ViewData { def: ViewDefinition, context?: any): ViewData {
const rendererFactory: RendererFactoryV2 = injector.get(RendererFactoryV2);
return createRootView( return createRootView(
createRootData(injector, projectableNodes, rootSelectorOrNode), def, context); createRootData(injector, rendererFactory, projectableNodes, rootSelectorOrNode), def,
context);
} }
function debugCreateRootView( function debugCreateRootView(
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: string | any, injector: Injector, projectableNodes: any[][], rootSelectorOrNode: string | any,
def: ViewDefinition, context?: any): ViewData { def: ViewDefinition, context?: any): ViewData {
const root = createRootData(injector, projectableNodes, rootSelectorOrNode); const rendererFactory: RendererFactoryV2 = injector.get(RendererFactoryV2);
const debugRoot: RootData = { const root = createRootData(
injector: root.injector, injector, new DebugRendererFactoryV2(rendererFactory), projectableNodes, rootSelectorOrNode);
projectableNodes: root.projectableNodes, return callWithDebugContext(DebugAction.create, createRootView, null, [root, def, context]);
selectorOrNode: root.selectorOrNode,
renderer: new DebugRenderer(root.renderer),
sanitizer: root.sanitizer
};
return callWithDebugContext('create', createRootView, null, [debugRoot, def, context]);
} }
function createRootData( function createRootData(
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: any): RootData { injector: Injector, rendererFactory: RendererFactoryV2, projectableNodes: any[][],
rootSelectorOrNode: any): RootData {
const sanitizer = injector.get(Sanitizer); const sanitizer = injector.get(Sanitizer);
const renderer = injector.get(RendererV2); const renderer = rendererFactory.createRenderer(null, null);
return {
const rootElement = injector,
rootSelectorOrNode ? renderer.selectRootElement(rootSelectorOrNode) : undefined; projectableNodes,
return {injector, projectableNodes, selectorOrNode: rootSelectorOrNode, sanitizer, renderer}; selectorOrNode: rootSelectorOrNode, sanitizer, rendererFactory, renderer
};
} }
function debugCreateEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData { function debugCreateEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData {
return callWithDebugContext('create', createEmbeddedView, null, [parent, anchorDef, context]); return callWithDebugContext(
DebugAction.create, createEmbeddedView, null, [parent, anchorDef, context]);
} }
function debugCheckAndUpdateView(view: ViewData) { function debugCheckAndUpdateView(view: ViewData) {
return callWithDebugContext('detectChanges', checkAndUpdateView, null, [view]); return callWithDebugContext(DebugAction.detectChanges, checkAndUpdateView, null, [view]);
} }
function debugCheckNoChangesView(view: ViewData) { function debugCheckNoChangesView(view: ViewData) {
return callWithDebugContext('checkNoChanges', checkNoChangesView, null, [view]); return callWithDebugContext(DebugAction.checkNoChanges, checkNoChangesView, null, [view]);
} }
function debugDestroyView(view: ViewData) { function debugDestroyView(view: ViewData) {
return callWithDebugContext('destroyView', destroyView, null, [view]); return callWithDebugContext(DebugAction.destroy, destroyView, null, [view]);
} }
enum DebugAction {
create,
detectChanges,
checkNoChanges,
destroy,
handleEvent
}
let _currentAction: string; let _currentAction: DebugAction;
let _currentView: ViewData; let _currentView: ViewData;
let _currentNodeIndex: number; let _currentNodeIndex: number;
@ -143,16 +151,16 @@ function debugSetCurrentNode(view: ViewData, nodeIndex: number) {
function debugHandleEvent(view: ViewData, nodeIndex: number, eventName: string, event: any) { function debugHandleEvent(view: ViewData, nodeIndex: number, eventName: string, event: any) {
if (view.state & ViewState.Destroyed) { if (view.state & ViewState.Destroyed) {
throw viewDestroyedError(_currentAction); throw viewDestroyedError(DebugAction[_currentAction]);
} }
debugSetCurrentNode(view, nodeIndex); debugSetCurrentNode(view, nodeIndex);
return callWithDebugContext( return callWithDebugContext(
'handleEvent', view.def.handleEvent, null, [view, nodeIndex, eventName, event]); DebugAction.handleEvent, view.def.handleEvent, null, [view, nodeIndex, eventName, event]);
} }
function debugUpdateDirectives(check: NodeCheckFn, view: ViewData) { function debugUpdateDirectives(check: NodeCheckFn, view: ViewData) {
if (view.state & ViewState.Destroyed) { if (view.state & ViewState.Destroyed) {
throw viewDestroyedError(_currentAction); throw viewDestroyedError(DebugAction[_currentAction]);
} }
debugSetCurrentNode(view, nextDirectiveWithBinding(view, 0)); debugSetCurrentNode(view, nextDirectiveWithBinding(view, 0));
return view.def.updateDirectives(debugCheckDirectivesFn, view); return view.def.updateDirectives(debugCheckDirectivesFn, view);
@ -167,7 +175,7 @@ function debugUpdateDirectives(check: NodeCheckFn, view: ViewData) {
function debugUpdateRenderer(check: NodeCheckFn, view: ViewData) { function debugUpdateRenderer(check: NodeCheckFn, view: ViewData) {
if (view.state & ViewState.Destroyed) { if (view.state & ViewState.Destroyed) {
throw viewDestroyedError(_currentAction); throw viewDestroyedError(DebugAction[_currentAction]);
} }
debugSetCurrentNode(view, nextRenderNodeWithBinding(view, 0)); debugSetCurrentNode(view, nextRenderNodeWithBinding(view, 0));
return view.def.updateRenderer(debugCheckRenderNodeFn, view); return view.def.updateRenderer(debugCheckRenderNodeFn, view);
@ -183,35 +191,41 @@ function debugUpdateRenderer(check: NodeCheckFn, view: ViewData) {
function debugCheckFn( function debugCheckFn(
delegate: NodeCheckFn, view: ViewData, nodeIndex: number, argStyle: ArgumentType, delegate: NodeCheckFn, view: ViewData, nodeIndex: number, argStyle: ArgumentType,
givenValues: any[]) { givenValues: any[]) {
const values = argStyle === ArgumentType.Dynamic ? givenValues[0] : givenValues; if (_currentAction === DebugAction.detectChanges) {
const nodeDef = view.def.nodes[nodeIndex]; const values = argStyle === ArgumentType.Dynamic ? givenValues[0] : givenValues;
for (let i = 0; i < nodeDef.bindings.length; i++) { const nodeDef = view.def.nodes[nodeIndex];
const binding = nodeDef.bindings[i]; if (nodeDef.type === NodeType.Directive || nodeDef.type === NodeType.Element) {
const value = values[i]; const bindingValues: {[key: string]: string} = {};
if ((binding.type === BindingType.ElementProperty || for (let i = 0; i < nodeDef.bindings.length; i++) {
binding.type === BindingType.DirectiveProperty) && const binding = nodeDef.bindings[i];
checkBinding(view, nodeDef, i, value)) { const value = values[i];
if ((binding.type === BindingType.ElementProperty ||
binding.type === BindingType.DirectiveProperty) &&
checkBinding(view, nodeDef, i, value)) {
bindingValues[normalizeDebugBindingName(binding.nonMinifiedName)] =
normalizeDebugBindingValue(value);
}
}
const elDef = nodeDef.type === NodeType.Directive ? nodeDef.parent : nodeDef; const elDef = nodeDef.type === NodeType.Directive ? nodeDef.parent : nodeDef;
setBindingDebugInfo( const el = asElementData(view, elDef.index).renderElement;
view.root.renderer, asElementData(view, elDef.index).renderElement, if (!elDef.element.name) {
binding.nonMinifiedName, value); // a comment.
view.renderer.setValue(el, `bindings=${JSON.stringify(bindingValues, null, 2)}`);
} else {
// a regular element.
for (let attr in bindingValues) {
view.renderer.setAttribute(el, attr, bindingValues[attr]);
}
}
} }
} }
return (<any>delegate)(view, nodeIndex, argStyle, ...givenValues); return (<any>delegate)(view, nodeIndex, argStyle, ...givenValues);
}; };
function setBindingDebugInfo(renderer: RendererV2, renderNode: any, propName: string, value: any) { function normalizeDebugBindingName(name: string) {
const renderName = `ng-reflect-${camelCaseToDashCase(propName)}`; // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
if (value) { name = camelCaseToDashCase(name.replace(/\$/g, '_'));
try { return `ng-reflect-${name}`;
renderer.setBindingDebugInfo(renderNode, renderName, value.toString());
} catch (e) {
renderer.setBindingDebugInfo(
renderNode, renderName, '[ERROR] Exception while trying to serialize the value');
}
} else {
renderer.removeBindingDebugInfo(renderNode, renderName);
}
} }
const CAMEL_CASE_REGEXP = /([A-Z])/g; const CAMEL_CASE_REGEXP = /([A-Z])/g;
@ -220,6 +234,15 @@ function camelCaseToDashCase(input: string): string {
return input.replace(CAMEL_CASE_REGEXP, (...m: any[]) => '-' + m[1].toLowerCase()); return input.replace(CAMEL_CASE_REGEXP, (...m: any[]) => '-' + m[1].toLowerCase());
} }
function normalizeDebugBindingValue(value: any): string {
try {
// Limit the size of the value as otherwise the DOM just gets polluted.
return value ? value.toString().slice(0, 20) : value;
} catch (e) {
return '[ERROR] Exception while trying to serialize the value';
}
}
function nextDirectiveWithBinding(view: ViewData, nodeIndex: number): number { function nextDirectiveWithBinding(view: ViewData, nodeIndex: number): number {
for (let i = nodeIndex; i < view.def.nodes.length; i++) { for (let i = nodeIndex; i < view.def.nodes.length; i++) {
const nodeDef = view.def.nodes[i]; const nodeDef = view.def.nodes[i];
@ -241,64 +264,6 @@ function nextRenderNodeWithBinding(view: ViewData, nodeIndex: number): number {
return undefined; return undefined;
} }
class DebugRenderer implements RendererV2 {
constructor(private _delegate: RendererV2) {}
createElement(name: string, namespace?: string): any {
return this._delegate.createElement(name, namespace, getCurrentDebugContext());
}
createComment(value: string): any {
return this._delegate.createComment(value, getCurrentDebugContext());
}
createText(value: string): any {
return this._delegate.createText(value, getCurrentDebugContext());
}
appendChild(parent: any, newChild: any): void {
return this._delegate.appendChild(parent, newChild);
}
insertBefore(parent: any, newChild: any, refChild: any): void {
return this._delegate.insertBefore(parent, newChild, refChild);
}
removeChild(parent: any, oldChild: any): void {
return this._delegate.removeChild(parent, oldChild);
}
selectRootElement(selectorOrNode: string|any): any {
return this._delegate.selectRootElement(selectorOrNode, getCurrentDebugContext());
}
parentNode(node: any): any { return this._delegate.parentNode(node); }
nextSibling(node: any): any { return this._delegate.nextSibling(node); }
setAttribute(el: any, name: string, value: string, namespace?: string): void {
return this._delegate.setAttribute(el, name, value, namespace);
}
removeAttribute(el: any, name: string, namespace?: string): void {
return this._delegate.removeAttribute(el, name, namespace);
}
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {
this._delegate.setBindingDebugInfo(el, propertyName, propertyValue);
}
removeBindingDebugInfo(el: any, propertyName: string): void {
this._delegate.removeBindingDebugInfo(el, propertyName);
}
addClass(el: any, name: string): void { return this._delegate.addClass(el, name); }
removeClass(el: any, name: string): void { return this._delegate.removeClass(el, name); }
setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean):
void {
return this._delegate.setStyle(el, style, value, hasVendorPrefix, hasImportant);
}
removeStyle(el: any, style: string, hasVendorPrefix: boolean): void {
return this._delegate.removeStyle(el, style, hasVendorPrefix);
}
setProperty(el: any, name: string, value: any): void {
return this._delegate.setProperty(el, name, value);
}
setText(node: any, value: string): void { return this._delegate.setText(node, value); }
listen(
target: 'window'|'document'|'body'|any, eventName: string,
callback: (event: any) => boolean): () => void {
return this._delegate.listen(target, eventName, callback);
}
}
class DebugContext_ implements DebugContext { class DebugContext_ implements DebugContext {
private nodeDef: NodeDef; private nodeDef: NodeDef;
private elView: ViewData; private elView: ViewData;
@ -401,7 +366,7 @@ function collectReferences(view: ViewData, nodeDef: NodeDef, references: {[key:
} }
} }
function callWithDebugContext(action: string, fn: any, self: any, args: any[]) { function callWithDebugContext(action: DebugAction, fn: any, self: any, args: any[]) {
const oldAction = _currentAction; const oldAction = _currentAction;
const oldView = _currentView; const oldView = _currentView;
const oldNodeIndex = _currentNodeIndex; const oldNodeIndex = _currentNodeIndex;
@ -421,6 +386,163 @@ function callWithDebugContext(action: string, fn: any, self: any, args: any[]) {
} }
} }
function getCurrentDebugContext() { export function getCurrentDebugContext(): DebugContext {
return new DebugContext_(_currentView, _currentNodeIndex); return new DebugContext_(_currentView, _currentNodeIndex);
} }
class DebugRendererFactoryV2 implements RendererFactoryV2 {
constructor(private delegate: RendererFactoryV2) {}
createRenderer(element: any, renderData: ComponentRenderTypeV2): RendererV2 {
return new DebugRendererV2(this.delegate.createRenderer(element, renderData));
}
}
class DebugRendererV2 implements RendererV2 {
constructor(private delegate: RendererV2) {}
destroyNode(node: any) {
removeDebugNodeFromIndex(getDebugNode(node));
if (this.delegate.destroyNode) {
this.delegate.destroyNode(node);
}
}
destroy() { this.delegate.destroy(); }
createElement(name: string, namespace?: string): any {
const el = this.delegate.createElement(name, namespace);
const debugEl = new DebugElement(el, null, getCurrentDebugContext());
debugEl.name = name;
indexDebugNode(debugEl);
return el;
}
createComment(value: string): any {
const comment = this.delegate.createComment(value);
const debugEl = new DebugNode(comment, null, getCurrentDebugContext());
indexDebugNode(debugEl);
return comment;
}
createText(value: string): any {
const text = this.delegate.createText(value);
const debugEl = new DebugNode(text, null, getCurrentDebugContext());
indexDebugNode(debugEl);
return text;
}
appendChild(parent: any, newChild: any): void {
const debugEl = getDebugNode(parent);
const debugChildEl = getDebugNode(newChild);
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
debugEl.addChild(debugChildEl);
}
this.delegate.appendChild(parent, newChild);
}
insertBefore(parent: any, newChild: any, refChild: any): void {
const debugEl = getDebugNode(parent);
const debugChildEl = getDebugNode(newChild);
const debugRefEl = getDebugNode(refChild);
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
debugEl.insertBefore(debugRefEl, debugChildEl);
}
this.delegate.insertBefore(parent, newChild, refChild);
}
removeChild(parent: any, oldChild: any): void {
const debugEl = getDebugNode(parent);
const debugChildEl = getDebugNode(oldChild);
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
debugEl.removeChild(debugChildEl);
}
this.delegate.removeChild(parent, oldChild);
}
selectRootElement(selectorOrNode: string|any): any {
const el = this.delegate.selectRootElement(selectorOrNode);
const debugEl = new DebugElement(el, null, getCurrentDebugContext());
indexDebugNode(debugEl);
return el;
}
setAttribute(el: any, name: string, value: string, namespace?: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
const fullName = namespace ? namespace + ':' + name : name;
debugEl.attributes[fullName] = value;
}
this.delegate.setAttribute(el, name, value, namespace);
}
removeAttribute(el: any, name: string, namespace?: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
const fullName = namespace ? namespace + ':' + name : name;
debugEl.attributes[fullName] = null;
}
this.delegate.removeAttribute(el, name, namespace);
}
addClass(el: any, name: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
debugEl.classes[name] = true;
}
this.delegate.addClass(el, name);
}
removeClass(el: any, name: string): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
debugEl.classes[name] = false;
}
this.delegate.removeClass(el, name);
}
setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean):
void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
debugEl.styles[style] = value;
}
this.delegate.setStyle(el, style, value, hasVendorPrefix, hasImportant);
}
removeStyle(el: any, style: string, hasVendorPrefix: boolean): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
debugEl.styles[style] = null;
}
this.delegate.removeStyle(el, style, hasVendorPrefix);
}
setProperty(el: any, name: string, value: any): void {
const debugEl = getDebugNode(el);
if (debugEl && debugEl instanceof DebugElement) {
debugEl.properties[name] = value;
}
this.delegate.setProperty(el, name, value);
}
listen(
target: 'document'|'windows'|'body'|any, eventName: string,
callback: (event: any) => boolean): () => void {
if (typeof target !== 'string') {
const debugEl = getDebugNode(target);
if (debugEl) {
debugEl.listeners.push(new EventListener(eventName, callback));
}
}
return this.delegate.listen(target, eventName, callback);
}
parentNode(node: any): any { return this.delegate.parentNode(node); }
nextSibling(node: any): any { return this.delegate.nextSibling(node); }
setValue(node: any, value: string): void { return this.delegate.setValue(node, value); }
}

View File

@ -54,7 +54,7 @@ export function textDef(ngContentIndex: number, constants: string[]): NodeDef {
export function createText(view: ViewData, renderHost: any, def: NodeDef): TextData { export function createText(view: ViewData, renderHost: any, def: NodeDef): TextData {
let renderNode: any; let renderNode: any;
const renderer = view.root.renderer; const renderer = view.renderer;
renderNode = renderer.createText(def.text.prefix); renderNode = renderer.createText(def.text.prefix);
const parentEl = getParentRenderElement(view, renderHost, def); const parentEl = getParentRenderElement(view, renderHost, def);
if (parentEl) { if (parentEl) {
@ -119,7 +119,7 @@ export function checkAndUpdateTextInline(
} }
value = def.text.prefix + value; value = def.text.prefix + value;
const renderNode = asTextData(view, def.index).renderText; const renderNode = asTextData(view, def.index).renderText;
view.root.renderer.setText(renderNode, value); view.renderer.setValue(renderNode, value);
} }
} }
@ -140,7 +140,7 @@ export function checkAndUpdateTextDynamic(view: ViewData, def: NodeDef, values:
} }
value = def.text.prefix + value; value = def.text.prefix + value;
const renderNode = asTextData(view, def.index).renderText; const renderNode = asTextData(view, def.index).renderText;
view.root.renderer.setText(renderNode, value); view.renderer.setValue(renderNode, value);
} }
} }

View File

@ -14,7 +14,7 @@ import {TemplateRef} from '../linker/template_ref';
import {ViewContainerRef} from '../linker/view_container_ref'; import {ViewContainerRef} from '../linker/view_container_ref';
import {ViewRef} from '../linker/view_ref'; import {ViewRef} from '../linker/view_ref';
import {ViewEncapsulation} from '../metadata/view'; import {ViewEncapsulation} from '../metadata/view';
import {RenderDebugContext, RendererV2} from '../render/api'; import {ComponentRenderTypeV2, RendererFactoryV2, RendererV2} from '../render/api';
import {Sanitizer, SecurityContext} from '../security'; import {Sanitizer, SecurityContext} from '../security';
// ------------------------------------- // -------------------------------------
@ -23,7 +23,6 @@ import {Sanitizer, SecurityContext} from '../security';
export interface ViewDefinition { export interface ViewDefinition {
flags: ViewFlags; flags: ViewFlags;
component: ComponentDefinition;
updateDirectives: ViewUpdateFn; updateDirectives: ViewUpdateFn;
updateRenderer: ViewUpdateFn; updateRenderer: ViewUpdateFn;
handleEvent: ViewHandleEventFn; handleEvent: ViewHandleEventFn;
@ -75,13 +74,7 @@ export enum ArgumentType {
*/ */
export enum ViewFlags { export enum ViewFlags {
None = 0, None = 0,
OnPush = 1 << 1 OnPush = 1 << 1,
}
export interface ComponentDefinition {
id: string;
encapsulation: ViewEncapsulation;
styles: string[];
} }
/** /**
@ -223,6 +216,7 @@ export interface ProviderDef {
value: any; value: any;
deps: DepDef[]; deps: DepDef[];
outputs: DirectiveOutputDef[]; outputs: DirectiveOutputDef[];
componentRenderType: ComponentRenderTypeV2;
// closure to allow recursive components // closure to allow recursive components
component: ViewDefinitionFactory; component: ViewDefinitionFactory;
} }
@ -306,6 +300,7 @@ export interface NgContentDef {
export interface ViewData { export interface ViewData {
def: ViewDefinition; def: ViewDefinition;
root: RootData; root: RootData;
renderer: RendererV2;
// index of component provider / anchor. // index of component provider / anchor.
parentNodeDef: NodeDef; parentNodeDef: NodeDef;
parent: ViewData; parent: ViewData;
@ -426,12 +421,21 @@ export interface RootData {
projectableNodes: any[][]; projectableNodes: any[][];
selectorOrNode: any; selectorOrNode: any;
renderer: RendererV2; renderer: RendererV2;
rendererFactory: RendererFactoryV2;
sanitizer: Sanitizer; sanitizer: Sanitizer;
} }
export abstract class DebugContext extends RenderDebugContext { export abstract class DebugContext {
abstract get view(): ViewData; abstract get view(): ViewData;
abstract get nodeIndex(): number; abstract get nodeIndex(): number;
abstract get injector(): Injector;
abstract get component(): any;
abstract get providerTokens(): any[];
abstract get references(): {[key: string]: any};
abstract get context(): any;
abstract get source(): string;
abstract get componentRenderElement(): any;
abstract get renderNode(): any;
} }
// ------------------------------------- // -------------------------------------

View File

@ -14,7 +14,8 @@ import {looseIdentical, stringify} from '../facade/lang';
import {TemplateRef} from '../linker/template_ref'; import {TemplateRef} from '../linker/template_ref';
import {ViewContainerRef} from '../linker/view_container_ref'; import {ViewContainerRef} from '../linker/view_container_ref';
import {ViewRef} from '../linker/view_ref'; import {ViewRef} from '../linker/view_ref';
import {Renderer} from '../render/api'; import {ViewEncapsulation} from '../metadata/view';
import {ComponentRenderTypeV2, Renderer} from '../render/api';
import {expressionChangedAfterItHasBeenCheckedError, isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors'; import {expressionChangedAfterItHasBeenCheckedError, isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
import {DebugContext, ElementData, NodeData, NodeDef, NodeFlags, NodeType, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewState, asElementData, asProviderData, asTextData} from './types'; import {DebugContext, ElementData, NodeData, NodeDef, NodeFlags, NodeType, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewState, asElementData, asProviderData, asTextData} from './types';
@ -40,6 +41,23 @@ export function unwrapValue(value: any): any {
return value; return value;
} }
let _renderCompCount = 0;
export function createComponentRenderTypeV2(values: {
styles: (string | any[])[],
encapsulation: ViewEncapsulation,
data: {[kind: string]: any[]}
}): ComponentRenderTypeV2 {
const isFilled = values && (values.encapsulation !== ViewEncapsulation.None ||
values.styles.length || Object.keys(values.data).length);
if (isFilled) {
const id = `c${_renderCompCount++}`;
return {id: id, styles: values.styles, encapsulation: values.encapsulation, data: values.data};
} else {
return null;
}
}
export function checkBinding( export function checkBinding(
view: ViewData, def: NodeDef, bindingIdx: number, value: any): boolean { view: ViewData, def: NodeDef, bindingIdx: number, value: any): boolean {
const oldValue = view.oldValues[def.bindingIndex + bindingIdx]; const oldValue = view.oldValues[def.bindingIndex + bindingIdx];
@ -220,7 +238,7 @@ export function visitRootRenderNodes(
view: ViewData, action: RenderNodeAction, parentNode: any, nextSibling: any, target: any[]) { view: ViewData, action: RenderNodeAction, parentNode: any, nextSibling: any, target: any[]) {
// We need to re-compute the parent node in case the nodes have been moved around manually // We need to re-compute the parent node in case the nodes have been moved around manually
if (action === RenderNodeAction.RemoveChild) { if (action === RenderNodeAction.RemoveChild) {
parentNode = view.root.renderer.parentNode(renderNode(view, view.def.lastRootNode)); parentNode = view.renderer.parentNode(renderNode(view, view.def.lastRootNode));
} }
visitSiblingRenderNodes( visitSiblingRenderNodes(
view, action, 0, view.def.nodes.length - 1, parentNode, nextSibling, target); view, action, 0, view.def.nodes.length - 1, parentNode, nextSibling, target);
@ -298,7 +316,7 @@ function visitRenderNode(
function execRenderNodeAction( function execRenderNodeAction(
view: ViewData, renderNode: any, action: RenderNodeAction, parentNode: any, nextSibling: any, view: ViewData, renderNode: any, action: RenderNodeAction, parentNode: any, nextSibling: any,
target: any[]) { target: any[]) {
const renderer = view.root.renderer; const renderer = view.renderer;
switch (action) { switch (action) {
case RenderNodeAction.AppendChild: case RenderNodeAction.AppendChild:
renderer.appendChild(parentNode, renderNode); renderer.appendChild(parentNode, renderNode);

View File

@ -7,6 +7,7 @@
*/ */
import {ViewEncapsulation} from '../metadata/view'; import {ViewEncapsulation} from '../metadata/view';
import {ComponentRenderTypeV2, RendererV2} from '../render/api';
import {checkAndUpdateElementDynamic, checkAndUpdateElementInline, createElement} from './element'; import {checkAndUpdateElementDynamic, checkAndUpdateElementInline, createElement} from './element';
import {expressionChangedAfterItHasBeenCheckedError} from './errors'; import {expressionChangedAfterItHasBeenCheckedError} from './errors';
@ -15,15 +16,14 @@ import {callLifecycleHooksChildrenFirst, checkAndUpdateDirectiveDynamic, checkAn
import {checkAndUpdatePureExpressionDynamic, checkAndUpdatePureExpressionInline, createPureExpression} from './pure_expression'; import {checkAndUpdatePureExpressionDynamic, checkAndUpdatePureExpressionInline, createPureExpression} from './pure_expression';
import {checkAndUpdateQuery, createQuery, queryDef} from './query'; import {checkAndUpdateQuery, createQuery, queryDef} from './query';
import {checkAndUpdateTextDynamic, checkAndUpdateTextInline, createText} from './text'; import {checkAndUpdateTextDynamic, checkAndUpdateTextInline, createText} from './text';
import {ArgumentType, ComponentDefinition, ElementDef, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderDef, RootData, Services, TextDef, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, asElementData, asProviderData, asPureExpressionData, asQueryList} from './types'; import {ArgumentType, ElementDef, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderDef, RootData, Services, TextDef, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, asElementData, asProviderData, asPureExpressionData, asQueryList, asTextData} from './types';
import {checkBindingNoChanges, isComponentView, resolveViewDefinition, viewParentEl} from './util'; import {checkBindingNoChanges, isComponentView, resolveViewDefinition, viewParentEl} from './util';
const NOOP = (): any => undefined; const NOOP = (): any => undefined;
export function viewDef( export function viewDef(
flags: ViewFlags, nodes: NodeDef[], updateDirectives?: ViewUpdateFn, flags: ViewFlags, nodes: NodeDef[], updateDirectives?: ViewUpdateFn,
updateRenderer?: ViewUpdateFn, handleEvent?: ViewHandleEventFn, compId?: string, updateRenderer?: ViewUpdateFn, handleEvent?: ViewHandleEventFn): ViewDefinition {
encapsulation?: ViewEncapsulation, styles?: string[]): ViewDefinition {
// clone nodes and set auto calculated values // clone nodes and set auto calculated values
if (nodes.length === 0) { if (nodes.length === 0) {
throw new Error(`Illegal State: Views without nodes are not allowed!`); throw new Error(`Illegal State: Views without nodes are not allowed!`);
@ -57,8 +57,11 @@ export function viewDef(
let currentRenderParent: NodeDef; let currentRenderParent: NodeDef;
if (currentParent && if (currentParent &&
!(currentParent.type === NodeType.Element && currentParent.element.component)) { (currentParent.type !== NodeType.Element || !currentParent.element.component ||
// children of components should never be attached! (currentParent.element.component.provider.componentRenderType &&
currentParent.element.component.provider.componentRenderType.encapsulation ===
ViewEncapsulation.Native))) {
// children of components that don't use native encapsulation should never be attached!
if (currentParent && currentParent.type === NodeType.Element && !currentParent.element.name) { if (currentParent && currentParent.type === NodeType.Element && !currentParent.element.name) {
currentRenderParent = currentParent.renderParent; currentRenderParent = currentParent.renderParent;
} else { } else {
@ -134,8 +137,6 @@ export function viewDef(
} }
currentParent = newParent; currentParent = newParent;
} }
const componentDef =
compId ? <ComponentDefinition>{id: compId, encapsulation, styles} : undefined;
return { return {
nodeFlags: viewNodeFlags, nodeFlags: viewNodeFlags,
nodeMatchedQueries: viewMatchedQueries, flags, nodeMatchedQueries: viewMatchedQueries, flags,
@ -143,7 +144,6 @@ export function viewDef(
updateDirectives: updateDirectives || NOOP, updateDirectives: updateDirectives || NOOP,
updateRenderer: updateRenderer || NOOP, updateRenderer: updateRenderer || NOOP,
handleEvent: handleEvent || NOOP, handleEvent: handleEvent || NOOP,
component: componentDef,
bindingCount: viewBindingCount, bindingCount: viewBindingCount,
disposableCount: viewDisposableCount, lastRootNode disposableCount: viewDisposableCount, lastRootNode
}; };
@ -222,21 +222,23 @@ function validateNode(parent: NodeDef, node: NodeDef, nodeCount: number) {
export function createEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData { export function createEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData {
// embedded views are seen as siblings to the anchor, so we need // embedded views are seen as siblings to the anchor, so we need
// to get the parent of the anchor and use it as parentIndex. // to get the parent of the anchor and use it as parentIndex.
const view = createView(parent.root, parent, anchorDef, anchorDef.element.template); const view =
createView(parent.root, parent.renderer, parent, anchorDef, anchorDef.element.template);
initView(view, parent.component, context); initView(view, parent.component, context);
createViewNodes(view); createViewNodes(view);
return view; return view;
} }
export function createRootView(root: RootData, def: ViewDefinition, context?: any): ViewData { export function createRootView(root: RootData, def: ViewDefinition, context?: any): ViewData {
const view = createView(root, null, null, def); const view = createView(root, root.renderer, null, null, def);
initView(view, context, context); initView(view, context, context);
createViewNodes(view); createViewNodes(view);
return view; return view;
} }
function createView( function createView(
root: RootData, parent: ViewData, parentNodeDef: NodeDef, def: ViewDefinition): ViewData { root: RootData, renderer: RendererV2, parent: ViewData, parentNodeDef: NodeDef,
def: ViewDefinition): ViewData {
const nodes: NodeData[] = new Array(def.nodes.length); const nodes: NodeData[] = new Array(def.nodes.length);
const disposables = def.disposableCount ? new Array(def.disposableCount) : undefined; const disposables = def.disposableCount ? new Array(def.disposableCount) : undefined;
const view: ViewData = { const view: ViewData = {
@ -245,7 +247,7 @@ function createView(
parentNodeDef, parentNodeDef,
context: undefined, context: undefined,
component: undefined, nodes, component: undefined, nodes,
state: ViewState.FirstCheck | ViewState.ChecksEnabled, root, state: ViewState.FirstCheck | ViewState.ChecksEnabled, root, renderer,
oldValues: new Array(def.bindingCount), disposables oldValues: new Array(def.bindingCount), disposables
}; };
return view; return view;
@ -259,9 +261,9 @@ function initView(view: ViewData, component: any, context: any) {
function createViewNodes(view: ViewData) { function createViewNodes(view: ViewData) {
let renderHost: any; let renderHost: any;
if (isComponentView(view)) { if (isComponentView(view)) {
renderHost = asElementData(view.parent, viewParentEl(view).index).renderElement; const hostDef = view.parentNodeDef;
renderHost = asElementData(view.parent, hostDef.parent.index).renderElement;
} }
const def = view.def; const def = view.def;
const nodes = view.nodes; const nodes = view.nodes;
for (let i = 0; i < def.nodes.length; i++) { for (let i = 0; i < def.nodes.length; i++) {
@ -291,8 +293,16 @@ function createViewNodes(view: ViewData) {
// Components can inject a ChangeDetectorRef that needs a references to // Components can inject a ChangeDetectorRef that needs a references to
// the component view. Therefore, we create the component view first // the component view. Therefore, we create the component view first
// and set the ProviderData in ViewData, and then instantiate the provider. // and set the ProviderData in ViewData, and then instantiate the provider.
const componentView = createView( const compViewDef = resolveViewDefinition(nodeDef.provider.component);
view.root, view, nodeDef, resolveViewDefinition(nodeDef.provider.component)); const compRenderType = nodeDef.provider.componentRenderType;
let compRenderer: RendererV2;
if (!compRenderType) {
compRenderer = view.root.renderer;
} else {
const hostEl = asElementData(view, nodeDef.parent.index).renderElement;
compRenderer = view.root.rendererFactory.createRenderer(hostEl, compRenderType);
}
const componentView = createView(view.root, compRenderer, view, nodeDef, compViewDef);
const providerData = <ProviderData>{componentView, instance: undefined}; const providerData = <ProviderData>{componentView, instance: undefined};
nodes[i] = providerData as any; nodes[i] = providerData as any;
const instance = providerData.instance = createDirectiveInstance(view, nodeDef); const instance = providerData.instance = createDirectiveInstance(view, nodeDef);
@ -473,9 +483,27 @@ export function destroyView(view: ViewData) {
view.disposables[i](); view.disposables[i]();
} }
} }
if (view.renderer.destroyNode) {
destroyViewNodes(view);
}
if (view.parentNodeDef && view.parentNodeDef.flags & NodeFlags.HasComponent) {
view.renderer.destroy();
}
view.state |= ViewState.Destroyed; view.state |= ViewState.Destroyed;
} }
function destroyViewNodes(view: ViewData) {
const len = view.def.nodes.length;
for (let i = 0; i < len; i++) {
const def = view.def.nodes[i];
if (def.type === NodeType.Element) {
view.renderer.destroyNode(asElementData(view, i).renderElement);
} else if (def.type === NodeType.Text) {
view.renderer.destroyNode(asTextData(view, i).renderText);
}
}
}
enum ViewAction { enum ViewAction {
CreateViewNodes, CreateViewNodes,
CheckNoChanges, CheckNoChanges,

View File

@ -77,15 +77,15 @@ export function moveEmbeddedView(
function renderAttachEmbeddedView(elementData: ElementData, prevView: ViewData, view: ViewData) { function renderAttachEmbeddedView(elementData: ElementData, prevView: ViewData, view: ViewData) {
const prevRenderNode = const prevRenderNode =
prevView ? renderNode(prevView, prevView.def.lastRootNode) : elementData.renderElement; prevView ? renderNode(prevView, prevView.def.lastRootNode) : elementData.renderElement;
const parentNode = view.root.renderer.parentNode(prevRenderNode); const parentNode = view.renderer.parentNode(prevRenderNode);
const nextSibling = view.root.renderer.nextSibling(prevRenderNode); const nextSibling = view.renderer.nextSibling(prevRenderNode);
// Note: We can't check if `nextSibling` is present, as on WebWorkers it will always be! // Note: We can't check if `nextSibling` is present, as on WebWorkers it will always be!
// However, browsers automatically do `appendChild` when there is no `nextSibling`. // However, browsers automatically do `appendChild` when there is no `nextSibling`.
visitRootRenderNodes(view, RenderNodeAction.InsertBefore, parentNode, nextSibling, undefined); visitRootRenderNodes(view, RenderNodeAction.InsertBefore, parentNode, nextSibling, undefined);
} }
function renderDetachEmbeddedView(elementData: ElementData, view: ViewData) { function renderDetachEmbeddedView(elementData: ElementData, view: ViewData) {
const parentNode = view.root.renderer.parentNode(elementData.renderElement); const parentNode = view.renderer.parentNode(elementData.renderElement);
visitRootRenderNodes(view, RenderNodeAction.RemoveChild, parentNode, null, undefined); visitRootRenderNodes(view, RenderNodeAction.RemoveChild, parentNode, null, undefined);
} }

View File

@ -9,8 +9,8 @@
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config'; import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry'; import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
import {TEST_COMPILER_PROVIDERS} from '@angular/compiler/testing/test_bindings'; import {TEST_COMPILER_PROVIDERS} from '@angular/compiler/testing/test_bindings';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, DoCheck, Inject, Injectable, Input, OnChanges, OnDestroy, OnInit, Output, Pipe, PipeTransform, RENDERER_V2_DIRECT, RenderComponentType, Renderer, RendererV2, RootRenderer, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, WrappedValue} from '@angular/core'; import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, DoCheck, Inject, Injectable, Input, OnChanges, OnDestroy, OnInit, Output, Pipe, PipeTransform, RenderComponentType, Renderer, RendererFactoryV2, RootRenderer, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, WrappedValue} from '@angular/core';
import {DebugDomRenderer, DebugDomRendererV2} from '@angular/core/src/debug/debug_renderer'; import {DebugDomRenderer} from '@angular/core/src/debug/debug_renderer';
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing'; import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
import {By} from '@angular/platform-browser/src/dom/debug/by'; import {By} from '@angular/platform-browser/src/dom/debug/by';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -57,6 +57,7 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
renderLog = TestBed.get(RenderLog); renderLog = TestBed.get(RenderLog);
directiveLog = TestBed.get(DirectiveLog); directiveLog = TestBed.get(DirectiveLog);
elSchema.existingProperties['someProp'] = true; elSchema.existingProperties['someProp'] = true;
patchLoggingRendererV2(TestBed.get(RendererFactoryV2), renderLog);
} }
function queryDirs(el: DebugElement, dirType: Type<any>): any { function queryDirs(el: DebugElement, dirType: Type<any>): any {
@ -123,11 +124,6 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
RenderLog, RenderLog,
DirectiveLog, DirectiveLog,
{provide: RootRenderer, useClass: LoggingRootRenderer}, {provide: RootRenderer, useClass: LoggingRootRenderer},
{
provide: RendererV2,
useFactory: (r: RendererV2, log: RenderLog) => new LoggingRendererV2(r, log),
deps: [[new Inject(RENDERER_V2_DIRECT)], [RenderLog]],
},
], ],
}); });
}); });
@ -1244,28 +1240,26 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
expect(renderLog.loggedValues).toEqual(['Tom']); expect(renderLog.loggedValues).toEqual(['Tom']);
}); });
// TODO(tbosch): ViewQueries don't work yet with the view engine... it('should recurse into nested view containers even if there are no bindings in the component view',
viewEngine || () => {
it('should recurse into nested view containers even if there are no bindings in the component view', @Component({template: '<template #vc>{{name}}</template>'})
() => { class Comp {
@Component({template: '<template #vc>{{name}}</template>'}) name = 'Tom';
class Comp { @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;
name = 'Tom'; @ViewChild(TemplateRef) template: TemplateRef<any>;
@ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef; }
@ViewChild(TemplateRef) template: TemplateRef<any>;
}
TestBed.configureTestingModule({declarations: [Comp]}); TestBed.configureTestingModule({declarations: [Comp]});
initHelpers(); initHelpers();
const ctx = TestBed.createComponent(Comp); const ctx = TestBed.createComponent(Comp);
ctx.detectChanges(); ctx.detectChanges();
expect(renderLog.loggedValues).toEqual([]); expect(renderLog.loggedValues).toEqual([]);
ctx.componentInstance.vc.createEmbeddedView(ctx.componentInstance.template); ctx.componentInstance.vc.createEmbeddedView(ctx.componentInstance.template);
ctx.detectChanges(); ctx.detectChanges();
expect(renderLog.loggedValues).toEqual(['Tom']); expect(renderLog.loggedValues).toEqual(['Tom']);
}); });
}); });
}); });
} }
@ -1315,18 +1309,32 @@ class DirectiveLogEntry {
constructor(public directiveName: string, public method: string) {} constructor(public directiveName: string, public method: string) {}
} }
class LoggingRendererV2 extends DebugDomRendererV2 { function patchLoggingRendererV2(rendererFactory: RendererFactoryV2, log: RenderLog) {
constructor(private delegate: RendererV2, private log: RenderLog) { super(delegate); } if ((<any>rendererFactory).__patchedForLogging) {
return;
setProperty(el: any, name: string, value: any): void {
this.log.setElementProperty(el, name, value);
super.setProperty(el, name, value);
}
setText(node: any, value: string): void {
this.log.setText(node, value);
super.setText(node, value);
} }
(<any>rendererFactory).__patchedForLogging = true;
const origCreateRenderer = rendererFactory.createRenderer;
rendererFactory.createRenderer = function() {
const renderer = origCreateRenderer.apply(this, arguments);
if ((<any>renderer).__patchedForLogging) {
return renderer;
}
(<any>renderer).__patchedForLogging = true;
const origSetProperty = renderer.setProperty;
const origSetValue = renderer.setValue;
renderer.setProperty = function(el: any, name: string, value: any): void {
log.setElementProperty(el, name, value);
origSetProperty.call(this, el, name, value);
};
renderer.setValue = function(node: any, value: string): void {
if (getDOM().isTextNode(node)) {
log.setText(node, value);
}
origSetValue.call(this, node, value);
};
return renderer;
};
} }
@Injectable() @Injectable()

View File

@ -1515,7 +1515,7 @@ function declareTests({useJit, viewEngine}: {useJit: boolean, viewEngine: boolea
const fixture = TestBed.createComponent(ParentCmp); const fixture = TestBed.createComponent(ParentCmp);
fixture.detectChanges(); fixture.detectChanges();
expect(getDOM().getInnerHTML(fixture.nativeElement)).toContain('ng-reflect-test$="hello"'); expect(getDOM().getInnerHTML(fixture.nativeElement)).toContain('ng-reflect-test_="hello"');
}); });
it('should reflect property values on template comments', () => { it('should reflect property values on template comments', () => {

View File

@ -378,7 +378,7 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
expect(main.nativeElement).toHaveText('TREE(0:TREE2(1:TREE(2:)))'); expect(main.nativeElement).toHaveText('TREE(0:TREE2(1:TREE(2:)))');
}); });
if (!viewEngine && getDOM().supportsNativeShadowDOM()) { if (getDOM().supportsNativeShadowDOM()) {
it('should support native content projection and isolate styles per component', () => { it('should support native content projection and isolate styles per component', () => {
TestBed.configureTestingModule({declarations: [SimpleNative1, SimpleNative2]}); TestBed.configureTestingModule({declarations: [SimpleNative1, SimpleNative2]});
TestBed.overrideComponent(MainComp, { TestBed.overrideComponent(MainComp, {
@ -396,7 +396,7 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
}); });
} }
if (!viewEngine && getDOM().supportsDOMEvents()) { if (getDOM().supportsDOMEvents()) {
it('should support non emulated styles', () => { it('should support non emulated styles', () => {
TestBed.configureTestingModule({declarations: [OtherComp]}); TestBed.configureTestingModule({declarations: [OtherComp]});
TestBed.overrideComponent(MainComp, { TestBed.overrideComponent(MainComp, {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectorRef, DoCheck, ElementRef, EventEmitter, Injector, OnChanges, OnDestroy, OnInit, RenderComponentType, Renderer, RootRenderer, Sanitizer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation, WrappedValue, getDebugNode} from '@angular/core'; import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectorRef, DoCheck, ElementRef, EventEmitter, Injector, OnChanges, OnDestroy, OnInit, RenderComponentType, Renderer, RendererV2, RootRenderer, Sanitizer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation, WrappedValue, getDebugNode} from '@angular/core';
import {getDebugContext} from '@angular/core/src/errors'; import {getDebugContext} from '@angular/core/src/errors';
import {ArgumentType, BindingType, DebugContext, DepFlags, NodeDef, NodeFlags, ProviderType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, directiveDef, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index'; import {ArgumentType, BindingType, DebugContext, DepFlags, NodeDef, NodeFlags, ProviderType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, directiveDef, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
import {TestBed, inject, withModule} from '@angular/core/testing'; import {TestBed, inject, withModule} from '@angular/core/testing';
@ -19,9 +19,7 @@ export function main() {
function compViewDef( function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn, nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef( return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
viewFlags, nodes, updateDirectives, updateRenderer, handleEvent, 'someCompId',
ViewEncapsulation.None, []);
} }
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory { function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory {
@ -292,11 +290,25 @@ export function main() {
it('should inject RendererV1', () => { it('should inject RendererV1', () => {
createAndGetRootNodes(compViewDef([ createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'span'), elementDef(NodeFlags.None, null, null, 1, 'span'),
directiveDef(NodeFlags.None, null, 0, SomeService, [Renderer]) directiveDef(
NodeFlags.None, null, 0, SomeService, [Renderer], null, null,
() => compViewDef([anchorDef(NodeFlags.None, null, null, 0)]))
])); ]));
expect(instance.dep.createElement).toBeTruthy(); expect(instance.dep.createElement).toBeTruthy();
}); });
it('should inject RendererV2', () => {
createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'span'),
directiveDef(
NodeFlags.None, null, 0, SomeService, [RendererV2], null, null,
() => compViewDef([anchorDef(NodeFlags.None, null, null, 0)]))
]));
expect(instance.dep.createElement).toBeTruthy();
});
}); });
}); });

View File

@ -7,7 +7,7 @@
*/ */
import {CommonModule, PlatformLocation} from '@angular/common'; import {CommonModule, PlatformLocation} from '@angular/common';
import {ApplicationModule, ErrorHandler, NgModule, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, RENDERER_V2_DIRECT, RendererV2, RootRenderer, Sanitizer, SkipSelf, Testability, createPlatformFactory, platformCore} from '@angular/core'; import {ApplicationModule, ErrorHandler, NgModule, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, RendererFactoryV2, RootRenderer, Sanitizer, SkipSelf, Testability, createPlatformFactory, platformCore} from '@angular/core';
import {AnimationDriver} from '../src/dom/animation_driver'; import {AnimationDriver} from '../src/dom/animation_driver';
import {WebAnimationsDriver} from '../src/dom/web_animations_driver'; import {WebAnimationsDriver} from '../src/dom/web_animations_driver';
@ -19,7 +19,7 @@ import {BrowserGetTestability} from './browser/testability';
import {Title} from './browser/title'; import {Title} from './browser/title';
import {ELEMENT_PROBE_PROVIDERS} from './dom/debug/ng_probe'; import {ELEMENT_PROBE_PROVIDERS} from './dom/debug/ng_probe';
import {getDOM} from './dom/dom_adapter'; import {getDOM} from './dom/dom_adapter';
import {DomRendererV2, DomRootRenderer, DomRootRenderer_} from './dom/dom_renderer'; import {DomRendererFactoryV2, DomRootRenderer, DomRootRenderer_} from './dom/dom_renderer';
import {DOCUMENT} from './dom/dom_tokens'; import {DOCUMENT} from './dom/dom_tokens';
import {DomEventsPlugin} from './dom/events/dom_events'; import {DomEventsPlugin} from './dom/events/dom_events';
import {EVENT_MANAGER_PLUGINS, EventManager} from './dom/events/event_manager'; import {EVENT_MANAGER_PLUGINS, EventManager} from './dom/events/event_manager';
@ -86,8 +86,8 @@ export function _resolveDefaultAnimationDriver(): AnimationDriver {
{provide: HAMMER_GESTURE_CONFIG, useClass: HammerGestureConfig}, {provide: HAMMER_GESTURE_CONFIG, useClass: HammerGestureConfig},
{provide: DomRootRenderer, useClass: DomRootRenderer_}, {provide: DomRootRenderer, useClass: DomRootRenderer_},
{provide: RootRenderer, useExisting: DomRootRenderer}, {provide: RootRenderer, useExisting: DomRootRenderer},
{provide: RENDERER_V2_DIRECT, useClass: DomRendererV2}, DomRendererFactoryV2,
{provide: RendererV2, useExisting: RENDERER_V2_DIRECT}, {provide: RendererFactoryV2, useExisting: DomRendererFactoryV2},
{provide: SharedStylesHost, useExisting: DomSharedStylesHost}, {provide: SharedStylesHost, useExisting: DomSharedStylesHost},
{provide: AnimationDriver, useFactory: _resolveDefaultAnimationDriver}, {provide: AnimationDriver, useFactory: _resolveDefaultAnimationDriver},
DomSharedStylesHost, DomSharedStylesHost,

View File

@ -9,9 +9,9 @@
import * as core from '@angular/core'; import * as core from '@angular/core';
import {StringMapWrapper} from '../../facade/collection'; import {StringMapWrapper} from '../../facade/collection';
import {DebugDomRendererV2, DebugDomRootRenderer} from '../../private_import_core'; import {DebugDomRootRenderer} from '../../private_import_core';
import {getDOM} from '../dom_adapter'; import {getDOM} from '../dom_adapter';
import {DomRootRenderer} from '../dom_renderer'; import {DomRendererFactoryV2, DomRootRenderer} from '../dom_renderer';
const CORE_TOKENS = { const CORE_TOKENS = {
'ApplicationRef': core.ApplicationRef, 'ApplicationRef': core.ApplicationRef,
@ -58,10 +58,6 @@ function _ngProbeTokensToMap(tokens: NgProbeToken[]): {[name: string]: any} {
return tokens.reduce((prev: any, t: any) => (prev[t.name] = t.token, prev), {}); return tokens.reduce((prev: any, t: any) => (prev[t.name] = t.token, prev), {});
} }
export function _createDebugRendererV2(renderer: core.RendererV2): core.RendererV2 {
return core.isDevMode() ? new DebugDomRendererV2(renderer) : renderer;
}
/** /**
* Providers which support debugging Angular applications (e.g. via `ng.probe`). * Providers which support debugging Angular applications (e.g. via `ng.probe`).
*/ */
@ -75,9 +71,4 @@ export const ELEMENT_PROBE_PROVIDERS: core.Provider[] = [
[core.NgProbeToken, new core.Optional()], [core.NgProbeToken, new core.Optional()],
], ],
}, },
{
provide: core.RendererV2,
useFactory: _createDebugRendererV2,
deps: [core.RENDERER_V2_DIRECT],
}
]; ];

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {APP_ID, Inject, Injectable, RenderComponentType, Renderer, RendererV2, RootRenderer, ViewEncapsulation} from '@angular/core'; import {APP_ID, ComponentRenderTypeV2, Inject, Injectable, RenderComponentType, Renderer, RendererFactoryV2, RendererV2, RootRenderer, ViewEncapsulation} from '@angular/core';
import {isPresent, stringify} from '../facade/lang'; import {isPresent, stringify} from '../facade/lang';
import {AnimationKeyframe, AnimationPlayer, AnimationStyles, DirectRenderer, NoOpAnimationPlayer, RenderDebugInfo} from '../private_import_core'; import {AnimationKeyframe, AnimationPlayer, AnimationStyles, DirectRenderer, NoOpAnimationPlayer, RenderDebugInfo} from '../private_import_core';
@ -229,13 +229,8 @@ export class DomRenderer implements Renderer {
TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(parsedBindings, null, 2)); TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(parsedBindings, null, 2));
} else { } else {
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
if (propertyName[propertyName.length - 1] === '$') { propertyName = propertyName.replace(/\$/g, '_');
const attrNode: Attr = createAttributeNode(propertyName).cloneNode(true) as Attr; this.setElementAttribute(renderElement, propertyName, propertyValue);
attrNode.value = propertyValue;
renderElement.setAttributeNode(attrNode);
} else {
this.setElementAttribute(renderElement, propertyName, propertyValue);
}
} }
} }
@ -366,10 +361,51 @@ function createAttributeNode(name: string): Attr {
} }
@Injectable() @Injectable()
export class DomRendererV2 implements RendererV2 { export class DomRendererFactoryV2 implements RendererFactoryV2 {
constructor(private eventManager: EventManager){}; private rendererByCompId = new Map<string, RendererV2>();
private defaultRenderer: RendererV2;
createElement(name: string, namespace?: string, debugInfo?: any): any { constructor(private eventManager: EventManager, private sharedStylesHost: DomSharedStylesHost) {
this.defaultRenderer = new DefaultDomRendererV2(eventManager);
};
createRenderer(element: any, type: ComponentRenderTypeV2): RendererV2 {
if (!element || !type) {
return this.defaultRenderer;
}
switch (type.encapsulation) {
case ViewEncapsulation.Emulated: {
let renderer = this.rendererByCompId.get(type.id);
if (!renderer) {
renderer = new EmulatedEncapsulationDomRendererV2(
this.eventManager, this.sharedStylesHost, type);
this.rendererByCompId.set(type.id, renderer);
}
(<EmulatedEncapsulationDomRendererV2>renderer).applyToHost(element);
return renderer;
}
case ViewEncapsulation.Native:
return new ShadowDomRenderer(this.eventManager, this.sharedStylesHost, element, type);
default: {
if (!this.rendererByCompId.has(type.id)) {
const styles = flattenStyles(type.id, type.styles, []);
this.sharedStylesHost.addStyles(styles);
this.rendererByCompId.set(type.id, this.defaultRenderer);
}
return this.defaultRenderer;
}
}
}
}
class DefaultDomRendererV2 implements RendererV2 {
constructor(private eventManager: EventManager) {}
destroy(): void {}
destroyNode: null;
createElement(name: string, namespace?: string): any {
if (namespace) { if (namespace) {
return document.createElementNS(NAMESPACE_URIS[namespace], name); return document.createElementNS(NAMESPACE_URIS[namespace], name);
} }
@ -377,9 +413,9 @@ export class DomRendererV2 implements RendererV2 {
return document.createElement(name); return document.createElement(name);
} }
createComment(value: string, debugInfo?: any): any { return document.createComment(value); } createComment(value: string): any { return document.createComment(value); }
createText(value: string, debugInfo?: any): any { return document.createTextNode(value); } createText(value: string): any { return document.createTextNode(value); }
appendChild(parent: any, newChild: any): void { parent.appendChild(newChild); } appendChild(parent: any, newChild: any): void { parent.appendChild(newChild); }
@ -395,7 +431,7 @@ export class DomRendererV2 implements RendererV2 {
} }
} }
selectRootElement(selectorOrNode: string|any, debugInfo?: any): any { selectRootElement(selectorOrNode: string|any): any {
let el: any = typeof selectorOrNode === 'string' ? document.querySelector(selectorOrNode) : let el: any = typeof selectorOrNode === 'string' ? document.querySelector(selectorOrNode) :
selectorOrNode; selectorOrNode;
el.textContent = ''; el.textContent = '';
@ -422,43 +458,6 @@ export class DomRendererV2 implements RendererV2 {
} }
} }
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {
if (el.nodeType === Node.COMMENT_NODE) {
const m = el.nodeValue.replace(/\n/g, '').match(TEMPLATE_BINDINGS_EXP);
const obj = m === null ? {} : JSON.parse(m[1]);
obj[propertyName] = propertyValue;
el.nodeValue = TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(obj, null, 2));
} else {
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
if (propertyName[propertyName.length - 1] === '$') {
const attrNode: Attr = createAttributeNode(propertyName).cloneNode(true) as Attr;
attrNode.value = propertyValue;
el.setAttributeNode(attrNode);
} else {
this.setAttribute(el, propertyName, propertyValue);
}
}
}
removeBindingDebugInfo(el: any, propertyName: string): void {
if (el.nodeType === Node.COMMENT_NODE) {
const m = el.nodeValue.replace(/\n/g, '').match(TEMPLATE_BINDINGS_EXP);
const obj = m === null ? {} : JSON.parse(m[1]);
delete obj[propertyName];
el.nodeValue = TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(obj, null, 2));
} else {
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
if (propertyName[propertyName.length - 1] === '$') {
const attrNode: Attr = createAttributeNode(propertyName).cloneNode(true) as Attr;
attrNode.value = '';
el.setAttributeNode(attrNode);
} else {
this.removeAttribute(el, propertyName);
}
}
}
addClass(el: any, name: string): void { el.classList.add(name); } addClass(el: any, name: string): void { el.classList.add(name); }
removeClass(el: any, name: string): void { el.classList.remove(name); } removeClass(el: any, name: string): void { el.classList.remove(name); }
@ -476,7 +475,7 @@ export class DomRendererV2 implements RendererV2 {
setProperty(el: any, name: string, value: any): void { el[name] = value; } setProperty(el: any, name: string, value: any): void { el[name] = value; }
setText(node: any, value: string): void { node.nodeValue = value; } setValue(node: any, value: string): void { node.nodeValue = value; }
listen(target: 'window'|'document'|'body'|any, event: string, callback: (event: any) => boolean): listen(target: 'window'|'document'|'body'|any, event: string, callback: (event: any) => boolean):
() => void { () => void {
@ -488,3 +487,62 @@ export class DomRendererV2 implements RendererV2 {
target, event, decoratePreventDefault(callback)) as() => void; target, event, decoratePreventDefault(callback)) as() => void;
} }
} }
class EmulatedEncapsulationDomRendererV2 extends DefaultDomRendererV2 {
private contentAttr: string;
private hostAttr: string;
constructor(
eventManager: EventManager, sharedStylesHost: DomSharedStylesHost,
private component: ComponentRenderTypeV2) {
super(eventManager);
const styles = flattenStyles(component.id, component.styles, []);
sharedStylesHost.addStyles(styles);
this.contentAttr = shimContentAttribute(component.id);
this.hostAttr = shimHostAttribute(component.id);
}
applyToHost(element: any) { super.setAttribute(element, this.hostAttr, ''); }
createElement(parent: any, name: string): Element {
const el = super.createElement(parent, name);
super.setAttribute(el, this.contentAttr, '');
return el;
}
}
class ShadowDomRenderer extends DefaultDomRendererV2 {
private shadowRoot: any;
constructor(
eventManager: EventManager, private sharedStylesHost: DomSharedStylesHost,
private hostEl: any, private component: ComponentRenderTypeV2) {
super(eventManager);
this.shadowRoot = (hostEl as any).createShadowRoot();
this.sharedStylesHost.addHost(this.shadowRoot);
const styles = flattenStyles(component.id, component.styles, []);
for (let i = 0; i < styles.length; i++) {
const styleEl = document.createElement('style');
styleEl.textContent = styles[i];
this.shadowRoot.appendChild(styleEl);
}
}
private nodeOrShadowRoot(node: any): any { return node === this.hostEl ? this.shadowRoot : node; }
destroy() { this.sharedStylesHost.removeHost(this.shadowRoot); }
appendChild(parent: any, newChild: any): void {
return super.appendChild(this.nodeOrShadowRoot(parent), newChild);
}
insertBefore(parent: any, newChild: any, refChild: any): void {
return super.insertBefore(this.nodeOrShadowRoot(parent), newChild, refChild);
}
removeChild(parent: any, oldChild: any): void {
return super.removeChild(this.nodeOrShadowRoot(parent), oldChild);
}
parentNode(node: any): any {
return this.nodeOrShadowRoot(super.parentNode(this.nodeOrShadowRoot(node)));
}
}

View File

@ -16,8 +16,6 @@ export const ReflectionCapabilities: typeof r.ReflectionCapabilities = r.Reflect
export type DebugDomRootRenderer = typeof r._DebugDomRootRenderer; export type DebugDomRootRenderer = typeof r._DebugDomRootRenderer;
export const DebugDomRootRenderer: typeof r.DebugDomRootRenderer = r.DebugDomRootRenderer; export const DebugDomRootRenderer: typeof r.DebugDomRootRenderer = r.DebugDomRootRenderer;
export type DebugDomRendererV2 = typeof r._DebugDomRendererV2;
export const DebugDomRendererV2: typeof r.DebugDomRendererV2 = r.DebugDomRendererV2;
export const reflector: typeof r.reflector = r.reflector; export const reflector: typeof r.reflector = r.reflector;

View File

@ -21,8 +21,6 @@ export type RenderDebugInfo = typeof r._RenderDebugInfo;
export const RenderDebugInfo: typeof r.RenderDebugInfo = r.RenderDebugInfo; export const RenderDebugInfo: typeof r.RenderDebugInfo = r.RenderDebugInfo;
export type DebugDomRootRenderer = typeof r._DebugDomRootRenderer; export type DebugDomRootRenderer = typeof r._DebugDomRootRenderer;
export const DebugDomRootRenderer: typeof r.DebugDomRootRenderer = r.DebugDomRootRenderer; export const DebugDomRootRenderer: typeof r.DebugDomRootRenderer = r.DebugDomRootRenderer;
export type DebugDomRendererV2 = typeof r._DebugDomRendererV2;
export const DebugDomRendererV2: typeof r.DebugDomRendererV2 = r.DebugDomRendererV2;
export type ALLOW_MULTIPLE_PLATFORMS = typeof r.ALLOW_MULTIPLE_PLATFORMS; export type ALLOW_MULTIPLE_PLATFORMS = typeof r.ALLOW_MULTIPLE_PLATFORMS;
export const ALLOW_MULTIPLE_PLATFORMS: typeof r.ALLOW_MULTIPLE_PLATFORMS = export const ALLOW_MULTIPLE_PLATFORMS: typeof r.ALLOW_MULTIPLE_PLATFORMS =
r.ALLOW_MULTIPLE_PLATFORMS; r.ALLOW_MULTIPLE_PLATFORMS;

View File

@ -8,7 +8,7 @@
import {PlatformLocation} from '@angular/common'; import {PlatformLocation} from '@angular/common';
import {platformCoreDynamic} from '@angular/compiler'; import {platformCoreDynamic} from '@angular/compiler';
import {APP_BOOTSTRAP_LISTENER, Injectable, InjectionToken, Injector, NgModule, PLATFORM_INITIALIZER, PlatformRef, Provider, RENDERER_V2_DIRECT, RendererV2, RootRenderer, createPlatformFactory, isDevMode, platformCore} from '@angular/core'; import {APP_BOOTSTRAP_LISTENER, Injectable, InjectionToken, Injector, NgModule, PLATFORM_INITIALIZER, PlatformRef, Provider, RendererFactoryV2, RootRenderer, createPlatformFactory, isDevMode, platformCore} from '@angular/core';
import {HttpModule} from '@angular/http'; import {HttpModule} from '@angular/http';
import {BrowserModule, DOCUMENT} from '@angular/platform-browser'; import {BrowserModule, DOCUMENT} from '@angular/platform-browser';
@ -16,9 +16,9 @@ import {SERVER_HTTP_PROVIDERS} from './http';
import {ServerPlatformLocation} from './location'; import {ServerPlatformLocation} from './location';
import {Parse5DomAdapter, parseDocument} from './parse5_adapter'; import {Parse5DomAdapter, parseDocument} from './parse5_adapter';
import {PlatformState} from './platform_state'; import {PlatformState} from './platform_state';
import {ALLOW_MULTIPLE_PLATFORMS, DebugDomRendererV2, DebugDomRootRenderer} from './private_import_core'; import {ALLOW_MULTIPLE_PLATFORMS, DebugDomRootRenderer} from './private_import_core';
import {SharedStylesHost, getDOM} from './private_import_platform-browser'; import {SharedStylesHost, getDOM} from './private_import_platform-browser';
import {ServerRendererV2, ServerRootRenderer} from './server_renderer'; import {ServerRendererFactoryV2, ServerRootRenderer} from './server_renderer';
import {ServerStylesHost} from './styles_host'; import {ServerStylesHost} from './styles_host';
import {INITIAL_CONFIG, PlatformConfig} from './tokens'; import {INITIAL_CONFIG, PlatformConfig} from './tokens';
@ -42,10 +42,6 @@ export function _createConditionalRootRenderer(rootRenderer: any) {
return isDevMode() ? new DebugDomRootRenderer(rootRenderer) : rootRenderer; return isDevMode() ? new DebugDomRootRenderer(rootRenderer) : rootRenderer;
} }
export function _createDebugRendererV2(renderer: RendererV2): RendererV2 {
return isDevMode() ? new DebugDomRendererV2(renderer) : renderer;
}
export function _addStylesToRootComponentFactory(stylesHost: ServerStylesHost) { export function _addStylesToRootComponentFactory(stylesHost: ServerStylesHost) {
const initializer = () => stylesHost.rootComponentIsReady(); const initializer = () => stylesHost.rootComponentIsReady();
return initializer; return initializer;
@ -53,9 +49,9 @@ export function _addStylesToRootComponentFactory(stylesHost: ServerStylesHost) {
export const SERVER_RENDER_PROVIDERS: Provider[] = [ export const SERVER_RENDER_PROVIDERS: Provider[] = [
ServerRootRenderer, ServerRootRenderer,
{provide: RENDERER_V2_DIRECT, useClass: ServerRendererV2},
{provide: RendererV2, useFactory: _createDebugRendererV2, deps: [RENDERER_V2_DIRECT]},
{provide: RootRenderer, useFactory: _createConditionalRootRenderer, deps: [ServerRootRenderer]}, {provide: RootRenderer, useFactory: _createConditionalRootRenderer, deps: [ServerRootRenderer]},
ServerRendererFactoryV2,
{provide: RendererFactoryV2, useExisting: ServerRendererFactoryV2},
ServerStylesHost, ServerStylesHost,
{provide: SharedStylesHost, useExisting: ServerStylesHost}, {provide: SharedStylesHost, useExisting: ServerStylesHost},
{ {

View File

@ -7,7 +7,7 @@
*/ */
import {DomElementSchemaRegistry} from '@angular/compiler'; import {DomElementSchemaRegistry} from '@angular/compiler';
import {APP_ID, Inject, Injectable, NgZone, RenderComponentType, Renderer, RendererV2, RootRenderer, ViewEncapsulation} from '@angular/core'; import {APP_ID, ComponentRenderTypeV2, Inject, Injectable, NgZone, RenderComponentType, Renderer, RendererFactoryV2, RendererV2, RootRenderer, ViewEncapsulation} from '@angular/core';
import {AnimationDriver, DOCUMENT} from '@angular/platform-browser'; import {AnimationDriver, DOCUMENT} from '@angular/platform-browser';
import {isBlank, isPresent, stringify} from './facade/lang'; import {isBlank, isPresent, stringify} from './facade/lang';
@ -204,6 +204,7 @@ export class ServerRenderer implements Renderer {
renderElement, renderElement,
TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(parsedBindings, null, 2))); TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(parsedBindings, null, 2)));
} else { } else {
propertyName = propertyName.replace(/\$/g, '_');
this.setElementAttribute(renderElement, propertyName, propertyValue); this.setElementAttribute(renderElement, propertyName, propertyValue);
} }
} }
@ -262,8 +263,51 @@ function appendNodes(parent: any, nodes: any) {
} }
@Injectable() @Injectable()
export class ServerRendererV2 implements RendererV2 { export class ServerRendererFactoryV2 implements RendererFactoryV2 {
constructor(private ngZone: NgZone, @Inject(DOCUMENT) private document: any) {} private rendererByCompId = new Map<string, RendererV2>();
private defaultRenderer: RendererV2;
constructor(
private ngZone: NgZone, @Inject(DOCUMENT) private document: any,
private sharedStylesHost: SharedStylesHost) {
this.defaultRenderer = new DefaultServerRendererV2(document, ngZone);
};
createRenderer(element: any, type: ComponentRenderTypeV2): RendererV2 {
if (!element || !type) {
return this.defaultRenderer;
}
switch (type.encapsulation) {
case ViewEncapsulation.Emulated: {
let renderer = this.rendererByCompId.get(type.id);
if (!renderer) {
renderer = new EmulatedEncapsulationServerRendererV2(
this.document, this.ngZone, this.sharedStylesHost, type);
this.rendererByCompId.set(type.id, renderer);
}
(<EmulatedEncapsulationServerRendererV2>renderer).applyToHost(element);
return renderer;
}
case ViewEncapsulation.Native:
throw new Error('Native encapsulation is not supported on the server!');
default: {
if (!this.rendererByCompId.has(type.id)) {
const styles = flattenStyles(type.id, type.styles, []);
this.sharedStylesHost.addStyles(styles);
this.rendererByCompId.set(type.id, this.defaultRenderer);
}
return this.defaultRenderer;
}
}
}
}
class DefaultServerRendererV2 implements RendererV2 {
constructor(private document: any, private ngZone: NgZone) {}
destroy(): void {}
destroyNode: null;
createElement(name: string, namespace?: string, debugInfo?: any): any { createElement(name: string, namespace?: string, debugInfo?: any): any {
if (namespace) { if (namespace) {
@ -325,28 +369,6 @@ export class ServerRendererV2 implements RendererV2 {
} }
} }
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {
if (getDOM().isCommentNode(el)) {
const m = getDOM().getText(el).replace(/\n/g, '').match(TEMPLATE_BINDINGS_EXP);
const obj = m === null ? {} : JSON.parse(m[1]);
obj[propertyName] = propertyValue;
getDOM().setText(el, TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(obj, null, 2)));
} else {
this.setAttribute(el, propertyName, propertyValue);
}
}
removeBindingDebugInfo(el: any, propertyName: string): void {
if (getDOM().isCommentNode(el)) {
const m = getDOM().getText(el).replace(/\n/g, '').match(TEMPLATE_BINDINGS_EXP);
const obj = m === null ? {} : JSON.parse(m[1]);
delete obj[propertyName];
getDOM().setText(el, TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(obj, null, 2)));
} else {
this.removeAttribute(el, propertyName);
}
}
addClass(el: any, name: string): void { getDOM().addClass(el, name); } addClass(el: any, name: string): void { getDOM().addClass(el, name); }
removeClass(el: any, name: string): void { getDOM().removeClass(el, name); } removeClass(el: any, name: string): void { getDOM().removeClass(el, name); }
@ -362,7 +384,7 @@ export class ServerRendererV2 implements RendererV2 {
setProperty(el: any, name: string, value: any): void { getDOM().setProperty(el, name, value); } setProperty(el: any, name: string, value: any): void { getDOM().setProperty(el, name, value); }
setText(node: any, value: string): void { getDOM().setText(node, value); } setValue(node: any, value: string): void { getDOM().setText(node, value); }
listen( listen(
target: 'document'|'window'|'body'|any, eventName: string, target: 'document'|'window'|'body'|any, eventName: string,
@ -375,3 +397,27 @@ export class ServerRendererV2 implements RendererV2 {
return this.ngZone.runOutsideAngular(() => getDOM().onAndCancel(el, eventName, outsideHandler)); return this.ngZone.runOutsideAngular(() => getDOM().onAndCancel(el, eventName, outsideHandler));
} }
} }
class EmulatedEncapsulationServerRendererV2 extends DefaultServerRendererV2 {
private contentAttr: string;
private hostAttr: string;
constructor(
document: any, ngZone: NgZone, sharedStylesHost: SharedStylesHost,
private component: ComponentRenderTypeV2) {
super(document, ngZone);
const styles = flattenStyles(component.id, component.styles, []);
sharedStylesHost.addStyles(styles);
this.contentAttr = shimContentAttribute(component.id);
this.hostAttr = shimHostAttribute(component.id);
}
applyToHost(element: any) { super.setAttribute(element, this.hostAttr, ''); }
createElement(parent: any, name: string): Element {
const el = super.createElement(parent, name);
super.setAttribute(el, this.contentAttr, '');
return el;
}
}

View File

@ -7,9 +7,9 @@
*/ */
import {NgIf} from '@angular/common'; import {NgIf} from '@angular/common';
import {ComponentFactory, ComponentRef, Injector, RendererV2, RootRenderer, Sanitizer, TemplateRef, ViewContainerRef} from '@angular/core'; import {ComponentFactory, ComponentRef, Injector, RendererFactoryV2, RootRenderer, Sanitizer, TemplateRef, ViewContainerRef} from '@angular/core';
import {ArgumentType, BindingType, NodeFlags, ViewDefinition, ViewFlags, anchorDef, createComponentFactory, directiveDef, elementDef, initServicesIfNeeded, textDef, viewDef} from '@angular/core/src/view/index'; import {ArgumentType, BindingType, NodeFlags, ViewDefinition, ViewFlags, anchorDef, createComponentFactory, directiveDef, elementDef, initServicesIfNeeded, textDef, viewDef} from '@angular/core/src/view/index';
import {DomRendererV2} from '@angular/platform-browser/src/dom/dom_renderer'; import {DomRendererFactoryV2} from '@angular/platform-browser/src/dom/dom_renderer';
import {DomSanitizerImpl, SafeStyle} from '@angular/platform-browser/src/security/dom_sanitization_service'; import {DomSanitizerImpl, SafeStyle} from '@angular/platform-browser/src/security/dom_sanitization_service';
import {TreeNode, emptyTree} from '../util'; import {TreeNode, emptyTree} from '../util';
@ -89,14 +89,14 @@ function TreeComponent_0(): ViewDefinition {
export class AppModule implements Injector { export class AppModule implements Injector {
private sanitizer: DomSanitizerImpl; private sanitizer: DomSanitizerImpl;
private componentFactory: ComponentFactory<TreeComponent>; private componentFactory: ComponentFactory<TreeComponent>;
private rendererV2: RendererV2; private rendererV2: RendererFactoryV2;
componentRef: ComponentRef<TreeComponent>; componentRef: ComponentRef<TreeComponent>;
constructor() { constructor() {
initServicesIfNeeded(); initServicesIfNeeded();
this.sanitizer = new DomSanitizerImpl(document); this.sanitizer = new DomSanitizerImpl(document);
this.rendererV2 = new DomRendererV2(null); this.rendererV2 = new DomRendererFactoryV2(null, null);
trustedEmptyColor = this.sanitizer.bypassSecurityTrustStyle(''); trustedEmptyColor = this.sanitizer.bypassSecurityTrustStyle('');
trustedGreyColor = this.sanitizer.bypassSecurityTrustStyle('grey'); trustedGreyColor = this.sanitizer.bypassSecurityTrustStyle('grey');
this.componentFactory = createComponentFactory('#root', TreeComponent, TreeComponent_Host); this.componentFactory = createComponentFactory('#root', TreeComponent, TreeComponent_Host);
@ -104,7 +104,7 @@ export class AppModule implements Injector {
get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any { get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any {
switch (token) { switch (token) {
case RendererV2: case RendererFactoryV2:
return this.rendererV2; return this.rendererV2;
case Sanitizer: case Sanitizer:
return this.sanitizer; return this.sanitizer;

View File

@ -292,6 +292,16 @@ export declare abstract class ComponentRef<C> {
abstract onDestroy(callback: Function): void; abstract onDestroy(callback: Function): void;
} }
/** @experimental */
export interface ComponentRenderTypeV2 {
data: {
[kind: string]: any[];
};
encapsulation: ViewEncapsulation;
id: string;
styles: (string | any[])[];
}
/** @stable */ /** @stable */
export declare const ContentChild: ContentChildDecorator; export declare const ContentChild: ContentChildDecorator;
@ -848,30 +858,32 @@ export declare abstract class Renderer {
} }
/** @experimental */ /** @experimental */
export declare const RENDERER_V2_DIRECT: InjectionToken<RendererV2>; export declare abstract class RendererFactoryV2 {
abstract createRenderer(hostElement: any, type: ComponentRenderTypeV2): RendererV2;
}
/** @experimental */ /** @experimental */
export declare abstract class RendererV2 { export declare abstract class RendererV2 {
destroyNode: (node: any) => void | null;
abstract addClass(el: any, name: string): void; abstract addClass(el: any, name: string): void;
abstract appendChild(parent: any, newChild: any): void; abstract appendChild(parent: any, newChild: any): void;
abstract createComment(value: string, debugInfo?: RenderDebugContext): any; abstract createComment(value: string): any;
abstract createElement(name: string, namespace?: string, debugInfo?: RenderDebugContext): any; abstract createElement(name: string, namespace?: string): any;
abstract createText(value: string, debugInfo?: RenderDebugContext): any; abstract createText(value: string): any;
abstract destroy(): void;
abstract insertBefore(parent: any, newChild: any, refChild: any): void; abstract insertBefore(parent: any, newChild: any, refChild: any): void;
abstract listen(target: 'window' | 'document' | 'body' | any, eventName: string, callback: (event: any) => boolean): () => void; abstract listen(target: 'window' | 'document' | 'body' | any, eventName: string, callback: (event: any) => boolean): () => void;
abstract nextSibling(node: any): any; abstract nextSibling(node: any): any;
abstract parentNode(node: any): any; abstract parentNode(node: any): any;
abstract removeAttribute(el: any, name: string, namespace?: string): void; abstract removeAttribute(el: any, name: string, namespace?: string): void;
abstract removeBindingDebugInfo(el: any, propertyName: string): void;
abstract removeChild(parent: any, oldChild: any): void; abstract removeChild(parent: any, oldChild: any): void;
abstract removeClass(el: any, name: string): void; abstract removeClass(el: any, name: string): void;
abstract removeStyle(el: any, style: string, hasVendorPrefix: boolean): void; abstract removeStyle(el: any, style: string, hasVendorPrefix: boolean): void;
abstract selectRootElement(selectorOrNode: string | any, debugInfo?: RenderDebugContext): any; abstract selectRootElement(selectorOrNode: string | any): any;
abstract setAttribute(el: any, name: string, value: string, namespace?: string): void; abstract setAttribute(el: any, name: string, value: string, namespace?: string): void;
abstract setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void;
abstract setProperty(el: any, name: string, value: any): void; abstract setProperty(el: any, name: string, value: any): void;
abstract setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean): void; abstract setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean): void;
abstract setText(node: any, value: string): void; abstract setValue(node: any, value: string): void;
} }
/** @experimental */ /** @experimental */