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:
parent
ba17dcbf2b
commit
0fa3895d5b
|
@ -101,11 +101,12 @@ export class AotCompiler {
|
|||
});
|
||||
|
||||
// compile components
|
||||
const compViewVars = this._compileComponent(
|
||||
compMeta, ngModule, ngModule.transitiveModule.directives,
|
||||
stylesCompileResults.componentStylesheet, fileSuffix, statements);
|
||||
exportedVars.push(
|
||||
this._compileComponentFactory(compMeta, ngModule, fileSuffix, statements),
|
||||
this._compileComponent(
|
||||
compMeta, ngModule, ngModule.transitiveModule.directives,
|
||||
stylesCompileResults.componentStylesheet, fileSuffix, statements));
|
||||
compViewVars.viewClassVar, compViewVars.compRenderTypeVar);
|
||||
});
|
||||
if (statements.length > 0) {
|
||||
const srcModule = this._codegenSourceModule(
|
||||
|
@ -175,8 +176,10 @@ export class AotCompiler {
|
|||
const hostType = this._metadataResolver.getHostComponentType(compMeta.type.reference);
|
||||
const hostMeta = createHostComponentMeta(
|
||||
hostType, compMeta, this._metadataResolver.getHostComponentViewClass(hostType));
|
||||
const hostViewFactoryVar = this._compileComponent(
|
||||
hostMeta, ngModule, [compMeta.type], null, fileSuffix, targetStatements);
|
||||
const hostViewFactoryVar =
|
||||
this._compileComponent(
|
||||
hostMeta, ngModule, [compMeta.type], null, fileSuffix, targetStatements)
|
||||
.viewClassVar;
|
||||
const compFactoryVar = componentFactoryName(compMeta.type.reference);
|
||||
targetStatements.push(
|
||||
o.variable(compFactoryVar)
|
||||
|
@ -198,7 +201,8 @@ export class AotCompiler {
|
|||
private _compileComponent(
|
||||
compMeta: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata,
|
||||
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 directives =
|
||||
directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
|
||||
|
@ -219,7 +223,10 @@ export class AotCompiler {
|
|||
}
|
||||
compiledAnimations.forEach(entry => targetStatements.push(...entry.statements));
|
||||
targetStatements.push(...viewResult.statements);
|
||||
return viewResult.viewClassVar;
|
||||
return {
|
||||
viewClassVar: viewResult.viewClassVar,
|
||||
compRenderTypeVar: viewResult.componentRenderTypeVar
|
||||
};
|
||||
}
|
||||
|
||||
private _codgenStyles(
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {ListWrapper} from './facade/collection';
|
||||
|
@ -15,6 +15,7 @@ import {LifecycleHooks, reflector} from './private_import_core';
|
|||
import {CssSelector} from './selector';
|
||||
import {splitAtColon} from './util';
|
||||
|
||||
|
||||
// group 0: "[prop] or (event) or @trigger"
|
||||
// group 1: "prop" from "[prop]"
|
||||
// group 2: "event" from "(event)"
|
||||
|
@ -116,6 +117,10 @@ export function viewClassName(compType: any, embeddedTemplateIndex: number): str
|
|||
return `View_${identifierName({reference: compType})}_${embeddedTemplateIndex}`;
|
||||
}
|
||||
|
||||
export function componentRenderTypeName(compType: any): string {
|
||||
return `RenderType_${identifierName({reference: compType})}`;
|
||||
}
|
||||
|
||||
export function hostViewClassName(compType: any): string {
|
||||
return `HostView_${identifierName({reference: compType})}`;
|
||||
}
|
||||
|
@ -310,6 +315,7 @@ export interface CompileDirectiveSummary extends CompileTypeSummary {
|
|||
template: CompileTemplateSummary;
|
||||
wrapperType: StaticSymbol|ProxyClass;
|
||||
componentViewType: StaticSymbol|ProxyClass;
|
||||
componentRenderType: StaticSymbol|ComponentRenderTypeV2;
|
||||
componentFactory: StaticSymbol|ComponentFactory<any>;
|
||||
}
|
||||
|
||||
|
@ -320,7 +326,7 @@ export class CompileDirectiveMetadata {
|
|||
static create(
|
||||
{isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
|
||||
providers, viewProviders, queries, viewQueries, entryComponents, template, wrapperType,
|
||||
componentViewType, componentFactory}: {
|
||||
componentViewType, componentRenderType, componentFactory}: {
|
||||
isHost?: boolean,
|
||||
type?: CompileTypeMetadata,
|
||||
isComponent?: boolean,
|
||||
|
@ -338,6 +344,7 @@ export class CompileDirectiveMetadata {
|
|||
template?: CompileTemplateMetadata,
|
||||
wrapperType?: StaticSymbol|ProxyClass,
|
||||
componentViewType?: StaticSymbol|ProxyClass,
|
||||
componentRenderType?: StaticSymbol|ComponentRenderTypeV2,
|
||||
componentFactory?: StaticSymbol|ComponentFactory<any>,
|
||||
} = {}): CompileDirectiveMetadata {
|
||||
const hostListeners: {[key: string]: string} = {};
|
||||
|
@ -392,6 +399,7 @@ export class CompileDirectiveMetadata {
|
|||
template,
|
||||
wrapperType,
|
||||
componentViewType,
|
||||
componentRenderType,
|
||||
componentFactory,
|
||||
});
|
||||
}
|
||||
|
@ -416,12 +424,14 @@ export class CompileDirectiveMetadata {
|
|||
|
||||
wrapperType: StaticSymbol|ProxyClass;
|
||||
componentViewType: StaticSymbol|ProxyClass;
|
||||
componentRenderType: StaticSymbol|ComponentRenderTypeV2;
|
||||
componentFactory: StaticSymbol|ComponentFactory<any>;
|
||||
|
||||
constructor({isHost, type, isComponent, selector, exportAs,
|
||||
changeDetection, inputs, outputs, hostListeners, hostProperties,
|
||||
hostAttributes, providers, viewProviders, queries, viewQueries,
|
||||
entryComponents, template, wrapperType, componentViewType, componentFactory}: {
|
||||
entryComponents, template, wrapperType, componentViewType, componentRenderType,
|
||||
componentFactory}: {
|
||||
isHost?: boolean,
|
||||
type?: CompileTypeMetadata,
|
||||
isComponent?: boolean,
|
||||
|
@ -441,6 +451,7 @@ export class CompileDirectiveMetadata {
|
|||
template?: CompileTemplateMetadata,
|
||||
wrapperType?: StaticSymbol|ProxyClass,
|
||||
componentViewType?: StaticSymbol|ProxyClass,
|
||||
componentRenderType?: StaticSymbol|ComponentRenderTypeV2,
|
||||
componentFactory?: StaticSymbol|ComponentFactory<any>,
|
||||
} = {}) {
|
||||
this.isHost = !!isHost;
|
||||
|
@ -463,6 +474,7 @@ export class CompileDirectiveMetadata {
|
|||
|
||||
this.wrapperType = wrapperType;
|
||||
this.componentViewType = componentViewType;
|
||||
this.componentRenderType = componentRenderType;
|
||||
this.componentFactory = componentFactory;
|
||||
}
|
||||
|
||||
|
@ -487,6 +499,7 @@ export class CompileDirectiveMetadata {
|
|||
template: this.template && this.template.toSummary(),
|
||||
wrapperType: this.wrapperType,
|
||||
componentViewType: this.componentViewType,
|
||||
componentRenderType: this.componentRenderType,
|
||||
componentFactory: this.componentFactory
|
||||
};
|
||||
}
|
||||
|
@ -521,7 +534,9 @@ export function createHostComponentMeta(
|
|||
viewProviders: [],
|
||||
queries: [],
|
||||
viewQueries: [],
|
||||
componentViewType: hostViewType
|
||||
componentViewType: hostViewType,
|
||||
componentRenderType:
|
||||
{id: '__Host__', encapsulation: ViewEncapsulation.None, styles: [], data: {}}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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';
|
||||
|
||||
|
@ -380,6 +380,12 @@ export class Identifiers {
|
|||
member: '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 {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {AnimationParser} from '../animation/animation_parser';
|
||||
|
@ -133,11 +133,11 @@ export class JitCompiler implements Compiler {
|
|||
const compileResult = this._ngModuleCompiler.compile(moduleMeta, extraProviders);
|
||||
if (!this._compilerConfig.useJit) {
|
||||
ngModuleFactory =
|
||||
interpretStatements(compileResult.statements, compileResult.ngModuleFactoryVar);
|
||||
interpretStatements(compileResult.statements, [compileResult.ngModuleFactoryVar])[0];
|
||||
} else {
|
||||
ngModuleFactory = jitStatements(
|
||||
`/${identifierName(moduleMeta.type)}/module.ngfactory.js`, compileResult.statements,
|
||||
compileResult.ngModuleFactoryVar);
|
||||
[compileResult.ngModuleFactoryVar])[0];
|
||||
}
|
||||
this._compiledNgModuleCache.set(moduleMeta.type.reference, ngModuleFactory);
|
||||
}
|
||||
|
@ -252,11 +252,12 @@ export class JitCompiler implements Compiler {
|
|||
const statements = compileResult.statements;
|
||||
let directiveWrapperClass: any;
|
||||
if (!this._compilerConfig.useJit) {
|
||||
directiveWrapperClass = interpretStatements(statements, compileResult.dirWrapperClassVar);
|
||||
directiveWrapperClass =
|
||||
interpretStatements(statements, [compileResult.dirWrapperClassVar])[0];
|
||||
} else {
|
||||
directiveWrapperClass = jitStatements(
|
||||
`/${identifierName(moduleMeta.type)}/${identifierName(dirMeta.type)}/wrapper.ngfactory.js`,
|
||||
statements, compileResult.dirWrapperClassVar);
|
||||
statements, [compileResult.dirWrapperClassVar])[0];
|
||||
}
|
||||
(<ProxyClass>dirMeta.wrapperType).setDelegate(directiveWrapperClass);
|
||||
this._compiledDirectiveWrapperCache.set(dirMeta.type.reference, directiveWrapperClass);
|
||||
|
@ -290,14 +291,18 @@ export class JitCompiler implements Compiler {
|
|||
.concat(...compiledAnimations.map(ca => ca.statements))
|
||||
.concat(compileResult.statements);
|
||||
let viewClass: any;
|
||||
let componentRenderType: any;
|
||||
if (!this._compilerConfig.useJit) {
|
||||
viewClass = interpretStatements(statements, compileResult.viewClassVar);
|
||||
[viewClass, componentRenderType] = interpretStatements(
|
||||
statements, [compileResult.viewClassVar, compileResult.componentRenderTypeVar]);
|
||||
} else {
|
||||
viewClass = jitStatements(
|
||||
`/${identifierName(template.ngModule.type)}/${identifierName(template.compType)}/${template.isHost?'host':'component'}.ngfactory.js`,
|
||||
statements, compileResult.viewClassVar);
|
||||
const sourceUrl =
|
||||
`/${identifierName(template.ngModule.type)}/${identifierName(template.compType)}/${template.isHost?'host':'component'}.ngfactory.js`;
|
||||
[viewClass, componentRenderType] = jitStatements(
|
||||
sourceUrl, statements,
|
||||
[compileResult.viewClassVar, compileResult.componentRenderTypeVar]);
|
||||
}
|
||||
template.compiled(viewClass);
|
||||
template.compiled(viewClass, componentRenderType);
|
||||
}
|
||||
|
||||
private _resolveStylesCompileResult(
|
||||
|
@ -315,10 +320,10 @@ export class JitCompiler implements Compiler {
|
|||
externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>): string[] {
|
||||
this._resolveStylesCompileResult(result, externalStylesheetsByModuleUrl);
|
||||
if (!this._compilerConfig.useJit) {
|
||||
return interpretStatements(result.statements, result.stylesVar);
|
||||
return interpretStatements(result.statements, [result.stylesVar])[0];
|
||||
} else {
|
||||
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 directives: CompileIdentifierMetadata[]) {}
|
||||
|
||||
compiled(viewClass: Function) {
|
||||
compiled(viewClass: Function, componentRenderType: any) {
|
||||
this._viewClass = viewClass;
|
||||
(<ProxyClass>this.compMeta.componentViewType).setDelegate(viewClass);
|
||||
for (let prop in componentRenderType) {
|
||||
(<any>this.compMeta.componentRenderType)[prop] = componentRenderType[prop];
|
||||
}
|
||||
this.isCompiled = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {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> {
|
||||
if (dirType instanceof StaticSymbol) {
|
||||
return this._staticSymbolCache.get(
|
||||
|
@ -235,6 +246,7 @@ export class CompileMetadataResolver {
|
|||
entryComponents: metadata.entryComponents,
|
||||
wrapperType: metadata.wrapperType,
|
||||
componentViewType: metadata.componentViewType,
|
||||
componentRenderType: metadata.componentRenderType,
|
||||
componentFactory: metadata.componentFactory,
|
||||
template: templateMetadata
|
||||
});
|
||||
|
@ -372,6 +384,8 @@ export class CompileMetadataResolver {
|
|||
wrapperType: this.getDirectiveWrapperClass(directiveType),
|
||||
componentViewType: nonNormalizedTemplateMetadata ? this.getComponentViewClass(directiveType) :
|
||||
undefined,
|
||||
componentRenderType:
|
||||
nonNormalizedTemplateMetadata ? this.getComponentRenderType(directiveType) : undefined,
|
||||
componentFactory: nonNormalizedTemplateMetadata ?
|
||||
this.getComponentFactory(selector, directiveType) :
|
||||
undefined
|
||||
|
|
|
@ -12,8 +12,9 @@ import {isPresent} from '../facade/lang';
|
|||
import * as o from './output_ast';
|
||||
import {debugOutputAstAsTypeScript} from './ts_emitter';
|
||||
|
||||
export function interpretStatements(statements: o.Statement[], resultVar: string): any {
|
||||
const stmtsWithReturn = statements.concat([new o.ReturnStatement(o.variable(resultVar))]);
|
||||
export function interpretStatements(statements: o.Statement[], resultVars: string[]): any[] {
|
||||
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 visitor = new StatementInterpreter();
|
||||
const result = visitor.visitAllStatements(stmtsWithReturn, ctx);
|
||||
|
|
|
@ -13,9 +13,9 @@ import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
|
|||
import * as o from './output_ast';
|
||||
|
||||
function evalExpression(
|
||||
sourceUrl: string, expr: string, ctx: EmitterVisitorContext, vars: {[key: string]: any}): any {
|
||||
sourceUrl: string, ctx: EmitterVisitorContext, vars: {[key: string]: any}): any {
|
||||
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 fnArgValues: any[] = [];
|
||||
for (const argName in vars) {
|
||||
|
@ -26,11 +26,13 @@ function evalExpression(
|
|||
}
|
||||
|
||||
export function jitStatements(
|
||||
sourceUrl: string, statements: o.Statement[], resultVar: string): any {
|
||||
sourceUrl: string, statements: o.Statement[], resultVars: string[]): any[] {
|
||||
const converter = new JitEmitterVisitor();
|
||||
const ctx = EmitterVisitorContext.createRoot([resultVar]);
|
||||
converter.visitAllStatements(statements, ctx);
|
||||
return evalExpression(sourceUrl, resultVar, ctx, converter.getArgs());
|
||||
const ctx = EmitterVisitorContext.createRoot(resultVars);
|
||||
const returnStmt =
|
||||
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 {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
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 {CompilerConfig} from '../config';
|
||||
import {isPresent} from '../facade/lang';
|
||||
|
@ -70,6 +70,7 @@ export class CompileView implements LegacyNameResolver {
|
|||
public pipes: CompilePipe[] = [];
|
||||
public locals = new Map<string, o.Expression>();
|
||||
public className: string;
|
||||
public renderComponentTypeName: string;
|
||||
public classType: o.Type;
|
||||
public classExpr: o.ReadVarExpr;
|
||||
|
||||
|
@ -102,6 +103,7 @@ export class CompileView implements LegacyNameResolver {
|
|||
|
||||
this.viewType = getViewType(component, viewIndex);
|
||||
this.className = viewClassName(component.type.reference, viewIndex);
|
||||
this.renderComponentTypeName = componentRenderTypeName(component.type.reference);
|
||||
this.classType = o.expressionType(o.variable(this.className));
|
||||
this.classExpr = o.variable(this.className);
|
||||
if (this.viewType === ViewType.COMPONENT || this.viewType === ViewType.HOST) {
|
||||
|
|
|
@ -386,7 +386,7 @@ function createViewTopLevelStmts(view: CompileView, targetStatements: o.Statemen
|
|||
|
||||
|
||||
const renderCompTypeVar: o.ReadVarExpr =
|
||||
o.variable(`renderType_${identifierName(view.component.type)}`); // fix highlighting: `
|
||||
o.variable(view.renderComponentTypeName); // fix highlighting: `
|
||||
if (view.viewIndex === 0) {
|
||||
let templateUrlInfo: string;
|
||||
if (view.component.template.templateUrl == identifierModuleUrl(view.component.type)) {
|
||||
|
|
|
@ -25,6 +25,7 @@ export {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDep
|
|||
export class ViewCompileResult {
|
||||
constructor(
|
||||
public statements: o.Statement[], public viewClassVar: string,
|
||||
public componentRenderTypeVar: string,
|
||||
public dependencies:
|
||||
Array<ComponentViewDependency|ComponentFactoryDependency|DirectiveWrapperDependency>) {}
|
||||
}
|
||||
|
@ -50,6 +51,7 @@ export class ViewCompiler {
|
|||
bindView(view, template, this._schemaRegistry);
|
||||
finishView(view, statements);
|
||||
|
||||
return new ViewCompileResult(statements, view.classExpr.name, dependencies);
|
||||
return new ViewCompileResult(
|
||||
statements, view.classExpr.name, view.renderComponentTypeName, dependencies);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
* 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 {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 {CompilerConfig} from '../config';
|
||||
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 {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 {ViewEncapsulationEnum} from '../view_compiler/constants';
|
||||
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency, ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
|
||||
|
||||
const CLASS_ATTR = 'class';
|
||||
|
@ -44,19 +43,33 @@ export class ViewCompilerNext extends ViewCompiler {
|
|||
let embeddedViewCount = 0;
|
||||
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 embeddedViewIndex = embeddedViewCount++;
|
||||
const viewName = `view_${compName}_${embeddedViewIndex}`;
|
||||
const viewName = viewClassName(component.type.reference, embeddedViewIndex);
|
||||
return new ViewBuilder(parent, viewName, usedPipes, staticQueryIds, viewBuilderFactory);
|
||||
};
|
||||
|
||||
const visitor = viewBuilderFactory(null);
|
||||
visitor.visitAll([], template);
|
||||
|
||||
const statements: o.Statement[] = [];
|
||||
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;
|
||||
if (directiveAst.directive.isComponent) {
|
||||
compView = o.importExpr({reference: directiveAst.directive.componentViewType});
|
||||
compRenderType = o.importExpr({reference: directiveAst.directive.componentRenderType});
|
||||
}
|
||||
|
||||
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(childCount), providerExpr, depsExpr,
|
||||
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;
|
||||
|
||||
|
|
|
@ -93,8 +93,6 @@ export const __core_private__: {
|
|||
makeDecorator: typeof decorators.makeDecorator,
|
||||
DebugDomRootRenderer: typeof debug.DebugDomRootRenderer,
|
||||
_DebugDomRootRenderer: debug.DebugDomRootRenderer,
|
||||
DebugDomRendererV2: typeof debug.DebugDomRendererV2,
|
||||
_DebugDomRendererV2: debug.DebugDomRendererV2,
|
||||
Console: typeof console.Console,
|
||||
_Console: console.Console,
|
||||
reflector: typeof reflection.reflector,
|
||||
|
@ -158,7 +156,6 @@ export const __core_private__: {
|
|||
ReflectionCapabilities: reflection_capabilities.ReflectionCapabilities,
|
||||
makeDecorator: decorators.makeDecorator,
|
||||
DebugDomRootRenderer: debug.DebugDomRootRenderer,
|
||||
DebugDomRendererV2: debug.DebugDomRendererV2,
|
||||
Console: console.Console,
|
||||
reflector: reflection.reflector,
|
||||
Reflector: reflection.Reflector,
|
||||
|
|
|
@ -10,7 +10,7 @@ import {AnimationKeyframe} from '../animation/animation_keyframe';
|
|||
import {AnimationPlayer} from '../animation/animation_player';
|
||||
import {AnimationStyles} from '../animation/animation_styles';
|
||||
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';
|
||||
|
||||
|
@ -156,151 +156,3 @@ export class DebugDomRenderer implements Renderer {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
*/
|
||||
|
||||
// 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';
|
||||
|
|
|
@ -12,13 +12,6 @@ import {AnimationStyles} from '../../src/animation/animation_styles';
|
|||
import {InjectionToken, Injector} from '../di';
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
|
||||
/**
|
||||
* Provide a concrete implementation of {@link RendererV2}
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
export const RENDERER_V2_DIRECT = new InjectionToken<RendererV2>('Renderer V2');
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
|
@ -98,56 +91,6 @@ export abstract class Renderer {
|
|||
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.
|
||||
*
|
||||
|
@ -164,3 +107,64 @@ export abstract class RenderDebugContext {
|
|||
export abstract class RootRenderer {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ export function elementDef(
|
|||
export function createElement(view: ViewData, renderHost: any, def: NodeDef): ElementData {
|
||||
const elDef = def.element;
|
||||
const rootSelectorOrNode = view.root.selectorOrNode;
|
||||
const renderer = view.root.renderer;
|
||||
const renderer = view.renderer;
|
||||
let el: any;
|
||||
if (view.parent || !rootSelectorOrNode) {
|
||||
if (elDef.name) {
|
||||
|
@ -240,7 +240,7 @@ function setElementAttribute(
|
|||
const securityContext = binding.securityContext;
|
||||
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
|
||||
renderValue = renderValue != null ? renderValue.toString() : null;
|
||||
const renderer = view.root.renderer;
|
||||
const renderer = view.renderer;
|
||||
// TODO(vicb): move the namespace to the node definition
|
||||
const nsAndName = splitNamespace(name);
|
||||
if (value != null) {
|
||||
|
@ -251,7 +251,7 @@ function setElementAttribute(
|
|||
}
|
||||
|
||||
function setElementClass(view: ViewData, renderNode: any, name: string, value: boolean) {
|
||||
const renderer = view.root.renderer;
|
||||
const renderer = view.renderer;
|
||||
if (value) {
|
||||
renderer.addClass(renderNode, name);
|
||||
} else {
|
||||
|
@ -271,7 +271,7 @@ function setElementStyle(
|
|||
} else {
|
||||
renderValue = null;
|
||||
}
|
||||
const renderer = view.root.renderer;
|
||||
const renderer = view.renderer;
|
||||
if (renderValue != null) {
|
||||
renderer.setStyle(renderNode, name, renderValue, false, false);
|
||||
} else {
|
||||
|
@ -283,7 +283,7 @@ function setElementProperty(
|
|||
view: ViewData, binding: BindingDef, renderNode: any, name: string, value: any) {
|
||||
const securityContext = binding.securityContext;
|
||||
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 = /^:([^:]+):(.+)$/;
|
||||
|
|
|
@ -14,7 +14,7 @@ export {queryDef} from './query';
|
|||
export {createComponentFactory} from './refs';
|
||||
export {initServicesIfNeeded} from './services';
|
||||
export {textDef} from './text';
|
||||
export {elementEventFullName, nodeValue, rootRenderNodes, unwrapValue} from './util';
|
||||
export {createComponentRenderTypeV2, elementEventFullName, nodeValue, rootRenderNodes, unwrapValue} from './util';
|
||||
export {viewDef} from './view';
|
||||
export {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';
|
||||
|
||||
|
|
|
@ -11,13 +11,15 @@ import {Injector} from '../di';
|
|||
import {ElementRef} from '../linker/element_ref';
|
||||
import {TemplateRef} from '../linker/template_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 {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';
|
||||
|
||||
const RendererV1TokenKey = tokenKey(v1renderer.Renderer);
|
||||
const RendererV1TokenKey = tokenKey(RendererV1);
|
||||
const RendererV2TokenKey = tokenKey(RendererV2);
|
||||
const ElementRefTokenKey = tokenKey(ElementRef);
|
||||
const ViewContainerRefTokenKey = tokenKey(ViewContainerRef);
|
||||
const TemplateRefTokenKey = tokenKey(TemplateRef);
|
||||
|
@ -29,7 +31,8 @@ const NOT_CREATED = new Object();
|
|||
export function directiveDef(
|
||||
flags: NodeFlags, matchedQueries: [string | number, QueryValueType][], childCount: number,
|
||||
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[] = [];
|
||||
if (props) {
|
||||
for (let prop in props) {
|
||||
|
@ -50,7 +53,7 @@ export function directiveDef(
|
|||
}
|
||||
return _def(
|
||||
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 {
|
||||
|
@ -67,8 +70,13 @@ export function _def(
|
|||
type: NodeType, flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
|
||||
childCount: number, providerType: ProviderType, token: any, value: any,
|
||||
deps: ([DepFlags, any] | any)[], bindings?: BindingDef[], outputs?: DirectiveOutputDef[],
|
||||
component?: () => ViewDefinition): NodeDef {
|
||||
component?: () => ViewDefinition, componentRenderType?: ComponentRenderTypeV2): NodeDef {
|
||||
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) {
|
||||
outputs = [];
|
||||
}
|
||||
|
@ -111,7 +119,7 @@ export function _def(
|
|||
type: providerType,
|
||||
token,
|
||||
tokenKey: tokenKey(token), value,
|
||||
deps: depDefs, outputs, component
|
||||
deps: depDefs, outputs, component, componentRenderType
|
||||
},
|
||||
text: undefined,
|
||||
pureExpression: undefined,
|
||||
|
@ -328,16 +336,19 @@ export function resolveDep(
|
|||
if (elDef) {
|
||||
switch (tokenKey) {
|
||||
case RendererV1TokenKey: {
|
||||
let compView = view;
|
||||
while (compView && !isComponentView(compView)) {
|
||||
compView = compView.parent;
|
||||
}
|
||||
const rootRenderer: v1renderer.RootRenderer =
|
||||
view.root.injector.get(v1renderer.RootRenderer);
|
||||
const compView = findCompView(view, elDef, allowPrivateServices);
|
||||
const compDef = compView.parentNodeDef;
|
||||
const rootRendererV1: RootRendererV1 = view.root.injector.get(RootRendererV1);
|
||||
|
||||
// Note: Don't fill in the styles as they have been installed already!
|
||||
return rootRenderer.renderComponent(new v1renderer.RenderComponentType(
|
||||
view.def.component.id, '', 0, view.def.component.encapsulation, [], {}));
|
||||
// Note: Don't fill in the styles as they have been installed already via the RendererV2!
|
||||
const compRenderType = compDef.provider.componentRenderType;
|
||||
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:
|
||||
return new ElementRef(asElementData(view, elDef.index).renderElement);
|
||||
|
@ -350,15 +361,7 @@ export function resolveDep(
|
|||
break;
|
||||
}
|
||||
case ChangeDetectorRefTokenKey: {
|
||||
let cdView: ViewData;
|
||||
if (allowPrivateServices) {
|
||||
cdView = asProviderData(view, elDef.element.component.index).componentView;
|
||||
} else {
|
||||
cdView = view;
|
||||
while (cdView.parent && !isComponentView(cdView)) {
|
||||
cdView = cdView.parent;
|
||||
}
|
||||
}
|
||||
let cdView = findCompView(view, elDef, allowPrivateServices);
|
||||
return createChangeDetectorRef(cdView);
|
||||
}
|
||||
case InjectorRefTokenKey:
|
||||
|
@ -383,6 +386,19 @@ export function resolveDep(
|
|||
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(
|
||||
view: ViewData, providerData: ProviderData, def: NodeDef, bindingIdx: number, value: any,
|
||||
changes: SimpleChanges): SimpleChanges {
|
||||
|
|
|
@ -201,8 +201,9 @@ export function createInjector(view: ViewData, elDef: NodeDef): Injector {
|
|||
class Injector_ implements Injector {
|
||||
constructor(private view: ViewData, private elDef: NodeDef) {}
|
||||
get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any {
|
||||
const allowPrivateServices = !!this.elDef.element.component;
|
||||
return Services.resolveDep(
|
||||
this.view, this.elDef, true, {flags: DepFlags.None, token, tokenKey: tokenKey(token)},
|
||||
notFoundValue);
|
||||
this.view, this.elDef, allowPrivateServices,
|
||||
{flags: DepFlags.None, token, tokenKey: tokenKey(token)}, notFoundValue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
*/
|
||||
|
||||
import {isDevMode} from '../application_ref';
|
||||
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node';
|
||||
import {Injector} from '../di';
|
||||
import {RendererV2} from '../render/api';
|
||||
import {ComponentRenderTypeV2, RendererFactoryV2, RendererV2} from '../render/api';
|
||||
import {Sanitizer, SecurityContext} from '../security';
|
||||
|
||||
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
|
||||
|
@ -87,52 +88,59 @@ function createDebugServices() {
|
|||
function createProdRootView(
|
||||
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: string | any,
|
||||
def: ViewDefinition, context?: any): ViewData {
|
||||
const rendererFactory: RendererFactoryV2 = injector.get(RendererFactoryV2);
|
||||
return createRootView(
|
||||
createRootData(injector, projectableNodes, rootSelectorOrNode), def, context);
|
||||
createRootData(injector, rendererFactory, projectableNodes, rootSelectorOrNode), def,
|
||||
context);
|
||||
}
|
||||
|
||||
function debugCreateRootView(
|
||||
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: string | any,
|
||||
def: ViewDefinition, context?: any): ViewData {
|
||||
const root = createRootData(injector, projectableNodes, rootSelectorOrNode);
|
||||
const debugRoot: RootData = {
|
||||
injector: root.injector,
|
||||
projectableNodes: root.projectableNodes,
|
||||
selectorOrNode: root.selectorOrNode,
|
||||
renderer: new DebugRenderer(root.renderer),
|
||||
sanitizer: root.sanitizer
|
||||
};
|
||||
return callWithDebugContext('create', createRootView, null, [debugRoot, def, context]);
|
||||
const rendererFactory: RendererFactoryV2 = injector.get(RendererFactoryV2);
|
||||
const root = createRootData(
|
||||
injector, new DebugRendererFactoryV2(rendererFactory), projectableNodes, rootSelectorOrNode);
|
||||
return callWithDebugContext(DebugAction.create, createRootView, null, [root, def, context]);
|
||||
}
|
||||
|
||||
function createRootData(
|
||||
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: any): RootData {
|
||||
injector: Injector, rendererFactory: RendererFactoryV2, projectableNodes: any[][],
|
||||
rootSelectorOrNode: any): RootData {
|
||||
const sanitizer = injector.get(Sanitizer);
|
||||
const renderer = injector.get(RendererV2);
|
||||
|
||||
const rootElement =
|
||||
rootSelectorOrNode ? renderer.selectRootElement(rootSelectorOrNode) : undefined;
|
||||
return {injector, projectableNodes, selectorOrNode: rootSelectorOrNode, sanitizer, renderer};
|
||||
const renderer = rendererFactory.createRenderer(null, null);
|
||||
return {
|
||||
injector,
|
||||
projectableNodes,
|
||||
selectorOrNode: rootSelectorOrNode, sanitizer, rendererFactory, renderer
|
||||
};
|
||||
}
|
||||
|
||||
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) {
|
||||
return callWithDebugContext('detectChanges', checkAndUpdateView, null, [view]);
|
||||
return callWithDebugContext(DebugAction.detectChanges, checkAndUpdateView, null, [view]);
|
||||
}
|
||||
|
||||
function debugCheckNoChangesView(view: ViewData) {
|
||||
return callWithDebugContext('checkNoChanges', checkNoChangesView, null, [view]);
|
||||
return callWithDebugContext(DebugAction.checkNoChanges, checkNoChangesView, null, [view]);
|
||||
}
|
||||
|
||||
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 _currentNodeIndex: number;
|
||||
|
||||
|
@ -143,16 +151,16 @@ function debugSetCurrentNode(view: ViewData, nodeIndex: number) {
|
|||
|
||||
function debugHandleEvent(view: ViewData, nodeIndex: number, eventName: string, event: any) {
|
||||
if (view.state & ViewState.Destroyed) {
|
||||
throw viewDestroyedError(_currentAction);
|
||||
throw viewDestroyedError(DebugAction[_currentAction]);
|
||||
}
|
||||
debugSetCurrentNode(view, nodeIndex);
|
||||
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) {
|
||||
if (view.state & ViewState.Destroyed) {
|
||||
throw viewDestroyedError(_currentAction);
|
||||
throw viewDestroyedError(DebugAction[_currentAction]);
|
||||
}
|
||||
debugSetCurrentNode(view, nextDirectiveWithBinding(view, 0));
|
||||
return view.def.updateDirectives(debugCheckDirectivesFn, view);
|
||||
|
@ -167,7 +175,7 @@ function debugUpdateDirectives(check: NodeCheckFn, view: ViewData) {
|
|||
|
||||
function debugUpdateRenderer(check: NodeCheckFn, view: ViewData) {
|
||||
if (view.state & ViewState.Destroyed) {
|
||||
throw viewDestroyedError(_currentAction);
|
||||
throw viewDestroyedError(DebugAction[_currentAction]);
|
||||
}
|
||||
debugSetCurrentNode(view, nextRenderNodeWithBinding(view, 0));
|
||||
return view.def.updateRenderer(debugCheckRenderNodeFn, view);
|
||||
|
@ -183,35 +191,41 @@ function debugUpdateRenderer(check: NodeCheckFn, view: ViewData) {
|
|||
function debugCheckFn(
|
||||
delegate: NodeCheckFn, view: ViewData, nodeIndex: number, argStyle: ArgumentType,
|
||||
givenValues: any[]) {
|
||||
const values = argStyle === ArgumentType.Dynamic ? givenValues[0] : givenValues;
|
||||
const nodeDef = view.def.nodes[nodeIndex];
|
||||
for (let i = 0; i < nodeDef.bindings.length; i++) {
|
||||
const binding = nodeDef.bindings[i];
|
||||
const value = values[i];
|
||||
if ((binding.type === BindingType.ElementProperty ||
|
||||
binding.type === BindingType.DirectiveProperty) &&
|
||||
checkBinding(view, nodeDef, i, value)) {
|
||||
if (_currentAction === DebugAction.detectChanges) {
|
||||
const values = argStyle === ArgumentType.Dynamic ? givenValues[0] : givenValues;
|
||||
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++) {
|
||||
const binding = nodeDef.bindings[i];
|
||||
const value = values[i];
|
||||
if ((binding.type === BindingType.ElementProperty ||
|
||||
binding.type === BindingType.DirectiveProperty) &&
|
||||
checkBinding(view, nodeDef, i, value)) {
|
||||
bindingValues[normalizeDebugBindingName(binding.nonMinifiedName)] =
|
||||
normalizeDebugBindingValue(value);
|
||||
}
|
||||
}
|
||||
const elDef = nodeDef.type === NodeType.Directive ? nodeDef.parent : nodeDef;
|
||||
setBindingDebugInfo(
|
||||
view.root.renderer, asElementData(view, elDef.index).renderElement,
|
||||
binding.nonMinifiedName, value);
|
||||
const el = asElementData(view, elDef.index).renderElement;
|
||||
if (!elDef.element.name) {
|
||||
// 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);
|
||||
};
|
||||
|
||||
function setBindingDebugInfo(renderer: RendererV2, renderNode: any, propName: string, value: any) {
|
||||
const renderName = `ng-reflect-${camelCaseToDashCase(propName)}`;
|
||||
if (value) {
|
||||
try {
|
||||
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);
|
||||
}
|
||||
function normalizeDebugBindingName(name: string) {
|
||||
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
|
||||
name = camelCaseToDashCase(name.replace(/\$/g, '_'));
|
||||
return `ng-reflect-${name}`;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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 {
|
||||
for (let i = nodeIndex; i < view.def.nodes.length; i++) {
|
||||
const nodeDef = view.def.nodes[i];
|
||||
|
@ -241,64 +264,6 @@ function nextRenderNodeWithBinding(view: ViewData, nodeIndex: number): number {
|
|||
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 {
|
||||
private nodeDef: NodeDef;
|
||||
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 oldView = _currentView;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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); }
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ export function textDef(ngContentIndex: number, constants: string[]): NodeDef {
|
|||
|
||||
export function createText(view: ViewData, renderHost: any, def: NodeDef): TextData {
|
||||
let renderNode: any;
|
||||
const renderer = view.root.renderer;
|
||||
const renderer = view.renderer;
|
||||
renderNode = renderer.createText(def.text.prefix);
|
||||
const parentEl = getParentRenderElement(view, renderHost, def);
|
||||
if (parentEl) {
|
||||
|
@ -119,7 +119,7 @@ export function checkAndUpdateTextInline(
|
|||
}
|
||||
value = def.text.prefix + value;
|
||||
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;
|
||||
const renderNode = asTextData(view, def.index).renderText;
|
||||
view.root.renderer.setText(renderNode, value);
|
||||
view.renderer.setValue(renderNode, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import {TemplateRef} from '../linker/template_ref';
|
|||
import {ViewContainerRef} from '../linker/view_container_ref';
|
||||
import {ViewRef} from '../linker/view_ref';
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
import {RenderDebugContext, RendererV2} from '../render/api';
|
||||
import {ComponentRenderTypeV2, RendererFactoryV2, RendererV2} from '../render/api';
|
||||
import {Sanitizer, SecurityContext} from '../security';
|
||||
|
||||
// -------------------------------------
|
||||
|
@ -23,7 +23,6 @@ import {Sanitizer, SecurityContext} from '../security';
|
|||
|
||||
export interface ViewDefinition {
|
||||
flags: ViewFlags;
|
||||
component: ComponentDefinition;
|
||||
updateDirectives: ViewUpdateFn;
|
||||
updateRenderer: ViewUpdateFn;
|
||||
handleEvent: ViewHandleEventFn;
|
||||
|
@ -75,13 +74,7 @@ export enum ArgumentType {
|
|||
*/
|
||||
export enum ViewFlags {
|
||||
None = 0,
|
||||
OnPush = 1 << 1
|
||||
}
|
||||
|
||||
export interface ComponentDefinition {
|
||||
id: string;
|
||||
encapsulation: ViewEncapsulation;
|
||||
styles: string[];
|
||||
OnPush = 1 << 1,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,6 +216,7 @@ export interface ProviderDef {
|
|||
value: any;
|
||||
deps: DepDef[];
|
||||
outputs: DirectiveOutputDef[];
|
||||
componentRenderType: ComponentRenderTypeV2;
|
||||
// closure to allow recursive components
|
||||
component: ViewDefinitionFactory;
|
||||
}
|
||||
|
@ -306,6 +300,7 @@ export interface NgContentDef {
|
|||
export interface ViewData {
|
||||
def: ViewDefinition;
|
||||
root: RootData;
|
||||
renderer: RendererV2;
|
||||
// index of component provider / anchor.
|
||||
parentNodeDef: NodeDef;
|
||||
parent: ViewData;
|
||||
|
@ -426,12 +421,21 @@ export interface RootData {
|
|||
projectableNodes: any[][];
|
||||
selectorOrNode: any;
|
||||
renderer: RendererV2;
|
||||
rendererFactory: RendererFactoryV2;
|
||||
sanitizer: Sanitizer;
|
||||
}
|
||||
|
||||
export abstract class DebugContext extends RenderDebugContext {
|
||||
export abstract class DebugContext {
|
||||
abstract get view(): ViewData;
|
||||
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;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
|
|
@ -14,7 +14,8 @@ import {looseIdentical, stringify} from '../facade/lang';
|
|||
import {TemplateRef} from '../linker/template_ref';
|
||||
import {ViewContainerRef} from '../linker/view_container_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 {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;
|
||||
}
|
||||
|
||||
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(
|
||||
view: ViewData, def: NodeDef, bindingIdx: number, value: any): boolean {
|
||||
const oldValue = view.oldValues[def.bindingIndex + bindingIdx];
|
||||
|
@ -220,7 +238,7 @@ export function visitRootRenderNodes(
|
|||
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
|
||||
if (action === RenderNodeAction.RemoveChild) {
|
||||
parentNode = view.root.renderer.parentNode(renderNode(view, view.def.lastRootNode));
|
||||
parentNode = view.renderer.parentNode(renderNode(view, view.def.lastRootNode));
|
||||
}
|
||||
visitSiblingRenderNodes(
|
||||
view, action, 0, view.def.nodes.length - 1, parentNode, nextSibling, target);
|
||||
|
@ -298,7 +316,7 @@ function visitRenderNode(
|
|||
function execRenderNodeAction(
|
||||
view: ViewData, renderNode: any, action: RenderNodeAction, parentNode: any, nextSibling: any,
|
||||
target: any[]) {
|
||||
const renderer = view.root.renderer;
|
||||
const renderer = view.renderer;
|
||||
switch (action) {
|
||||
case RenderNodeAction.AppendChild:
|
||||
renderer.appendChild(parentNode, renderNode);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
import {ComponentRenderTypeV2, RendererV2} from '../render/api';
|
||||
|
||||
import {checkAndUpdateElementDynamic, checkAndUpdateElementInline, createElement} from './element';
|
||||
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
|
||||
|
@ -15,15 +16,14 @@ import {callLifecycleHooksChildrenFirst, checkAndUpdateDirectiveDynamic, checkAn
|
|||
import {checkAndUpdatePureExpressionDynamic, checkAndUpdatePureExpressionInline, createPureExpression} from './pure_expression';
|
||||
import {checkAndUpdateQuery, createQuery, queryDef} from './query';
|
||||
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';
|
||||
|
||||
const NOOP = (): any => undefined;
|
||||
|
||||
export function viewDef(
|
||||
flags: ViewFlags, nodes: NodeDef[], updateDirectives?: ViewUpdateFn,
|
||||
updateRenderer?: ViewUpdateFn, handleEvent?: ViewHandleEventFn, compId?: string,
|
||||
encapsulation?: ViewEncapsulation, styles?: string[]): ViewDefinition {
|
||||
updateRenderer?: ViewUpdateFn, handleEvent?: ViewHandleEventFn): ViewDefinition {
|
||||
// clone nodes and set auto calculated values
|
||||
if (nodes.length === 0) {
|
||||
throw new Error(`Illegal State: Views without nodes are not allowed!`);
|
||||
|
@ -57,8 +57,11 @@ export function viewDef(
|
|||
|
||||
let currentRenderParent: NodeDef;
|
||||
if (currentParent &&
|
||||
!(currentParent.type === NodeType.Element && currentParent.element.component)) {
|
||||
// children of components should never be attached!
|
||||
(currentParent.type !== NodeType.Element || !currentParent.element.component ||
|
||||
(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) {
|
||||
currentRenderParent = currentParent.renderParent;
|
||||
} else {
|
||||
|
@ -134,8 +137,6 @@ export function viewDef(
|
|||
}
|
||||
currentParent = newParent;
|
||||
}
|
||||
const componentDef =
|
||||
compId ? <ComponentDefinition>{id: compId, encapsulation, styles} : undefined;
|
||||
return {
|
||||
nodeFlags: viewNodeFlags,
|
||||
nodeMatchedQueries: viewMatchedQueries, flags,
|
||||
|
@ -143,7 +144,6 @@ export function viewDef(
|
|||
updateDirectives: updateDirectives || NOOP,
|
||||
updateRenderer: updateRenderer || NOOP,
|
||||
handleEvent: handleEvent || NOOP,
|
||||
component: componentDef,
|
||||
bindingCount: viewBindingCount,
|
||||
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 {
|
||||
// embedded views are seen as siblings to the anchor, so we need
|
||||
// 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);
|
||||
createViewNodes(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
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);
|
||||
createViewNodes(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
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 disposables = def.disposableCount ? new Array(def.disposableCount) : undefined;
|
||||
const view: ViewData = {
|
||||
|
@ -245,7 +247,7 @@ function createView(
|
|||
parentNodeDef,
|
||||
context: undefined,
|
||||
component: undefined, nodes,
|
||||
state: ViewState.FirstCheck | ViewState.ChecksEnabled, root,
|
||||
state: ViewState.FirstCheck | ViewState.ChecksEnabled, root, renderer,
|
||||
oldValues: new Array(def.bindingCount), disposables
|
||||
};
|
||||
return view;
|
||||
|
@ -259,9 +261,9 @@ function initView(view: ViewData, component: any, context: any) {
|
|||
function createViewNodes(view: ViewData) {
|
||||
let renderHost: any;
|
||||
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 nodes = view.nodes;
|
||||
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
|
||||
// the component view. Therefore, we create the component view first
|
||||
// and set the ProviderData in ViewData, and then instantiate the provider.
|
||||
const componentView = createView(
|
||||
view.root, view, nodeDef, resolveViewDefinition(nodeDef.provider.component));
|
||||
const compViewDef = 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};
|
||||
nodes[i] = providerData as any;
|
||||
const instance = providerData.instance = createDirectiveInstance(view, nodeDef);
|
||||
|
@ -473,9 +483,27 @@ export function destroyView(view: ViewData) {
|
|||
view.disposables[i]();
|
||||
}
|
||||
}
|
||||
if (view.renderer.destroyNode) {
|
||||
destroyViewNodes(view);
|
||||
}
|
||||
if (view.parentNodeDef && view.parentNodeDef.flags & NodeFlags.HasComponent) {
|
||||
view.renderer.destroy();
|
||||
}
|
||||
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 {
|
||||
CreateViewNodes,
|
||||
CheckNoChanges,
|
||||
|
|
|
@ -77,15 +77,15 @@ export function moveEmbeddedView(
|
|||
function renderAttachEmbeddedView(elementData: ElementData, prevView: ViewData, view: ViewData) {
|
||||
const prevRenderNode =
|
||||
prevView ? renderNode(prevView, prevView.def.lastRootNode) : elementData.renderElement;
|
||||
const parentNode = view.root.renderer.parentNode(prevRenderNode);
|
||||
const nextSibling = view.root.renderer.nextSibling(prevRenderNode);
|
||||
const parentNode = view.renderer.parentNode(prevRenderNode);
|
||||
const nextSibling = view.renderer.nextSibling(prevRenderNode);
|
||||
// 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`.
|
||||
visitRootRenderNodes(view, RenderNodeAction.InsertBefore, parentNode, nextSibling, undefined);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
|
||||
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
|
||||
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 {DebugDomRenderer, DebugDomRendererV2} from '@angular/core/src/debug/debug_renderer';
|
||||
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} from '@angular/core/src/debug/debug_renderer';
|
||||
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
|
@ -57,6 +57,7 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
|
|||
renderLog = TestBed.get(RenderLog);
|
||||
directiveLog = TestBed.get(DirectiveLog);
|
||||
elSchema.existingProperties['someProp'] = true;
|
||||
patchLoggingRendererV2(TestBed.get(RendererFactoryV2), renderLog);
|
||||
}
|
||||
|
||||
function queryDirs(el: DebugElement, dirType: Type<any>): any {
|
||||
|
@ -123,11 +124,6 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
|
|||
RenderLog,
|
||||
DirectiveLog,
|
||||
{provide: RootRenderer, useClass: LoggingRootRenderer},
|
||||
{
|
||||
provide: RendererV2,
|
||||
useFactory: (r: RendererV2, log: RenderLog) => new LoggingRendererV2(r, log),
|
||||
deps: [[new Inject(RENDERER_V2_DIRECT)], [RenderLog]],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
@ -1244,28 +1240,26 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
|
|||
expect(renderLog.loggedValues).toEqual(['Tom']);
|
||||
});
|
||||
|
||||
// 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',
|
||||
() => {
|
||||
@Component({template: '<template #vc>{{name}}</template>'})
|
||||
class Comp {
|
||||
name = 'Tom';
|
||||
@ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;
|
||||
@ViewChild(TemplateRef) template: TemplateRef<any>;
|
||||
}
|
||||
it('should recurse into nested view containers even if there are no bindings in the component view',
|
||||
() => {
|
||||
@Component({template: '<template #vc>{{name}}</template>'})
|
||||
class Comp {
|
||||
name = 'Tom';
|
||||
@ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;
|
||||
@ViewChild(TemplateRef) template: TemplateRef<any>;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Comp]});
|
||||
initHelpers();
|
||||
TestBed.configureTestingModule({declarations: [Comp]});
|
||||
initHelpers();
|
||||
|
||||
const ctx = TestBed.createComponent(Comp);
|
||||
ctx.detectChanges();
|
||||
expect(renderLog.loggedValues).toEqual([]);
|
||||
const ctx = TestBed.createComponent(Comp);
|
||||
ctx.detectChanges();
|
||||
expect(renderLog.loggedValues).toEqual([]);
|
||||
|
||||
ctx.componentInstance.vc.createEmbeddedView(ctx.componentInstance.template);
|
||||
ctx.detectChanges();
|
||||
expect(renderLog.loggedValues).toEqual(['Tom']);
|
||||
});
|
||||
ctx.componentInstance.vc.createEmbeddedView(ctx.componentInstance.template);
|
||||
ctx.detectChanges();
|
||||
expect(renderLog.loggedValues).toEqual(['Tom']);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1315,18 +1309,32 @@ class DirectiveLogEntry {
|
|||
constructor(public directiveName: string, public method: string) {}
|
||||
}
|
||||
|
||||
class LoggingRendererV2 extends DebugDomRendererV2 {
|
||||
constructor(private delegate: RendererV2, private log: RenderLog) { super(delegate); }
|
||||
|
||||
setProperty(el: any, name: string, value: any): void {
|
||||
this.log.setElementProperty(el, name, value);
|
||||
super.setProperty(el, name, value);
|
||||
}
|
||||
|
||||
setText(node: any, value: string): void {
|
||||
this.log.setText(node, value);
|
||||
super.setText(node, value);
|
||||
function patchLoggingRendererV2(rendererFactory: RendererFactoryV2, log: RenderLog) {
|
||||
if ((<any>rendererFactory).__patchedForLogging) {
|
||||
return;
|
||||
}
|
||||
(<any>rendererFactory).__patchedForLogging = true;
|
||||
const origCreateRenderer = rendererFactory.createRenderer;
|
||||
rendererFactory.createRenderer = function() {
|
||||
const renderer = origCreateRenderer.apply(this, arguments);
|
||||
if ((<any>renderer).__patchedForLogging) {
|
||||
return renderer;
|
||||
}
|
||||
(<any>renderer).__patchedForLogging = true;
|
||||
const origSetProperty = renderer.setProperty;
|
||||
const origSetValue = renderer.setValue;
|
||||
renderer.setProperty = function(el: any, name: string, value: any): void {
|
||||
log.setElementProperty(el, name, value);
|
||||
origSetProperty.call(this, el, name, value);
|
||||
};
|
||||
renderer.setValue = function(node: any, value: string): void {
|
||||
if (getDOM().isTextNode(node)) {
|
||||
log.setText(node, value);
|
||||
}
|
||||
origSetValue.call(this, node, value);
|
||||
};
|
||||
return renderer;
|
||||
};
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
|
|
|
@ -1515,7 +1515,7 @@ function declareTests({useJit, viewEngine}: {useJit: boolean, viewEngine: boolea
|
|||
const fixture = TestBed.createComponent(ParentCmp);
|
||||
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', () => {
|
||||
|
|
|
@ -378,7 +378,7 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
|
|||
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', () => {
|
||||
TestBed.configureTestingModule({declarations: [SimpleNative1, SimpleNative2]});
|
||||
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', () => {
|
||||
TestBed.configureTestingModule({declarations: [OtherComp]});
|
||||
TestBed.overrideComponent(MainComp, {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {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';
|
||||
|
@ -19,9 +19,7 @@ export function main() {
|
|||
function compViewDef(
|
||||
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
|
||||
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
|
||||
return viewDef(
|
||||
viewFlags, nodes, updateDirectives, updateRenderer, handleEvent, 'someCompId',
|
||||
ViewEncapsulation.None, []);
|
||||
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
|
||||
}
|
||||
|
||||
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory {
|
||||
|
@ -292,11 +290,25 @@ export function main() {
|
|||
it('should inject RendererV1', () => {
|
||||
createAndGetRootNodes(compViewDef([
|
||||
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();
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
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 {WebAnimationsDriver} from '../src/dom/web_animations_driver';
|
||||
|
@ -19,7 +19,7 @@ import {BrowserGetTestability} from './browser/testability';
|
|||
import {Title} from './browser/title';
|
||||
import {ELEMENT_PROBE_PROVIDERS} from './dom/debug/ng_probe';
|
||||
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 {DomEventsPlugin} from './dom/events/dom_events';
|
||||
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: DomRootRenderer, useClass: DomRootRenderer_},
|
||||
{provide: RootRenderer, useExisting: DomRootRenderer},
|
||||
{provide: RENDERER_V2_DIRECT, useClass: DomRendererV2},
|
||||
{provide: RendererV2, useExisting: RENDERER_V2_DIRECT},
|
||||
DomRendererFactoryV2,
|
||||
{provide: RendererFactoryV2, useExisting: DomRendererFactoryV2},
|
||||
{provide: SharedStylesHost, useExisting: DomSharedStylesHost},
|
||||
{provide: AnimationDriver, useFactory: _resolveDefaultAnimationDriver},
|
||||
DomSharedStylesHost,
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
import * as core from '@angular/core';
|
||||
|
||||
import {StringMapWrapper} from '../../facade/collection';
|
||||
import {DebugDomRendererV2, DebugDomRootRenderer} from '../../private_import_core';
|
||||
import {DebugDomRootRenderer} from '../../private_import_core';
|
||||
import {getDOM} from '../dom_adapter';
|
||||
import {DomRootRenderer} from '../dom_renderer';
|
||||
import {DomRendererFactoryV2, DomRootRenderer} from '../dom_renderer';
|
||||
|
||||
const CORE_TOKENS = {
|
||||
'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), {});
|
||||
}
|
||||
|
||||
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`).
|
||||
*/
|
||||
|
@ -75,9 +71,4 @@ export const ELEMENT_PROBE_PROVIDERS: core.Provider[] = [
|
|||
[core.NgProbeToken, new core.Optional()],
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: core.RendererV2,
|
||||
useFactory: _createDebugRendererV2,
|
||||
deps: [core.RENDERER_V2_DIRECT],
|
||||
}
|
||||
];
|
|
@ -6,7 +6,7 @@
|
|||
* 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 {AnimationKeyframe, AnimationPlayer, AnimationStyles, DirectRenderer, NoOpAnimationPlayer, RenderDebugInfo} from '../private_import_core';
|
||||
|
@ -229,13 +229,8 @@ export class DomRenderer implements Renderer {
|
|||
TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(parsedBindings, null, 2));
|
||||
} 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;
|
||||
renderElement.setAttributeNode(attrNode);
|
||||
} else {
|
||||
this.setElementAttribute(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
propertyName = propertyName.replace(/\$/g, '_');
|
||||
this.setElementAttribute(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,10 +361,51 @@ function createAttributeNode(name: string): Attr {
|
|||
}
|
||||
|
||||
@Injectable()
|
||||
export class DomRendererV2 implements RendererV2 {
|
||||
constructor(private eventManager: EventManager){};
|
||||
export class DomRendererFactoryV2 implements RendererFactoryV2 {
|
||||
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) {
|
||||
return document.createElementNS(NAMESPACE_URIS[namespace], name);
|
||||
}
|
||||
|
@ -377,9 +413,9 @@ export class DomRendererV2 implements RendererV2 {
|
|||
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); }
|
||||
|
||||
|
@ -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) :
|
||||
selectorOrNode;
|
||||
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); }
|
||||
|
||||
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; }
|
||||
|
||||
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):
|
||||
() => void {
|
||||
|
@ -488,3 +487,62 @@ export class DomRendererV2 implements RendererV2 {
|
|||
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)));
|
||||
}
|
||||
}
|
|
@ -16,8 +16,6 @@ export const ReflectionCapabilities: typeof r.ReflectionCapabilities = r.Reflect
|
|||
|
||||
export type DebugDomRootRenderer = typeof 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;
|
||||
|
||||
|
|
|
@ -21,8 +21,6 @@ export type RenderDebugInfo = typeof r._RenderDebugInfo;
|
|||
export const RenderDebugInfo: typeof r.RenderDebugInfo = r.RenderDebugInfo;
|
||||
export type DebugDomRootRenderer = typeof 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 const ALLOW_MULTIPLE_PLATFORMS: typeof r.ALLOW_MULTIPLE_PLATFORMS =
|
||||
r.ALLOW_MULTIPLE_PLATFORMS;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import {PlatformLocation} from '@angular/common';
|
||||
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 {BrowserModule, DOCUMENT} from '@angular/platform-browser';
|
||||
|
||||
|
@ -16,9 +16,9 @@ import {SERVER_HTTP_PROVIDERS} from './http';
|
|||
import {ServerPlatformLocation} from './location';
|
||||
import {Parse5DomAdapter, parseDocument} from './parse5_adapter';
|
||||
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 {ServerRendererV2, ServerRootRenderer} from './server_renderer';
|
||||
import {ServerRendererFactoryV2, ServerRootRenderer} from './server_renderer';
|
||||
import {ServerStylesHost} from './styles_host';
|
||||
import {INITIAL_CONFIG, PlatformConfig} from './tokens';
|
||||
|
||||
|
@ -42,10 +42,6 @@ export function _createConditionalRootRenderer(rootRenderer: any) {
|
|||
return isDevMode() ? new DebugDomRootRenderer(rootRenderer) : rootRenderer;
|
||||
}
|
||||
|
||||
export function _createDebugRendererV2(renderer: RendererV2): RendererV2 {
|
||||
return isDevMode() ? new DebugDomRendererV2(renderer) : renderer;
|
||||
}
|
||||
|
||||
export function _addStylesToRootComponentFactory(stylesHost: ServerStylesHost) {
|
||||
const initializer = () => stylesHost.rootComponentIsReady();
|
||||
return initializer;
|
||||
|
@ -53,9 +49,9 @@ export function _addStylesToRootComponentFactory(stylesHost: ServerStylesHost) {
|
|||
|
||||
export const SERVER_RENDER_PROVIDERS: Provider[] = [
|
||||
ServerRootRenderer,
|
||||
{provide: RENDERER_V2_DIRECT, useClass: ServerRendererV2},
|
||||
{provide: RendererV2, useFactory: _createDebugRendererV2, deps: [RENDERER_V2_DIRECT]},
|
||||
{provide: RootRenderer, useFactory: _createConditionalRootRenderer, deps: [ServerRootRenderer]},
|
||||
ServerRendererFactoryV2,
|
||||
{provide: RendererFactoryV2, useExisting: ServerRendererFactoryV2},
|
||||
ServerStylesHost,
|
||||
{provide: SharedStylesHost, useExisting: ServerStylesHost},
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
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 {isBlank, isPresent, stringify} from './facade/lang';
|
||||
|
@ -204,6 +204,7 @@ export class ServerRenderer implements Renderer {
|
|||
renderElement,
|
||||
TEMPLATE_COMMENT_TEXT.replace('{}', JSON.stringify(parsedBindings, null, 2)));
|
||||
} else {
|
||||
propertyName = propertyName.replace(/\$/g, '_');
|
||||
this.setElementAttribute(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
}
|
||||
|
@ -262,8 +263,51 @@ function appendNodes(parent: any, nodes: any) {
|
|||
}
|
||||
|
||||
@Injectable()
|
||||
export class ServerRendererV2 implements RendererV2 {
|
||||
constructor(private ngZone: NgZone, @Inject(DOCUMENT) private document: any) {}
|
||||
export class ServerRendererFactoryV2 implements RendererFactoryV2 {
|
||||
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 {
|
||||
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); }
|
||||
|
||||
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); }
|
||||
|
||||
setText(node: any, value: string): void { getDOM().setText(node, value); }
|
||||
setValue(node: any, value: string): void { getDOM().setText(node, value); }
|
||||
|
||||
listen(
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
*/
|
||||
|
||||
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 {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 {TreeNode, emptyTree} from '../util';
|
||||
|
@ -89,14 +89,14 @@ function TreeComponent_0(): ViewDefinition {
|
|||
export class AppModule implements Injector {
|
||||
private sanitizer: DomSanitizerImpl;
|
||||
private componentFactory: ComponentFactory<TreeComponent>;
|
||||
private rendererV2: RendererV2;
|
||||
private rendererV2: RendererFactoryV2;
|
||||
|
||||
componentRef: ComponentRef<TreeComponent>;
|
||||
|
||||
constructor() {
|
||||
initServicesIfNeeded();
|
||||
this.sanitizer = new DomSanitizerImpl(document);
|
||||
this.rendererV2 = new DomRendererV2(null);
|
||||
this.rendererV2 = new DomRendererFactoryV2(null, null);
|
||||
trustedEmptyColor = this.sanitizer.bypassSecurityTrustStyle('');
|
||||
trustedGreyColor = this.sanitizer.bypassSecurityTrustStyle('grey');
|
||||
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 {
|
||||
switch (token) {
|
||||
case RendererV2:
|
||||
case RendererFactoryV2:
|
||||
return this.rendererV2;
|
||||
case Sanitizer:
|
||||
return this.sanitizer;
|
||||
|
|
|
@ -292,6 +292,16 @@ export declare abstract class ComponentRef<C> {
|
|||
abstract onDestroy(callback: Function): void;
|
||||
}
|
||||
|
||||
/** @experimental */
|
||||
export interface ComponentRenderTypeV2 {
|
||||
data: {
|
||||
[kind: string]: any[];
|
||||
};
|
||||
encapsulation: ViewEncapsulation;
|
||||
id: string;
|
||||
styles: (string | any[])[];
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
export declare const ContentChild: ContentChildDecorator;
|
||||
|
||||
|
@ -848,30 +858,32 @@ export declare abstract class Renderer {
|
|||
}
|
||||
|
||||
/** @experimental */
|
||||
export declare const RENDERER_V2_DIRECT: InjectionToken<RendererV2>;
|
||||
export declare abstract class RendererFactoryV2 {
|
||||
abstract createRenderer(hostElement: any, type: ComponentRenderTypeV2): RendererV2;
|
||||
}
|
||||
|
||||
/** @experimental */
|
||||
export declare abstract class RendererV2 {
|
||||
destroyNode: (node: any) => void | null;
|
||||
abstract addClass(el: any, name: string): void;
|
||||
abstract appendChild(parent: any, newChild: any): void;
|
||||
abstract createComment(value: string, debugInfo?: RenderDebugContext): any;
|
||||
abstract createElement(name: string, namespace?: string, debugInfo?: RenderDebugContext): any;
|
||||
abstract createText(value: string, debugInfo?: RenderDebugContext): any;
|
||||
abstract createComment(value: string): any;
|
||||
abstract createElement(name: string, namespace?: string): any;
|
||||
abstract createText(value: string): any;
|
||||
abstract destroy(): 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 nextSibling(node: any): any;
|
||||
abstract parentNode(node: any): any;
|
||||
abstract removeAttribute(el: any, name: string, namespace?: string): void;
|
||||
abstract removeBindingDebugInfo(el: any, propertyName: string): void;
|
||||
abstract removeChild(parent: any, oldChild: any): void;
|
||||
abstract removeClass(el: any, name: string): 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 setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void;
|
||||
abstract setProperty(el: any, name: string, value: any): 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 */
|
||||
|
|
Loading…
Reference in New Issue