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[]) {
if (_currentAction === DebugAction.detectChanges) {
const values = argStyle === ArgumentType.Dynamic ? givenValues[0] : givenValues; const values = argStyle === ArgumentType.Dynamic ? givenValues[0] : givenValues;
const nodeDef = view.def.nodes[nodeIndex]; const nodeDef = view.def.nodes[nodeIndex];
if (nodeDef.type === NodeType.Directive || nodeDef.type === NodeType.Element) {
const bindingValues: {[key: string]: string} = {};
for (let i = 0; i < nodeDef.bindings.length; i++) { for (let i = 0; i < nodeDef.bindings.length; i++) {
const binding = nodeDef.bindings[i]; const binding = nodeDef.bindings[i];
const value = values[i]; const value = values[i];
if ((binding.type === BindingType.ElementProperty || if ((binding.type === BindingType.ElementProperty ||
binding.type === BindingType.DirectiveProperty) && binding.type === BindingType.DirectiveProperty) &&
checkBinding(view, nodeDef, i, value)) { 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,8 +1240,6 @@ 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...
viewEngine ||
it('should recurse into nested view containers even if there are no bindings in the component view', it('should recurse into nested view containers even if there are no bindings in the component view',
() => { () => {
@Component({template: '<template #vc>{{name}}</template>'}) @Component({template: '<template #vc>{{name}}</template>'})
@ -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);
} }
(<any>rendererFactory).__patchedForLogging = true;
setText(node: any, value: string): void { const origCreateRenderer = rendererFactory.createRenderer;
this.log.setText(node, value); rendererFactory.createRenderer = function() {
super.setText(node, value); 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,15 +229,10 @@ 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;
attrNode.value = propertyValue;
renderElement.setAttributeNode(attrNode);
} else {
this.setElementAttribute(renderElement, propertyName, propertyValue); this.setElementAttribute(renderElement, propertyName, propertyValue);
} }
} }
}
setElementClass(renderElement: Element, className: string, isAdd: boolean): void { setElementClass(renderElement: Element, className: string, isAdd: boolean): void {
if (isAdd) { if (isAdd) {
@ -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 */