fix: make all tests green with new view engine and JIT
Note that this does not yet include enabling the view engine by default. Included refactoring: - view engine: split namespace of elements / attributes already when creating the `NodeDef` - view engine: when injecting the old `Renderer`, use an implementation that is based on `RendererV2` - view engine: store view queries in the component view, not on the host element
This commit is contained in:
parent
74ce121dba
commit
b9f17a9cb2
@ -13,9 +13,14 @@ export function main() {
|
|||||||
describe('binding to CSS class list', () => {
|
describe('binding to CSS class list', () => {
|
||||||
let fixture: ComponentFixture<any>;
|
let fixture: ComponentFixture<any>;
|
||||||
|
|
||||||
|
function normalizeClassNames(classes: string) {
|
||||||
|
return classes.trim().split(' ').sort().join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
function detectChangesAndExpectClassName(classes: string): void {
|
function detectChangesAndExpectClassName(classes: string): void {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(fixture.debugElement.children[0].nativeElement.className.trim()).toEqual(classes);
|
let nonNormalizedClassName = fixture.debugElement.children[0].nativeElement.className;
|
||||||
|
expect(normalizeClassNames(nonNormalizedClassName)).toEqual(normalizeClassNames(classes));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getComponent(): TestComponent { return fixture.debugElement.componentInstance; }
|
function getComponent(): TestComponent { return fixture.debugElement.componentInstance; }
|
||||||
|
@ -68,9 +68,9 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
|
|||||||
const expressionParser = new Parser(new Lexer());
|
const expressionParser = new Parser(new Lexer());
|
||||||
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
||||||
const tmplParser =
|
const tmplParser =
|
||||||
new TemplateParser(expressionParser, elementSchemaRegistry, htmlParser, console, []);
|
new TemplateParser(config, expressionParser, elementSchemaRegistry, htmlParser, console, []);
|
||||||
const resolver = new CompileMetadataResolver(
|
const resolver = new CompileMetadataResolver(
|
||||||
new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
config, new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
||||||
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
|
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
|
||||||
symbolCache, staticReflector);
|
symbolCache, staticReflector);
|
||||||
// TODO(vicb): do not pass options.i18nFormat here
|
// TODO(vicb): do not pass options.i18nFormat here
|
||||||
|
@ -26,17 +26,19 @@ export class CompilerConfig {
|
|||||||
private _genDebugInfo: boolean;
|
private _genDebugInfo: boolean;
|
||||||
private _logBindingUpdate: boolean;
|
private _logBindingUpdate: boolean;
|
||||||
public useJit: boolean;
|
public useJit: boolean;
|
||||||
|
public useViewEngine: boolean;
|
||||||
public missingTranslation: MissingTranslationStrategy;
|
public missingTranslation: MissingTranslationStrategy;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{renderTypes = new DefaultRenderTypes(), defaultEncapsulation = ViewEncapsulation.Emulated,
|
{renderTypes = new DefaultRenderTypes(), defaultEncapsulation = ViewEncapsulation.Emulated,
|
||||||
genDebugInfo, logBindingUpdate, useJit = true, missingTranslation}: {
|
genDebugInfo, logBindingUpdate, useJit = true, missingTranslation, useViewEngine}: {
|
||||||
renderTypes?: RenderTypes,
|
renderTypes?: RenderTypes,
|
||||||
defaultEncapsulation?: ViewEncapsulation,
|
defaultEncapsulation?: ViewEncapsulation,
|
||||||
genDebugInfo?: boolean,
|
genDebugInfo?: boolean,
|
||||||
logBindingUpdate?: boolean,
|
logBindingUpdate?: boolean,
|
||||||
useJit?: boolean,
|
useJit?: boolean,
|
||||||
missingTranslation?: MissingTranslationStrategy,
|
missingTranslation?: MissingTranslationStrategy,
|
||||||
|
useViewEngine?: boolean
|
||||||
} = {}) {
|
} = {}) {
|
||||||
this.renderTypes = renderTypes;
|
this.renderTypes = renderTypes;
|
||||||
this.defaultEncapsulation = defaultEncapsulation;
|
this.defaultEncapsulation = defaultEncapsulation;
|
||||||
@ -44,6 +46,7 @@ export class CompilerConfig {
|
|||||||
this._logBindingUpdate = logBindingUpdate;
|
this._logBindingUpdate = logBindingUpdate;
|
||||||
this.useJit = useJit;
|
this.useJit = useJit;
|
||||||
this.missingTranslation = missingTranslation;
|
this.missingTranslation = missingTranslation;
|
||||||
|
this.useViewEngine = useViewEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
get genDebugInfo(): boolean {
|
get genDebugInfo(): boolean {
|
||||||
|
@ -357,7 +357,8 @@ function parseHostBindings(
|
|||||||
const sourceSpan = new ParseSourceSpan(
|
const sourceSpan = new ParseSourceSpan(
|
||||||
new ParseLocation(sourceFile, null, null, null),
|
new ParseLocation(sourceFile, null, null, null),
|
||||||
new ParseLocation(sourceFile, null, null, null));
|
new ParseLocation(sourceFile, null, null, null));
|
||||||
const parsedHostProps = parser.createDirectiveHostPropertyAsts(dirMeta.toSummary(), sourceSpan);
|
const parsedHostProps =
|
||||||
|
parser.createDirectiveHostPropertyAsts(dirMeta.toSummary(), dirMeta.selector, sourceSpan);
|
||||||
const parsedHostListeners = parser.createDirectiveHostEventAsts(dirMeta.toSummary(), sourceSpan);
|
const parsedHostListeners = parser.createDirectiveHostEventAsts(dirMeta.toSummary(), sourceSpan);
|
||||||
|
|
||||||
return new ParseResult(parsedHostProps, parsedHostListeners, errors);
|
return new ParseResult(parsedHostProps, parsedHostListeners, errors);
|
||||||
|
@ -107,7 +107,7 @@ export class Extractor {
|
|||||||
{get: (url: string) => host.loadResource(url)}, urlResolver, htmlParser, config);
|
{get: (url: string) => host.loadResource(url)}, urlResolver, htmlParser, config);
|
||||||
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
||||||
const resolver = new CompileMetadataResolver(
|
const resolver = new CompileMetadataResolver(
|
||||||
new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
config, new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
||||||
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
|
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
|
||||||
symbolCache, staticReflector);
|
symbolCache, staticReflector);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import {Compiler, ComponentFactory, ComponentRenderTypeV2, Inject, Injector, Mod
|
|||||||
import {AnimationCompiler} from '../animation/animation_compiler';
|
import {AnimationCompiler} from '../animation/animation_compiler';
|
||||||
import {AnimationParser} from '../animation/animation_parser';
|
import {AnimationParser} from '../animation/animation_parser';
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, ProviderMeta, ProxyClass, createHostComponentMeta, identifierName} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, ProviderMeta, ProxyClass, createHostComponentMeta, identifierName} from '../compile_metadata';
|
||||||
import {CompilerConfig, USE_VIEW_ENGINE} from '../config';
|
import {CompilerConfig} from '../config';
|
||||||
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
||||||
import {stringify} from '../facade/lang';
|
import {stringify} from '../facade/lang';
|
||||||
import {CompilerInjectable} from '../injectable';
|
import {CompilerInjectable} from '../injectable';
|
||||||
@ -50,8 +50,7 @@ export class JitCompiler implements Compiler {
|
|||||||
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
|
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
|
||||||
private _viewCompiler: ViewCompiler, private _ngModuleCompiler: NgModuleCompiler,
|
private _viewCompiler: ViewCompiler, private _ngModuleCompiler: NgModuleCompiler,
|
||||||
private _directiveWrapperCompiler: DirectiveWrapperCompiler,
|
private _directiveWrapperCompiler: DirectiveWrapperCompiler,
|
||||||
private _compilerConfig: CompilerConfig, private _animationParser: AnimationParser,
|
private _compilerConfig: CompilerConfig, private _animationParser: AnimationParser) {}
|
||||||
@Inject(USE_VIEW_ENGINE) private _useViewEngine: boolean) {}
|
|
||||||
|
|
||||||
get injector(): Injector { return this._injector; }
|
get injector(): Injector { return this._injector; }
|
||||||
|
|
||||||
@ -245,7 +244,7 @@ export class JitCompiler implements Compiler {
|
|||||||
|
|
||||||
private _compileDirectiveWrapper(
|
private _compileDirectiveWrapper(
|
||||||
dirMeta: CompileDirectiveMetadata, moduleMeta: CompileNgModuleMetadata): void {
|
dirMeta: CompileDirectiveMetadata, moduleMeta: CompileNgModuleMetadata): void {
|
||||||
if (this._useViewEngine) {
|
if (this._compilerConfig.useViewEngine) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const compileResult = this._directiveWrapperCompiler.compile(dirMeta);
|
const compileResult = this._directiveWrapperCompiler.compile(dirMeta);
|
||||||
|
@ -43,9 +43,8 @@ const _NO_RESOURCE_LOADER: ResourceLoader = {
|
|||||||
|
|
||||||
const baseHtmlParser = new InjectionToken('HtmlParser');
|
const baseHtmlParser = new InjectionToken('HtmlParser');
|
||||||
|
|
||||||
function viewCompilerFactory(
|
function viewCompilerFactory(cc: CompilerConfig, sr: ElementSchemaRegistry) {
|
||||||
useViewEngine: boolean, cc: CompilerConfig, sr: ElementSchemaRegistry) {
|
return cc.useViewEngine ? new ViewCompilerNext(cc, sr) : new ViewCompiler(cc, sr);
|
||||||
return useViewEngine ? new ViewCompilerNext(cc, sr) : new ViewCompiler(cc, sr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,7 +90,7 @@ export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> =
|
|||||||
{
|
{
|
||||||
provide: ViewCompiler,
|
provide: ViewCompiler,
|
||||||
useFactory: viewCompilerFactory,
|
useFactory: viewCompilerFactory,
|
||||||
deps: [USE_VIEW_ENGINE, CompilerConfig, ElementSchemaRegistry]
|
deps: [CompilerConfig, ElementSchemaRegistry]
|
||||||
},
|
},
|
||||||
NgModuleCompiler,
|
NgModuleCompiler,
|
||||||
DirectiveWrapperCompiler,
|
DirectiveWrapperCompiler,
|
||||||
@ -124,7 +123,7 @@ export class JitCompilerFactory implements CompilerFactory {
|
|||||||
const injector = ReflectiveInjector.resolveAndCreate([
|
const injector = ReflectiveInjector.resolveAndCreate([
|
||||||
COMPILER_PROVIDERS, {
|
COMPILER_PROVIDERS, {
|
||||||
provide: CompilerConfig,
|
provide: CompilerConfig,
|
||||||
useFactory: () => {
|
useFactory: (useViewEngine: boolean) => {
|
||||||
return new CompilerConfig({
|
return new CompilerConfig({
|
||||||
// let explicit values from the compiler options overwrite options
|
// let explicit values from the compiler options overwrite options
|
||||||
// from the app providers. E.g. important for the testing platform.
|
// from the app providers. E.g. important for the testing platform.
|
||||||
@ -136,10 +135,10 @@ export class JitCompilerFactory implements CompilerFactory {
|
|||||||
// from the app providers
|
// from the app providers
|
||||||
defaultEncapsulation: opts.defaultEncapsulation,
|
defaultEncapsulation: opts.defaultEncapsulation,
|
||||||
logBindingUpdate: opts.useDebug,
|
logBindingUpdate: opts.useDebug,
|
||||||
missingTranslation: opts.missingTranslation,
|
missingTranslation: opts.missingTranslation, useViewEngine
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
deps: []
|
deps: [USE_VIEW_ENGINE]
|
||||||
},
|
},
|
||||||
opts.providers
|
opts.providers
|
||||||
]);
|
]);
|
||||||
|
@ -12,7 +12,7 @@ import {StaticSymbol, StaticSymbolCache} from './aot/static_symbol';
|
|||||||
import {ngfactoryFilePath} from './aot/util';
|
import {ngfactoryFilePath} from './aot/util';
|
||||||
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
||||||
import * as cpl from './compile_metadata';
|
import * as cpl from './compile_metadata';
|
||||||
import {USE_VIEW_ENGINE} from './config';
|
import {CompilerConfig} from './config';
|
||||||
import {DirectiveNormalizer} from './directive_normalizer';
|
import {DirectiveNormalizer} from './directive_normalizer';
|
||||||
import {DirectiveResolver} from './directive_resolver';
|
import {DirectiveResolver} from './directive_resolver';
|
||||||
import {stringify} from './facade/lang';
|
import {stringify} from './facade/lang';
|
||||||
@ -48,14 +48,14 @@ export class CompileMetadataResolver {
|
|||||||
private _ngModuleOfTypes = new Map<Type<any>, Type<any>>();
|
private _ngModuleOfTypes = new Map<Type<any>, Type<any>>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _ngModuleResolver: NgModuleResolver, private _directiveResolver: DirectiveResolver,
|
private _config: CompilerConfig, private _ngModuleResolver: NgModuleResolver,
|
||||||
private _pipeResolver: PipeResolver, private _summaryResolver: SummaryResolver<any>,
|
private _directiveResolver: DirectiveResolver, private _pipeResolver: PipeResolver,
|
||||||
|
private _summaryResolver: SummaryResolver<any>,
|
||||||
private _schemaRegistry: ElementSchemaRegistry,
|
private _schemaRegistry: ElementSchemaRegistry,
|
||||||
private _directiveNormalizer: DirectiveNormalizer,
|
private _directiveNormalizer: DirectiveNormalizer,
|
||||||
@Optional() private _staticSymbolCache: StaticSymbolCache,
|
@Optional() private _staticSymbolCache: StaticSymbolCache,
|
||||||
private _reflector: ReflectorReader = reflector,
|
private _reflector: ReflectorReader = reflector,
|
||||||
@Optional() @Inject(ERROR_COLLECTOR_TOKEN) private _errorCollector?: ErrorCollector,
|
@Optional() @Inject(ERROR_COLLECTOR_TOKEN) private _errorCollector?: ErrorCollector) {}
|
||||||
@Optional() @Inject(USE_VIEW_ENGINE) private _useViewEngine?: boolean) {}
|
|
||||||
|
|
||||||
clearCacheFor(type: Type<any>) {
|
clearCacheFor(type: Type<any>) {
|
||||||
const dirMeta = this._directiveCache.get(type);
|
const dirMeta = this._directiveCache.get(type);
|
||||||
@ -148,7 +148,7 @@ export class CompileMetadataResolver {
|
|||||||
ngfactoryFilePath(dirType.filePath), cpl.componentFactoryName(dirType));
|
ngfactoryFilePath(dirType.filePath), cpl.componentFactoryName(dirType));
|
||||||
} else {
|
} else {
|
||||||
const hostView = this.getHostComponentViewClass(dirType);
|
const hostView = this.getHostComponentViewClass(dirType);
|
||||||
if (this._useViewEngine) {
|
if (this._config.useViewEngine) {
|
||||||
return viewEngine.createComponentFactory(selector, dirType, <any>hostView);
|
return viewEngine.createComponentFactory(selector, dirType, <any>hostView);
|
||||||
} else {
|
} else {
|
||||||
return new ComponentFactory(selector, <any>hostView, dirType);
|
return new ComponentFactory(selector, <any>hostView, dirType);
|
||||||
|
@ -62,8 +62,9 @@ export class BindingParser {
|
|||||||
|
|
||||||
getUsedPipes(): CompilePipeSummary[] { return Array.from(this._usedPipes.values()); }
|
getUsedPipes(): CompilePipeSummary[] { return Array.from(this._usedPipes.values()); }
|
||||||
|
|
||||||
createDirectiveHostPropertyAsts(dirMeta: CompileDirectiveSummary, sourceSpan: ParseSourceSpan):
|
createDirectiveHostPropertyAsts(
|
||||||
BoundElementPropertyAst[] {
|
dirMeta: CompileDirectiveSummary, elementSelector: string,
|
||||||
|
sourceSpan: ParseSourceSpan): BoundElementPropertyAst[] {
|
||||||
if (dirMeta.hostProperties) {
|
if (dirMeta.hostProperties) {
|
||||||
const boundProps: BoundProperty[] = [];
|
const boundProps: BoundProperty[] = [];
|
||||||
Object.keys(dirMeta.hostProperties).forEach(propName => {
|
Object.keys(dirMeta.hostProperties).forEach(propName => {
|
||||||
@ -76,7 +77,7 @@ export class BindingParser {
|
|||||||
sourceSpan);
|
sourceSpan);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return boundProps.map((prop) => this.createElementPropertyAst(dirMeta.selector, prop));
|
return boundProps.map((prop) => this.createElementPropertyAst(elementSelector, prop));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
import {Inject, InjectionToken, Optional, SchemaMetadata} from '@angular/core';
|
import {Inject, InjectionToken, Optional, SchemaMetadata} from '@angular/core';
|
||||||
|
|
||||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CompileTemplateSummary, CompileTokenMetadata, CompileTypeMetadata, identifierName} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CompileTemplateSummary, CompileTokenMetadata, CompileTypeMetadata, identifierName} from '../compile_metadata';
|
||||||
|
import {CompilerConfig} from '../config';
|
||||||
import {AST, ASTWithSource, EmptyExpr} from '../expression_parser/ast';
|
import {AST, ASTWithSource, EmptyExpr} from '../expression_parser/ast';
|
||||||
import {Parser} from '../expression_parser/parser';
|
import {Parser} from '../expression_parser/parser';
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
@ -33,6 +34,7 @@ import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventA
|
|||||||
import {PreparsedElementType, preparseElement} from './template_preparser';
|
import {PreparsedElementType, preparseElement} from './template_preparser';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Group 1 = "bind-"
|
// Group 1 = "bind-"
|
||||||
// Group 2 = "let-"
|
// Group 2 = "let-"
|
||||||
// Group 3 = "ref-/#"
|
// Group 3 = "ref-/#"
|
||||||
@ -88,8 +90,9 @@ export class TemplateParseResult {
|
|||||||
@CompilerInjectable()
|
@CompilerInjectable()
|
||||||
export class TemplateParser {
|
export class TemplateParser {
|
||||||
constructor(
|
constructor(
|
||||||
private _exprParser: Parser, private _schemaRegistry: ElementSchemaRegistry,
|
private _config: CompilerConfig, private _exprParser: Parser,
|
||||||
private _htmlParser: I18NHtmlParser, private _console: Console,
|
private _schemaRegistry: ElementSchemaRegistry, private _htmlParser: I18NHtmlParser,
|
||||||
|
private _console: Console,
|
||||||
@Optional() @Inject(TEMPLATE_TRANSFORMS) public transforms: TemplateAstVisitor[]) {}
|
@Optional() @Inject(TEMPLATE_TRANSFORMS) public transforms: TemplateAstVisitor[]) {}
|
||||||
|
|
||||||
parse(
|
parse(
|
||||||
@ -144,8 +147,8 @@ export class TemplateParser {
|
|||||||
const bindingParser = new BindingParser(
|
const bindingParser = new BindingParser(
|
||||||
this._exprParser, interpolationConfig, this._schemaRegistry, uniqPipes, errors);
|
this._exprParser, interpolationConfig, this._schemaRegistry, uniqPipes, errors);
|
||||||
const parseVisitor = new TemplateParseVisitor(
|
const parseVisitor = new TemplateParseVisitor(
|
||||||
providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry, schemas,
|
this._config, providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry,
|
||||||
errors);
|
schemas, errors);
|
||||||
result = html.visitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
|
result = html.visitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
|
||||||
errors.push(...providerViewContext.errors);
|
errors.push(...providerViewContext.errors);
|
||||||
usedPipes.push(...bindingParser.getUsedPipes());
|
usedPipes.push(...bindingParser.getUsedPipes());
|
||||||
@ -211,9 +214,10 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
contentQueryStartId: number;
|
contentQueryStartId: number;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public providerViewContext: ProviderViewContext, directives: CompileDirectiveSummary[],
|
private config: CompilerConfig, public providerViewContext: ProviderViewContext,
|
||||||
private _bindingParser: BindingParser, private _schemaRegistry: ElementSchemaRegistry,
|
directives: CompileDirectiveSummary[], private _bindingParser: BindingParser,
|
||||||
private _schemas: SchemaMetadata[], private _targetErrors: TemplateParseError[]) {
|
private _schemaRegistry: ElementSchemaRegistry, private _schemas: SchemaMetadata[],
|
||||||
|
private _targetErrors: TemplateParseError[]) {
|
||||||
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
||||||
this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1;
|
this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1;
|
||||||
directives.forEach((directive, index) => {
|
directives.forEach((directive, index) => {
|
||||||
@ -574,8 +578,8 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
component = directive;
|
component = directive;
|
||||||
}
|
}
|
||||||
const directiveProperties: BoundDirectivePropertyAst[] = [];
|
const directiveProperties: BoundDirectivePropertyAst[] = [];
|
||||||
let hostProperties =
|
let hostProperties = this._bindingParser.createDirectiveHostPropertyAsts(
|
||||||
this._bindingParser.createDirectiveHostPropertyAsts(directive, sourceSpan);
|
directive, this.config.useViewEngine ? elementName : directive.selector, sourceSpan);
|
||||||
// Note: We need to check the host properties here as well,
|
// Note: We need to check the host properties here as well,
|
||||||
// as we don't know the element name in the DirectiveWrapperCompiler yet.
|
// as we don't know the element name in the DirectiveWrapperCompiler yet.
|
||||||
hostProperties = this._checkPropertiesInSchema(elementName, hostProperties);
|
hostProperties = this._checkPropertiesInSchema(elementName, hostProperties);
|
||||||
|
@ -61,13 +61,14 @@ export class ViewCompilerNext extends ViewCompiler {
|
|||||||
const viewBuilderFactory = (parent: ViewBuilder): ViewBuilder => {
|
const viewBuilderFactory = (parent: ViewBuilder): ViewBuilder => {
|
||||||
const embeddedViewIndex = embeddedViewCount++;
|
const embeddedViewIndex = embeddedViewCount++;
|
||||||
const viewName = viewClassName(component.type.reference, embeddedViewIndex);
|
const viewName = viewClassName(component.type.reference, embeddedViewIndex);
|
||||||
return new ViewBuilder(parent, viewName, usedPipes, staticQueryIds, viewBuilderFactory);
|
return new ViewBuilder(
|
||||||
|
parent, component, viewName, usedPipes, staticQueryIds, viewBuilderFactory);
|
||||||
};
|
};
|
||||||
|
|
||||||
const visitor = viewBuilderFactory(null);
|
const visitor = viewBuilderFactory(null);
|
||||||
visitor.visitAll([], template);
|
visitor.visitAll([], template);
|
||||||
|
|
||||||
statements.push(...visitor.build(component));
|
statements.push(...visitor.build());
|
||||||
|
|
||||||
return new ViewCompileResult(statements, visitor.viewName, renderComponentVar.name, []);
|
return new ViewCompileResult(statements, visitor.viewName, renderComponentVar.name, []);
|
||||||
}
|
}
|
||||||
@ -107,7 +108,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
|
|||||||
private handleEventExpressions: HandleEventExpression[] = [];
|
private handleEventExpressions: HandleEventExpression[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private parent: ViewBuilder, public viewName: string, private usedPipes: CompilePipeSummary[],
|
private parent: ViewBuilder, private component: CompileDirectiveMetadata,
|
||||||
|
public viewName: string, private usedPipes: CompilePipeSummary[],
|
||||||
private staticQueryIds: Map<TemplateAst, StaticAndDynamicQueryIds>,
|
private staticQueryIds: Map<TemplateAst, StaticAndDynamicQueryIds>,
|
||||||
private viewBuilderFactory: ViewBuilderFactory) {}
|
private viewBuilderFactory: ViewBuilderFactory) {}
|
||||||
|
|
||||||
@ -122,6 +124,25 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.parent) {
|
||||||
|
const queryIds = staticViewQueryIds(this.staticQueryIds);
|
||||||
|
this.component.viewQueries.forEach((query, queryIndex) => {
|
||||||
|
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
||||||
|
const queryId = queryIndex + 1;
|
||||||
|
const bindingType =
|
||||||
|
query.first ? viewEngine.QueryBindingType.First : viewEngine.QueryBindingType.All;
|
||||||
|
let flags = viewEngine.NodeFlags.HasViewQuery;
|
||||||
|
if (queryIds.staticQueryIds.has(queryId)) {
|
||||||
|
flags |= viewEngine.NodeFlags.HasStaticQuery;
|
||||||
|
} else {
|
||||||
|
flags |= viewEngine.NodeFlags.HasDynamicQuery;
|
||||||
|
}
|
||||||
|
this.nodeDefs.push(o.importExpr(createIdentifier(Identifiers.queryDef)).callFn([
|
||||||
|
o.literal(flags), o.literal(queryId),
|
||||||
|
new o.LiteralMapExpr([new o.LiteralMapEntry(query.propertyName, o.literal(bindingType))])
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
}
|
||||||
templateVisitAll(this, astNodes);
|
templateVisitAll(this, astNodes);
|
||||||
if (astNodes.length === 0 ||
|
if (astNodes.length === 0 ||
|
||||||
(this.parent && needsAdditionalRootNode(astNodes[astNodes.length - 1]))) {
|
(this.parent && needsAdditionalRootNode(astNodes[astNodes.length - 1]))) {
|
||||||
@ -133,9 +154,9 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build(component: CompileDirectiveMetadata, targetStatements: o.Statement[] = []): o.Statement[] {
|
build(targetStatements: o.Statement[] = []): o.Statement[] {
|
||||||
const compType = o.importType(component.type);
|
const compType = o.importType(this.component.type);
|
||||||
this.children.forEach((child) => { child.build(component, targetStatements); });
|
this.children.forEach((child) => child.build(targetStatements));
|
||||||
|
|
||||||
const updateDirectivesFn = this._createUpdateFn(this.updateDirectivesExpressions, compType);
|
const updateDirectivesFn = this._createUpdateFn(this.updateDirectivesExpressions, compType);
|
||||||
const updateRendererFn = this._createUpdateFn(this.updateRendererExpressions, compType);
|
const updateRendererFn = this._createUpdateFn(this.updateRendererExpressions, compType);
|
||||||
@ -174,7 +195,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
|
|||||||
}
|
}
|
||||||
|
|
||||||
let viewFlags = viewEngine.ViewFlags.None;
|
let viewFlags = viewEngine.ViewFlags.None;
|
||||||
if (!this.parent && component.changeDetection === ChangeDetectionStrategy.OnPush) {
|
if (!this.parent && this.component.changeDetection === ChangeDetectionStrategy.OnPush) {
|
||||||
viewFlags |= viewEngine.ViewFlags.OnPush;
|
viewFlags |= viewEngine.ViewFlags.OnPush;
|
||||||
}
|
}
|
||||||
const viewFactory = new o.DeclareFunctionStmt(
|
const viewFactory = new o.DeclareFunctionStmt(
|
||||||
@ -272,31 +293,36 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
|
|||||||
// reserve the space in the nodeDefs array so we can add children
|
// reserve the space in the nodeDefs array so we can add children
|
||||||
this.nodeDefs.push(null);
|
this.nodeDefs.push(null);
|
||||||
|
|
||||||
let {flags, usedEvents, queryMatchesExpr, hostBindings} =
|
|
||||||
this._visitElementOrTemplate(nodeIndex, ast);
|
|
||||||
|
|
||||||
templateVisitAll(this, ast.children);
|
|
||||||
|
|
||||||
ast.inputs.forEach(
|
|
||||||
(inputAst) => { hostBindings.push({context: COMP_VAR, value: inputAst.value}); });
|
|
||||||
this._addUpdateExpressions(nodeIndex, hostBindings, this.updateRendererExpressions);
|
|
||||||
|
|
||||||
const inputDefs = elementBindingDefs(ast.inputs);
|
|
||||||
ast.directives.forEach(
|
|
||||||
(dirAst, dirIndex) => { inputDefs.push(...elementBindingDefs(dirAst.hostProperties)); });
|
|
||||||
const outputDefs = usedEvents.map(([target, eventName]) => {
|
|
||||||
return target ? o.literalArr([o.literal(target), o.literal(eventName)]) :
|
|
||||||
o.literal(eventName);
|
|
||||||
});
|
|
||||||
|
|
||||||
const childCount = this.nodeDefs.length - nodeIndex - 1;
|
|
||||||
|
|
||||||
let elName = ast.name;
|
let elName = ast.name;
|
||||||
if (ast.name === NG_CONTAINER_TAG) {
|
if (ast.name === NG_CONTAINER_TAG) {
|
||||||
// Using a null element name creates an anchor.
|
// Using a null element name creates an anchor.
|
||||||
elName = null;
|
elName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let {flags, usedEvents, queryMatchesExpr, hostBindings} =
|
||||||
|
this._visitElementOrTemplate(nodeIndex, ast);
|
||||||
|
|
||||||
|
let inputDefs: o.Expression[] = [];
|
||||||
|
let outputDefs: o.Expression[] = [];
|
||||||
|
if (elName) {
|
||||||
|
ast.inputs.forEach(
|
||||||
|
(inputAst) => { hostBindings.push({context: COMP_VAR, value: inputAst.value}); });
|
||||||
|
if (hostBindings.length) {
|
||||||
|
this._addUpdateExpressions(nodeIndex, hostBindings, this.updateRendererExpressions);
|
||||||
|
}
|
||||||
|
inputDefs = elementBindingDefs(ast.inputs);
|
||||||
|
ast.directives.forEach(
|
||||||
|
(dirAst, dirIndex) => inputDefs.push(...elementBindingDefs(dirAst.hostProperties)));
|
||||||
|
outputDefs = usedEvents.map(([target, eventName]) => {
|
||||||
|
return target ? o.literalArr([o.literal(target), o.literal(eventName)]) :
|
||||||
|
o.literal(eventName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
templateVisitAll(this, ast.children);
|
||||||
|
|
||||||
|
const childCount = this.nodeDefs.length - nodeIndex - 1;
|
||||||
|
|
||||||
// elementDef(
|
// elementDef(
|
||||||
// flags: NodeFlags, matchedQueries: [string, QueryValueType][], ngContentIndex: number,
|
// flags: NodeFlags, matchedQueries: [string, QueryValueType][], ngContentIndex: number,
|
||||||
// childCount: number, name: string, fixedAttrs: {[name: string]: string} = {},
|
// childCount: number, name: string, fixedAttrs: {[name: string]: string} = {},
|
||||||
@ -307,7 +333,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
|
|||||||
// outputs?: (string | [string, string])[]): NodeDef;
|
// outputs?: (string | [string, string])[]): NodeDef;
|
||||||
this.nodeDefs[nodeIndex] = o.importExpr(createIdentifier(Identifiers.elementDef)).callFn([
|
this.nodeDefs[nodeIndex] = o.importExpr(createIdentifier(Identifiers.elementDef)).callFn([
|
||||||
o.literal(flags), queryMatchesExpr, o.literal(ast.ngContentIndex), o.literal(childCount),
|
o.literal(flags), queryMatchesExpr, o.literal(ast.ngContentIndex), o.literal(childCount),
|
||||||
o.literal(elName), fixedAttrsDef(ast),
|
o.literal(elName), elName ? fixedAttrsDef(ast) : o.NULL_EXPR,
|
||||||
inputDefs.length ? o.literalArr(inputDefs) : o.NULL_EXPR,
|
inputDefs.length ? o.literalArr(inputDefs) : o.NULL_EXPR,
|
||||||
outputDefs.length ? o.literalArr(outputDefs) : o.NULL_EXPR
|
outputDefs.length ? o.literalArr(outputDefs) : o.NULL_EXPR
|
||||||
]);
|
]);
|
||||||
@ -422,22 +448,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
|
|||||||
// reserve the space in the nodeDefs array so we can add children
|
// reserve the space in the nodeDefs array so we can add children
|
||||||
this.nodeDefs.push(null);
|
this.nodeDefs.push(null);
|
||||||
|
|
||||||
directiveAst.directive.viewQueries.forEach((query, queryIndex) => {
|
|
||||||
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
|
||||||
const queryId = queryIndex + 1;
|
|
||||||
const bindingType =
|
|
||||||
query.first ? viewEngine.QueryBindingType.First : viewEngine.QueryBindingType.All;
|
|
||||||
let flags = viewEngine.NodeFlags.HasViewQuery;
|
|
||||||
if (queryIds.staticQueryIds.has(queryId)) {
|
|
||||||
flags |= viewEngine.NodeFlags.HasStaticQuery;
|
|
||||||
} else {
|
|
||||||
flags |= viewEngine.NodeFlags.HasDynamicQuery;
|
|
||||||
}
|
|
||||||
this.nodeDefs.push(o.importExpr(createIdentifier(Identifiers.queryDef)).callFn([
|
|
||||||
o.literal(flags), o.literal(queryId),
|
|
||||||
new o.LiteralMapExpr([new o.LiteralMapEntry(query.propertyName, o.literal(bindingType))])
|
|
||||||
]));
|
|
||||||
});
|
|
||||||
directiveAst.directive.queries.forEach((query, queryIndex) => {
|
directiveAst.directive.queries.forEach((query, queryIndex) => {
|
||||||
let flags = viewEngine.NodeFlags.HasContentQuery;
|
let flags = viewEngine.NodeFlags.HasContentQuery;
|
||||||
const queryId = directiveAst.contentQueryStartId + queryIndex;
|
const queryId = directiveAst.contentQueryStartId + queryIndex;
|
||||||
@ -493,7 +503,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
|
|||||||
outputDefs.push(new o.LiteralMapEntry(propName, o.literal(eventName), false));
|
outputDefs.push(new o.LiteralMapEntry(propName, o.literal(eventName), false));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (directiveAst.inputs.length) {
|
if (directiveAst.inputs.length ||
|
||||||
|
(flags & (viewEngine.NodeFlags.DoCheck | viewEngine.NodeFlags.OnInit)) > 0) {
|
||||||
this._addUpdateExpressions(
|
this._addUpdateExpressions(
|
||||||
nodeIndex,
|
nodeIndex,
|
||||||
directiveAst.inputs.map((input) => { return {context: COMP_VAR, value: input.value}; }),
|
directiveAst.inputs.map((input) => { return {context: COMP_VAR, value: input.value}; }),
|
||||||
@ -697,9 +708,6 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
|
|||||||
private _addUpdateExpressions(
|
private _addUpdateExpressions(
|
||||||
nodeIndex: number, expressions: {context: o.Expression, value: AST}[],
|
nodeIndex: number, expressions: {context: o.Expression, value: AST}[],
|
||||||
target: UpdateExpression[]) {
|
target: UpdateExpression[]) {
|
||||||
if (expressions.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const transformedExpressions = expressions.map(({context, value}) => {
|
const transformedExpressions = expressions.map(({context, value}) => {
|
||||||
if (value instanceof ASTWithSource) {
|
if (value instanceof ASTWithSource) {
|
||||||
value = value.ast;
|
value = value.ast;
|
||||||
@ -885,7 +893,7 @@ function elementBindingDefs(inputAsts: BoundElementPropertyAst[]): o.Expression[
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function fixedAttrsDef(elementAst: ElementAst): o.LiteralMapExpr {
|
function fixedAttrsDef(elementAst: ElementAst): o.Expression {
|
||||||
const mapResult: {[key: string]: string} = {};
|
const mapResult: {[key: string]: string} = {};
|
||||||
elementAst.attrs.forEach(attrAst => { mapResult[attrAst.name] = attrAst.value; });
|
elementAst.attrs.forEach(attrAst => { mapResult[attrAst.name] = attrAst.value; });
|
||||||
elementAst.directives.forEach(dirAst => {
|
elementAst.directives.forEach(dirAst => {
|
||||||
@ -898,10 +906,8 @@ function fixedAttrsDef(elementAst: ElementAst): o.LiteralMapExpr {
|
|||||||
const mapEntries: o.LiteralMapEntry[] = [];
|
const mapEntries: o.LiteralMapEntry[] = [];
|
||||||
// Note: We need to sort to get a defined output order
|
// Note: We need to sort to get a defined output order
|
||||||
// for tests and for caching generated artifacts...
|
// for tests and for caching generated artifacts...
|
||||||
Object.keys(mapResult).sort().forEach((attrName) => {
|
return o.literalArr(Object.keys(mapResult).sort().map(
|
||||||
mapEntries.push(new o.LiteralMapEntry(attrName, o.literal(mapResult[attrName]), true));
|
(attrName) => o.literalArr([o.literal(attrName), o.literal(mapResult[attrName])])));
|
||||||
});
|
|
||||||
return new o.LiteralMapExpr(mapEntries);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeAttributeValue(attrName: string, attrValue1: string, attrValue2: string): string {
|
function mergeAttributeValue(attrName: string, attrValue1: string, attrValue2: string): string {
|
||||||
@ -967,9 +973,21 @@ function findStaticQueryIds(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function staticViewQueryIds(nodeStaticQueryIds: Map<TemplateAst, StaticAndDynamicQueryIds>):
|
||||||
|
StaticAndDynamicQueryIds {
|
||||||
|
const staticQueryIds = new Set<number>();
|
||||||
|
const dynamicQueryIds = new Set<number>();
|
||||||
|
Array.from(nodeStaticQueryIds.values()).forEach((entry) => {
|
||||||
|
entry.staticQueryIds.forEach(queryId => staticQueryIds.add(queryId));
|
||||||
|
entry.dynamicQueryIds.forEach(queryId => dynamicQueryIds.add(queryId));
|
||||||
|
});
|
||||||
|
dynamicQueryIds.forEach(queryId => staticQueryIds.delete(queryId));
|
||||||
|
return {staticQueryIds, dynamicQueryIds};
|
||||||
|
}
|
||||||
|
|
||||||
function createComponentFactoryResolver(directives: DirectiveAst[]): ProviderAst {
|
function createComponentFactoryResolver(directives: DirectiveAst[]): ProviderAst {
|
||||||
const componentDirMeta = directives.find(dirAst => dirAst.directive.isComponent);
|
const componentDirMeta = directives.find(dirAst => dirAst.directive.isComponent);
|
||||||
if (componentDirMeta) {
|
if (componentDirMeta && componentDirMeta.directive.entryComponents.length) {
|
||||||
const entryComponentFactories = componentDirMeta.directive.entryComponents.map(
|
const entryComponentFactories = componentDirMeta.directive.entryComponents.map(
|
||||||
(entryComponent) => o.importExpr({reference: entryComponent.componentFactory}));
|
(entryComponent) => o.importExpr({reference: entryComponent.componentFactory}));
|
||||||
const cfrExpr = o.importExpr(createIdentifier(Identifiers.CodegenComponentFactoryResolver))
|
const cfrExpr = o.importExpr(createIdentifier(Identifiers.CodegenComponentFactoryResolver))
|
||||||
|
@ -92,8 +92,12 @@ export class ComponentRef_<C> extends ComponentRef<C> {
|
|||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class ComponentFactory<C> {
|
export class ComponentFactory<C> {
|
||||||
/** @internal */
|
/**
|
||||||
_viewClass: Type<AppView<any>>;
|
* TODO(tbosch): type this properly to ViewDefinitionFactory again once the view engine
|
||||||
|
* is the default.
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
_viewClass: any;
|
||||||
constructor(
|
constructor(
|
||||||
public selector: string, _viewClass: Type<AppView<any>>, public componentType: Type<any>) {
|
public selector: string, _viewClass: Type<AppView<any>>, public componentType: Type<any>) {
|
||||||
this._viewClass = _viewClass;
|
this._viewClass = _viewClass;
|
||||||
|
@ -10,7 +10,7 @@ import {isDevMode} from '../application_ref';
|
|||||||
import {SecurityContext} from '../security';
|
import {SecurityContext} from '../security';
|
||||||
|
|
||||||
import {BindingDef, BindingType, DebugContext, DisposableFn, ElementData, ElementOutputDef, NodeData, NodeDef, NodeFlags, NodeType, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, asElementData} from './types';
|
import {BindingDef, BindingType, DebugContext, DisposableFn, ElementData, ElementOutputDef, NodeData, NodeDef, NodeFlags, NodeType, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, asElementData} from './types';
|
||||||
import {checkAndUpdateBinding, dispatchEvent, elementEventFullName, filterQueryId, getParentRenderElement, resolveViewDefinition, sliceErrorStack, splitMatchedQueriesDsl} from './util';
|
import {checkAndUpdateBinding, dispatchEvent, elementEventFullName, filterQueryId, getParentRenderElement, resolveViewDefinition, sliceErrorStack, splitMatchedQueriesDsl, splitNamespace} from './util';
|
||||||
|
|
||||||
export function anchorDef(
|
export function anchorDef(
|
||||||
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
|
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
|
||||||
@ -36,6 +36,7 @@ export function anchorDef(
|
|||||||
bindings: [],
|
bindings: [],
|
||||||
disposableCount: 0,
|
disposableCount: 0,
|
||||||
element: {
|
element: {
|
||||||
|
ns: undefined,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
attrs: undefined,
|
attrs: undefined,
|
||||||
outputs: [], template, source,
|
outputs: [], template, source,
|
||||||
@ -54,8 +55,8 @@ export function anchorDef(
|
|||||||
|
|
||||||
export function elementDef(
|
export function elementDef(
|
||||||
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
|
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
|
||||||
ngContentIndex: number, childCount: number, name: string,
|
ngContentIndex: number, childCount: number, namespaceAndName: string,
|
||||||
fixedAttrs: {[name: string]: string} = {},
|
fixedAttrs: [string, string][] = [],
|
||||||
bindings?:
|
bindings?:
|
||||||
([BindingType.ElementClass, string] | [BindingType.ElementStyle, string, string] |
|
([BindingType.ElementClass, string] | [BindingType.ElementStyle, string, string] |
|
||||||
[BindingType.ElementAttribute | BindingType.ElementProperty, string, SecurityContext])[],
|
[BindingType.ElementAttribute | BindingType.ElementProperty, string, SecurityContext])[],
|
||||||
@ -63,13 +64,18 @@ export function elementDef(
|
|||||||
// skip the call to sliceErrorStack itself + the call to this function.
|
// skip the call to sliceErrorStack itself + the call to this function.
|
||||||
const source = isDevMode() ? sliceErrorStack(2, 3) : '';
|
const source = isDevMode() ? sliceErrorStack(2, 3) : '';
|
||||||
const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl);
|
const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl);
|
||||||
|
let ns: string;
|
||||||
|
let name: string;
|
||||||
|
if (namespaceAndName) {
|
||||||
|
[ns, name] = splitNamespace(namespaceAndName);
|
||||||
|
}
|
||||||
bindings = bindings || [];
|
bindings = bindings || [];
|
||||||
const bindingDefs: BindingDef[] = new Array(bindings.length);
|
const bindingDefs: BindingDef[] = new Array(bindings.length);
|
||||||
for (let i = 0; i < bindings.length; i++) {
|
for (let i = 0; i < bindings.length; i++) {
|
||||||
const entry = bindings[i];
|
const entry = bindings[i];
|
||||||
let bindingDef: BindingDef;
|
let bindingDef: BindingDef;
|
||||||
const bindingType = entry[0];
|
const bindingType = entry[0];
|
||||||
const name = entry[1];
|
const [ns, name] = splitNamespace(entry[1]);
|
||||||
let securityContext: SecurityContext;
|
let securityContext: SecurityContext;
|
||||||
let suffix: string;
|
let suffix: string;
|
||||||
switch (bindingType) {
|
switch (bindingType) {
|
||||||
@ -81,7 +87,7 @@ export function elementDef(
|
|||||||
securityContext = <SecurityContext>entry[2];
|
securityContext = <SecurityContext>entry[2];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bindingDefs[i] = {type: bindingType, name, nonMinifiedName: name, securityContext, suffix};
|
bindingDefs[i] = {type: bindingType, ns, name, nonMinifiedName: name, securityContext, suffix};
|
||||||
}
|
}
|
||||||
outputs = outputs || [];
|
outputs = outputs || [];
|
||||||
const outputDefs: ElementOutputDef[] = new Array(outputs.length);
|
const outputDefs: ElementOutputDef[] = new Array(outputs.length);
|
||||||
@ -96,6 +102,11 @@ export function elementDef(
|
|||||||
}
|
}
|
||||||
outputDefs[i] = {eventName: eventName, target: target};
|
outputDefs[i] = {eventName: eventName, target: target};
|
||||||
}
|
}
|
||||||
|
fixedAttrs = fixedAttrs || [];
|
||||||
|
const attrs = <[string, string, string][]>fixedAttrs.map(([namespaceAndName, value]) => {
|
||||||
|
const [ns, name] = splitNamespace(namespaceAndName);
|
||||||
|
return [ns, name, value];
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
type: NodeType.Element,
|
type: NodeType.Element,
|
||||||
// will bet set by the view definition
|
// will bet set by the view definition
|
||||||
@ -112,8 +123,9 @@ export function elementDef(
|
|||||||
bindings: bindingDefs,
|
bindings: bindingDefs,
|
||||||
disposableCount: outputDefs.length,
|
disposableCount: outputDefs.length,
|
||||||
element: {
|
element: {
|
||||||
|
ns,
|
||||||
name,
|
name,
|
||||||
attrs: fixedAttrs,
|
attrs,
|
||||||
outputs: outputDefs, source,
|
outputs: outputDefs, source,
|
||||||
template: undefined,
|
template: undefined,
|
||||||
// will bet set by the view definition
|
// will bet set by the view definition
|
||||||
@ -136,9 +148,7 @@ export function createElement(view: ViewData, renderHost: any, def: NodeDef): El
|
|||||||
let el: any;
|
let el: any;
|
||||||
if (view.parent || !rootSelectorOrNode) {
|
if (view.parent || !rootSelectorOrNode) {
|
||||||
if (elDef.name) {
|
if (elDef.name) {
|
||||||
// TODO(vicb): move the namespace to the node definition
|
el = renderer.createElement(elDef.name, elDef.ns);
|
||||||
const nsAndName = splitNamespace(elDef.name);
|
|
||||||
el = renderer.createElement(nsAndName[1], nsAndName[0]);
|
|
||||||
} else {
|
} else {
|
||||||
el = renderer.createComment('');
|
el = renderer.createComment('');
|
||||||
}
|
}
|
||||||
@ -150,10 +160,9 @@ export function createElement(view: ViewData, renderHost: any, def: NodeDef): El
|
|||||||
el = renderer.selectRootElement(rootSelectorOrNode);
|
el = renderer.selectRootElement(rootSelectorOrNode);
|
||||||
}
|
}
|
||||||
if (elDef.attrs) {
|
if (elDef.attrs) {
|
||||||
for (let attrName in elDef.attrs) {
|
for (let i = 0; i < elDef.attrs.length; i++) {
|
||||||
// TODO(vicb): move the namespace to the node definition
|
const [ns, name, value] = elDef.attrs[i];
|
||||||
const nsAndName = splitNamespace(attrName);
|
renderer.setAttribute(el, name, value, ns);
|
||||||
renderer.setAttribute(el, nsAndName[1], elDef.attrs[attrName], nsAndName[0]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (elDef.outputs.length) {
|
if (elDef.outputs.length) {
|
||||||
@ -217,11 +226,11 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const binding = def.bindings[bindingIdx];
|
const binding = def.bindings[bindingIdx];
|
||||||
const name = binding.name;
|
|
||||||
const renderNode = asElementData(view, def.index).renderElement;
|
const renderNode = asElementData(view, def.index).renderElement;
|
||||||
|
const name = binding.name;
|
||||||
switch (binding.type) {
|
switch (binding.type) {
|
||||||
case BindingType.ElementAttribute:
|
case BindingType.ElementAttribute:
|
||||||
setElementAttribute(view, binding, renderNode, name, value);
|
setElementAttribute(view, binding, renderNode, binding.ns, name, value);
|
||||||
break;
|
break;
|
||||||
case BindingType.ElementClass:
|
case BindingType.ElementClass:
|
||||||
setElementClass(view, renderNode, name, value);
|
setElementClass(view, renderNode, name, value);
|
||||||
@ -236,17 +245,15 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setElementAttribute(
|
function setElementAttribute(
|
||||||
view: ViewData, binding: BindingDef, renderNode: any, name: string, value: any) {
|
view: ViewData, binding: BindingDef, renderNode: any, ns: string, name: string, value: any) {
|
||||||
const securityContext = binding.securityContext;
|
const securityContext = binding.securityContext;
|
||||||
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
|
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
|
||||||
renderValue = renderValue != null ? renderValue.toString() : null;
|
renderValue = renderValue != null ? renderValue.toString() : null;
|
||||||
const renderer = view.renderer;
|
const renderer = view.renderer;
|
||||||
// TODO(vicb): move the namespace to the node definition
|
|
||||||
const nsAndName = splitNamespace(name);
|
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
renderer.setAttribute(renderNode, nsAndName[1], renderValue, nsAndName[0]);
|
renderer.setAttribute(renderNode, name, renderValue, ns);
|
||||||
} else {
|
} else {
|
||||||
renderer.removeAttribute(renderNode, nsAndName[1], nsAndName[0]);
|
renderer.removeAttribute(renderNode, name, ns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,13 +292,3 @@ function setElementProperty(
|
|||||||
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
|
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
|
||||||
view.renderer.setProperty(renderNode, name, renderValue);
|
view.renderer.setProperty(renderNode, name, renderValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
const NS_PREFIX_RE = /^:([^:]+):(.+)$/;
|
|
||||||
|
|
||||||
function splitNamespace(name: string): string[] {
|
|
||||||
if (name[0] === ':') {
|
|
||||||
const match = name.match(NS_PREFIX_RE);
|
|
||||||
return [match[1], match[2]];
|
|
||||||
}
|
|
||||||
return ['', name];
|
|
||||||
}
|
|
||||||
|
@ -11,10 +11,10 @@ export {ngContentDef} from './ng_content';
|
|||||||
export {directiveDef, pipeDef, providerDef} from './provider';
|
export {directiveDef, pipeDef, providerDef} from './provider';
|
||||||
export {pureArrayDef, pureObjectDef, purePipeDef} from './pure_expression';
|
export {pureArrayDef, pureObjectDef, purePipeDef} from './pure_expression';
|
||||||
export {queryDef} from './query';
|
export {queryDef} from './query';
|
||||||
export {createComponentFactory} from './refs';
|
export {ViewRef_, createComponentFactory, nodeValue} from './refs';
|
||||||
export {initServicesIfNeeded} from './services';
|
export {initServicesIfNeeded} from './services';
|
||||||
export {textDef} from './text';
|
export {textDef} from './text';
|
||||||
export {createComponentRenderTypeV2, elementEventFullName, nodeValue, rootRenderNodes, unwrapValue} from './util';
|
export {createComponentRenderTypeV2, elementEventFullName, rootRenderNodes, unwrapValue} from './util';
|
||||||
export {viewDef} from './view';
|
export {viewDef} from './view';
|
||||||
export {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';
|
export {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';
|
||||||
|
|
||||||
|
@ -12,9 +12,9 @@ import {ElementRef} from '../linker/element_ref';
|
|||||||
import {TemplateRef} from '../linker/template_ref';
|
import {TemplateRef} from '../linker/template_ref';
|
||||||
import {ViewContainerRef} from '../linker/view_container_ref';
|
import {ViewContainerRef} from '../linker/view_container_ref';
|
||||||
import {ViewEncapsulation} from '../metadata/view';
|
import {ViewEncapsulation} from '../metadata/view';
|
||||||
import {ComponentRenderTypeV2, RenderComponentType as RenderComponentTypeV1, Renderer as RendererV1, RendererFactoryV2, RendererV2, RootRenderer as RootRendererV1} from '../render/api';
|
import {ComponentRenderTypeV2, Renderer as RendererV1, RendererFactoryV2, RendererV2} from '../render/api';
|
||||||
|
|
||||||
import {createChangeDetectorRef, createInjector, createTemplateRef, createViewContainerRef} from './refs';
|
import {createChangeDetectorRef, createInjector, createRendererV1, createTemplateRef, createViewContainerRef} from './refs';
|
||||||
import {BindingDef, BindingType, DepDef, DepFlags, DirectiveOutputDef, DisposableFn, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderType, QueryBindingType, QueryDef, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewState, asElementData, asProviderData} from './types';
|
import {BindingDef, BindingType, DepDef, DepFlags, DirectiveOutputDef, DisposableFn, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderType, QueryBindingType, QueryDef, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewState, asElementData, asProviderData} from './types';
|
||||||
import {checkAndUpdateBinding, dispatchEvent, filterQueryId, isComponentView, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
|
import {checkAndUpdateBinding, dispatchEvent, filterQueryId, isComponentView, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
|
||||||
|
|
||||||
@ -40,6 +40,7 @@ export function directiveDef(
|
|||||||
bindings[bindingIndex] = {
|
bindings[bindingIndex] = {
|
||||||
type: BindingType.DirectiveProperty,
|
type: BindingType.DirectiveProperty,
|
||||||
name: prop, nonMinifiedName,
|
name: prop, nonMinifiedName,
|
||||||
|
ns: undefined,
|
||||||
securityContext: undefined,
|
securityContext: undefined,
|
||||||
suffix: undefined
|
suffix: undefined
|
||||||
};
|
};
|
||||||
@ -337,14 +338,7 @@ export function resolveDep(
|
|||||||
switch (tokenKey) {
|
switch (tokenKey) {
|
||||||
case RendererV1TokenKey: {
|
case RendererV1TokenKey: {
|
||||||
const compView = findCompView(view, elDef, allowPrivateServices);
|
const compView = findCompView(view, elDef, allowPrivateServices);
|
||||||
const compDef = compView.parentNodeDef;
|
return createRendererV1(compView);
|
||||||
const rootRendererV1: RootRendererV1 = view.root.injector.get(RootRendererV1);
|
|
||||||
|
|
||||||
// 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: {
|
case RendererV2TokenKey: {
|
||||||
const compView = findCompView(view, elDef, allowPrivateServices);
|
const compView = findCompView(view, elDef, allowPrivateServices);
|
||||||
|
@ -29,6 +29,7 @@ function _pureExpressionDef(type: PureExpressionType, propertyNames: string[]):
|
|||||||
bindings[i] = {
|
bindings[i] = {
|
||||||
type: BindingType.PureExpressionProperty,
|
type: BindingType.PureExpressionProperty,
|
||||||
name: prop,
|
name: prop,
|
||||||
|
ns: undefined,
|
||||||
nonMinifiedName: prop,
|
nonMinifiedName: prop,
|
||||||
securityContext: undefined,
|
securityContext: undefined,
|
||||||
suffix: undefined
|
suffix: undefined
|
||||||
|
@ -80,14 +80,14 @@ export function dirtyParentQueries(view: ViewData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// view queries
|
// view queries
|
||||||
let compDef = view.parentNodeDef;
|
if (view.def.nodeFlags & NodeFlags.HasViewQuery) {
|
||||||
view = view.parent;
|
for (let i = 0; i < view.def.nodes.length; i++) {
|
||||||
if (view) {
|
|
||||||
for (let i = compDef.index + 1; i <= compDef.index + compDef.childCount; i++) {
|
|
||||||
const nodeDef = view.def.nodes[i];
|
const nodeDef = view.def.nodes[i];
|
||||||
if ((nodeDef.flags & NodeFlags.HasViewQuery) && (nodeDef.flags & NodeFlags.HasDynamicQuery)) {
|
if ((nodeDef.flags & NodeFlags.HasViewQuery) && (nodeDef.flags & NodeFlags.HasDynamicQuery)) {
|
||||||
asQueryList(view, i).setDirty();
|
asQueryList(view, i).setDirty();
|
||||||
}
|
}
|
||||||
|
// only visit the root nodes
|
||||||
|
i += nodeDef.childCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,16 +97,16 @@ export function checkAndUpdateQuery(view: ViewData, nodeDef: NodeDef) {
|
|||||||
if (!queryList.dirty) {
|
if (!queryList.dirty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const providerDef = nodeDef.parent;
|
let directiveInstance: any;
|
||||||
const providerData = asProviderData(view, providerDef.index);
|
|
||||||
let newValues: any[];
|
let newValues: any[];
|
||||||
if (nodeDef.flags & NodeFlags.HasContentQuery) {
|
if (nodeDef.flags & NodeFlags.HasContentQuery) {
|
||||||
const elementDef = providerDef.parent;
|
const elementDef = nodeDef.parent.parent;
|
||||||
newValues = calcQueryValues(
|
newValues = calcQueryValues(
|
||||||
view, elementDef.index, elementDef.index + elementDef.childCount, nodeDef.query, []);
|
view, elementDef.index, elementDef.index + elementDef.childCount, nodeDef.query, []);
|
||||||
|
directiveInstance = asProviderData(view, nodeDef.parent.index).instance;
|
||||||
} else if (nodeDef.flags & NodeFlags.HasViewQuery) {
|
} else if (nodeDef.flags & NodeFlags.HasViewQuery) {
|
||||||
const compView = providerData.componentView;
|
newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query, []);
|
||||||
newValues = calcQueryValues(compView, 0, compView.def.nodes.length - 1, nodeDef.query, []);
|
directiveInstance = view.component;
|
||||||
}
|
}
|
||||||
queryList.reset(newValues);
|
queryList.reset(newValues);
|
||||||
const bindings = nodeDef.query.bindings;
|
const bindings = nodeDef.query.bindings;
|
||||||
@ -123,7 +123,7 @@ export function checkAndUpdateQuery(view: ViewData, nodeDef: NodeDef) {
|
|||||||
notify = true;
|
notify = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
providerData.instance[binding.propName] = boundValue;
|
directiveInstance[binding.propName] = boundValue;
|
||||||
}
|
}
|
||||||
if (notify) {
|
if (notify) {
|
||||||
queryList.notifyOnChanges();
|
queryList.notifyOnChanges();
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {NoOpAnimationPlayer} from '../animation/animation_player';
|
||||||
|
import {ApplicationRef} from '../application_ref';
|
||||||
import {ChangeDetectorRef} from '../change_detection/change_detection';
|
import {ChangeDetectorRef} from '../change_detection/change_detection';
|
||||||
import {Injector} from '../di';
|
import {Injector} from '../di';
|
||||||
import {ComponentFactory, ComponentRef} from '../linker/component_factory';
|
import {ComponentFactory, ComponentRef} from '../linker/component_factory';
|
||||||
@ -13,10 +15,12 @@ import {ElementRef} from '../linker/element_ref';
|
|||||||
import {TemplateRef} from '../linker/template_ref';
|
import {TemplateRef} from '../linker/template_ref';
|
||||||
import {ViewContainerRef} from '../linker/view_container_ref';
|
import {ViewContainerRef} from '../linker/view_container_ref';
|
||||||
import {EmbeddedViewRef, ViewRef} from '../linker/view_ref';
|
import {EmbeddedViewRef, ViewRef} from '../linker/view_ref';
|
||||||
|
import {Renderer as RendererV1, RendererV2} from '../render/api';
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
|
import {VERSION} from '../version';
|
||||||
|
|
||||||
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData} from './types';
|
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData, asTextData} from './types';
|
||||||
import {isComponentView, renderNode, resolveViewDefinition, rootRenderNodes, tokenKey, viewParentEl} from './util';
|
import {isComponentView, renderNode, resolveViewDefinition, rootRenderNodes, splitNamespace, tokenKey, viewParentEl} from './util';
|
||||||
|
|
||||||
const EMPTY_CONTEXT = new Object();
|
const EMPTY_CONTEXT = new Object();
|
||||||
|
|
||||||
@ -26,16 +30,9 @@ export function createComponentFactory(
|
|||||||
return new ComponentFactory_(selector, componentType, viewDefFactory);
|
return new ComponentFactory_(selector, componentType, viewDefFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComponentFactory_ implements ComponentFactory<any> {
|
class ComponentFactory_ extends ComponentFactory<any> {
|
||||||
/**
|
constructor(selector: string, componentType: Type<any>, viewDefFactory: ViewDefinitionFactory) {
|
||||||
* We are not renaming this field as the old ComponentFactory is using it.
|
super(selector, <any>viewDefFactory, componentType);
|
||||||
* @internal */
|
|
||||||
_viewClass: any;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public selector: string, public componentType: Type<any>,
|
|
||||||
_viewDefFactory: ViewDefinitionFactory) {
|
|
||||||
this._viewClass = _viewDefFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,13 +46,16 @@ class ComponentFactory_ implements ComponentFactory<any> {
|
|||||||
const view = Services.createRootView(
|
const view = Services.createRootView(
|
||||||
injector, projectableNodes || [], rootSelectorOrNode, viewDef, EMPTY_CONTEXT);
|
injector, projectableNodes || [], rootSelectorOrNode, viewDef, EMPTY_CONTEXT);
|
||||||
const component = asProviderData(view, componentNodeIndex).instance;
|
const component = asProviderData(view, componentNodeIndex).instance;
|
||||||
|
view.renderer.setAttribute(asElementData(view, 0).renderElement, 'ng-version', VERSION.full);
|
||||||
|
|
||||||
return new ComponentRef_(view, new ViewRef_(view), component);
|
return new ComponentRef_(view, new ViewRef_(view), component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComponentRef_ implements ComponentRef<any> {
|
class ComponentRef_ extends ComponentRef<any> {
|
||||||
private _elDef: NodeDef;
|
private _elDef: NodeDef;
|
||||||
constructor(private _view: ViewData, private _viewRef: ViewRef, private _component: any) {
|
constructor(private _view: ViewData, private _viewRef: ViewRef, private _component: any) {
|
||||||
|
super();
|
||||||
this._elDef = this._view.def.nodes[0];
|
this._elDef = this._view.def.nodes[0];
|
||||||
}
|
}
|
||||||
get location(): ElementRef {
|
get location(): ElementRef {
|
||||||
@ -103,7 +103,11 @@ class ViewContainerRef_ implements ViewContainerRef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get(index: number): ViewRef { return new ViewRef_(this._data.embeddedViews[index]); }
|
get(index: number): ViewRef {
|
||||||
|
const ref = new ViewRef_(this._data.embeddedViews[index]);
|
||||||
|
ref.attachToViewContainerRef(this);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
get length(): number { return this._data.embeddedViews.length; };
|
get length(): number { return this._data.embeddedViews.length; };
|
||||||
|
|
||||||
@ -124,8 +128,10 @@ class ViewContainerRef_ implements ViewContainerRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
insert(viewRef: ViewRef, index?: number): ViewRef {
|
insert(viewRef: ViewRef, index?: number): ViewRef {
|
||||||
const viewData = (<ViewRef_>viewRef)._view;
|
const viewRef_ = <ViewRef_>viewRef;
|
||||||
|
const viewData = viewRef_._view;
|
||||||
Services.attachEmbeddedView(this._data, index, viewData);
|
Services.attachEmbeddedView(this._data, index, viewData);
|
||||||
|
viewRef_.attachToViewContainerRef(this);
|
||||||
return viewRef;
|
return viewRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +153,7 @@ class ViewContainerRef_ implements ViewContainerRef {
|
|||||||
detach(index?: number): ViewRef {
|
detach(index?: number): ViewRef {
|
||||||
const view = this.get(index);
|
const view = this.get(index);
|
||||||
Services.detachEmbeddedView(this._data, index);
|
Services.detachEmbeddedView(this._data, index);
|
||||||
|
(view as ViewRef_).detachFromContainer();
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,11 +162,17 @@ export function createChangeDetectorRef(view: ViewData): ChangeDetectorRef {
|
|||||||
return new ViewRef_(view);
|
return new ViewRef_(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewRef_ implements EmbeddedViewRef<any> {
|
export class ViewRef_ implements EmbeddedViewRef<any> {
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_view: ViewData;
|
_view: ViewData;
|
||||||
|
private _viewContainerRef: ViewContainerRef;
|
||||||
|
private _appRef: ApplicationRef;
|
||||||
|
|
||||||
constructor(_view: ViewData) { this._view = _view; }
|
constructor(_view: ViewData) {
|
||||||
|
this._view = _view;
|
||||||
|
this._viewContainerRef = null;
|
||||||
|
this._appRef = null;
|
||||||
|
}
|
||||||
|
|
||||||
get rootNodes(): any[] { return rootRenderNodes(this._view); }
|
get rootNodes(): any[] { return rootRenderNodes(this._view); }
|
||||||
|
|
||||||
@ -173,9 +186,40 @@ class ViewRef_ implements EmbeddedViewRef<any> {
|
|||||||
checkNoChanges(): void { Services.checkNoChangesView(this._view); }
|
checkNoChanges(): void { Services.checkNoChangesView(this._view); }
|
||||||
|
|
||||||
reattach(): void { this._view.state |= ViewState.ChecksEnabled; }
|
reattach(): void { this._view.state |= ViewState.ChecksEnabled; }
|
||||||
onDestroy(callback: Function) { this._view.disposables.push(<any>callback); }
|
onDestroy(callback: Function) {
|
||||||
|
if (!this._view.disposables) {
|
||||||
|
this._view.disposables = [];
|
||||||
|
}
|
||||||
|
this._view.disposables.push(<any>callback);
|
||||||
|
}
|
||||||
|
|
||||||
destroy() { Services.destroyView(this._view); }
|
destroy() {
|
||||||
|
if (this._appRef) {
|
||||||
|
this._appRef.detachView(this);
|
||||||
|
} else if (this._viewContainerRef) {
|
||||||
|
this._viewContainerRef.detach(this._viewContainerRef.indexOf(this));
|
||||||
|
}
|
||||||
|
Services.destroyView(this._view);
|
||||||
|
}
|
||||||
|
|
||||||
|
detachFromContainer() {
|
||||||
|
this._appRef = null;
|
||||||
|
this._viewContainerRef = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachToAppRef(appRef: ApplicationRef) {
|
||||||
|
if (this._viewContainerRef) {
|
||||||
|
throw new Error('This view is already attached to a ViewContainer!');
|
||||||
|
}
|
||||||
|
this._appRef = appRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachToViewContainerRef(vcRef: ViewContainerRef) {
|
||||||
|
if (this._appRef) {
|
||||||
|
throw new Error('This view is already attached directly to the ApplicationRef!');
|
||||||
|
}
|
||||||
|
this._viewContainerRef = vcRef;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTemplateRef(view: ViewData, def: NodeDef): TemplateRef<any> {
|
export function createTemplateRef(view: ViewData, def: NodeDef): TemplateRef<any> {
|
||||||
@ -207,3 +251,137 @@ class Injector_ implements Injector {
|
|||||||
{flags: DepFlags.None, token, tokenKey: tokenKey(token)}, notFoundValue);
|
{flags: DepFlags.None, token, tokenKey: tokenKey(token)}, notFoundValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function nodeValue(view: ViewData, index: number): any {
|
||||||
|
const def = view.def.nodes[index];
|
||||||
|
switch (def.type) {
|
||||||
|
case NodeType.Element:
|
||||||
|
if (def.element.template) {
|
||||||
|
return createTemplateRef(view, def);
|
||||||
|
} else {
|
||||||
|
return asElementData(view, def.index).renderElement;
|
||||||
|
}
|
||||||
|
case NodeType.Text:
|
||||||
|
return asTextData(view, def.index).renderText;
|
||||||
|
case NodeType.Directive:
|
||||||
|
case NodeType.Pipe:
|
||||||
|
case NodeType.Provider:
|
||||||
|
return asProviderData(view, def.index).instance;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createRendererV1(view: ViewData): RendererV1 {
|
||||||
|
return new RendererAdapter(view.renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
class RendererAdapter implements RendererV1 {
|
||||||
|
constructor(private delegate: RendererV2) {}
|
||||||
|
selectRootElement(selectorOrNode: string|Element): Element {
|
||||||
|
return this.delegate.selectRootElement(selectorOrNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
createElement(parent: Element|DocumentFragment, namespaceAndName: string): Element {
|
||||||
|
const [ns, name] = splitNamespace(namespaceAndName);
|
||||||
|
const el = this.delegate.createElement(name, ns);
|
||||||
|
if (parent) {
|
||||||
|
this.delegate.appendChild(parent, el);
|
||||||
|
}
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
createViewRoot(hostElement: Element): Element|DocumentFragment { return hostElement; }
|
||||||
|
|
||||||
|
createTemplateAnchor(parentElement: Element|DocumentFragment): Comment {
|
||||||
|
const comment = this.delegate.createComment('');
|
||||||
|
if (parentElement) {
|
||||||
|
this.delegate.appendChild(parentElement, comment);
|
||||||
|
}
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
createText(parentElement: Element|DocumentFragment, value: string): any {
|
||||||
|
const node = this.delegate.createText(value);
|
||||||
|
if (parentElement) {
|
||||||
|
this.delegate.appendChild(parentElement, node);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
projectNodes(parentElement: Element|DocumentFragment, nodes: Node[]) {
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
this.delegate.appendChild(parentElement, nodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attachViewAfter(node: Node, viewRootNodes: Node[]) {
|
||||||
|
const parentElement = this.delegate.parentNode(node);
|
||||||
|
const nextSibling = this.delegate.nextSibling(node);
|
||||||
|
for (let i = 0; i < viewRootNodes.length; i++) {
|
||||||
|
this.delegate.insertBefore(parentElement, viewRootNodes[i], nextSibling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
detachView(viewRootNodes: (Element|Text|Comment)[]) {
|
||||||
|
for (let i = 0; i < viewRootNodes.length; i++) {
|
||||||
|
const node = viewRootNodes[i];
|
||||||
|
const parentElement = this.delegate.parentNode(node);
|
||||||
|
this.delegate.removeChild(parentElement, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyView(hostElement: Element|DocumentFragment, viewAllNodes: Node[]) {
|
||||||
|
for (let i = 0; i < viewAllNodes.length; i++) {
|
||||||
|
this.delegate.destroyNode(viewAllNodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(renderElement: any, name: string, callback: Function): Function {
|
||||||
|
return this.delegate.listen(renderElement, name, <any>callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
listenGlobal(target: string, name: string, callback: Function): Function {
|
||||||
|
return this.delegate.listen(target, name, <any>callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
setElementProperty(
|
||||||
|
renderElement: Element|DocumentFragment, propertyName: string, propertyValue: any): void {
|
||||||
|
this.delegate.setProperty(renderElement, propertyName, propertyValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
setElementAttribute(renderElement: Element, namespaceAndName: string, attributeValue: string):
|
||||||
|
void {
|
||||||
|
const [ns, name] = splitNamespace(namespaceAndName);
|
||||||
|
if (attributeValue != null) {
|
||||||
|
this.delegate.setAttribute(renderElement, name, attributeValue, ns);
|
||||||
|
} else {
|
||||||
|
this.delegate.removeAttribute(renderElement, name, ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setBindingDebugInfo(renderElement: Element, propertyName: string, propertyValue: string): void {}
|
||||||
|
|
||||||
|
setElementClass(renderElement: Element, className: string, isAdd: boolean): void {
|
||||||
|
if (isAdd) {
|
||||||
|
this.delegate.addClass(renderElement, className);
|
||||||
|
} else {
|
||||||
|
this.delegate.removeClass(renderElement, className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setElementStyle(renderElement: HTMLElement, styleName: string, styleValue: string): void {
|
||||||
|
if (styleValue != null) {
|
||||||
|
this.delegate.setStyle(renderElement, styleName, styleValue, false, false);
|
||||||
|
} else {
|
||||||
|
this.delegate.removeStyle(renderElement, styleName, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeElementMethod(renderElement: Element, methodName: string, args: any[]): void {
|
||||||
|
(renderElement as any)[methodName].apply(renderElement, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
setText(renderNode: Text, text: string): void { this.delegate.setValue(renderNode, text); }
|
||||||
|
|
||||||
|
animate(): NoOpAnimationPlayer { return new NoOpAnimationPlayer(); }
|
||||||
|
}
|
@ -168,7 +168,9 @@ function debugUpdateDirectives(check: NodeCheckFn, view: ViewData) {
|
|||||||
function debugCheckDirectivesFn(
|
function debugCheckDirectivesFn(
|
||||||
view: ViewData, nodeIndex: number, argStyle: ArgumentType, ...values: any[]) {
|
view: ViewData, nodeIndex: number, argStyle: ArgumentType, ...values: any[]) {
|
||||||
const result = debugCheckFn(check, view, nodeIndex, argStyle, values);
|
const result = debugCheckFn(check, view, nodeIndex, argStyle, values);
|
||||||
debugSetCurrentNode(view, nextDirectiveWithBinding(view, nodeIndex));
|
if (view.def.nodes[nodeIndex].type === NodeType.Directive) {
|
||||||
|
debugSetCurrentNode(view, nextDirectiveWithBinding(view, nodeIndex));
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -183,7 +185,10 @@ function debugUpdateRenderer(check: NodeCheckFn, view: ViewData) {
|
|||||||
function debugCheckRenderNodeFn(
|
function debugCheckRenderNodeFn(
|
||||||
view: ViewData, nodeIndex: number, argStyle: ArgumentType, ...values: any[]) {
|
view: ViewData, nodeIndex: number, argStyle: ArgumentType, ...values: any[]) {
|
||||||
const result = debugCheckFn(check, view, nodeIndex, argStyle, values);
|
const result = debugCheckFn(check, view, nodeIndex, argStyle, values);
|
||||||
debugSetCurrentNode(view, nextRenderNodeWithBinding(view, nodeIndex));
|
const nodeDef = view.def.nodes[nodeIndex];
|
||||||
|
if (nodeDef.type === NodeType.Element || nodeDef.type === NodeType.Text) {
|
||||||
|
debugSetCurrentNode(view, nextRenderNodeWithBinding(view, nodeIndex));
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -271,7 +276,7 @@ class DebugContext_ implements DebugContext {
|
|||||||
private compProviderDef: NodeDef;
|
private compProviderDef: NodeDef;
|
||||||
constructor(public view: ViewData, public nodeIndex: number) {
|
constructor(public view: ViewData, public nodeIndex: number) {
|
||||||
if (nodeIndex == null) {
|
if (nodeIndex == null) {
|
||||||
this.nodeIndex = 0;
|
this.nodeIndex = nodeIndex = 0;
|
||||||
}
|
}
|
||||||
this.nodeDef = view.def.nodes[nodeIndex];
|
this.nodeDef = view.def.nodes[nodeIndex];
|
||||||
let elDef = this.nodeDef;
|
let elDef = this.nodeDef;
|
||||||
|
@ -20,6 +20,7 @@ export function textDef(ngContentIndex: number, constants: string[]): NodeDef {
|
|||||||
bindings[i - 1] = {
|
bindings[i - 1] = {
|
||||||
type: BindingType.TextInterpolation,
|
type: BindingType.TextInterpolation,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
|
ns: undefined,
|
||||||
nonMinifiedName: undefined,
|
nonMinifiedName: undefined,
|
||||||
securityContext: undefined,
|
securityContext: undefined,
|
||||||
suffix: constants[i]
|
suffix: constants[i]
|
||||||
|
@ -161,6 +161,7 @@ export enum NodeFlags {
|
|||||||
|
|
||||||
export interface BindingDef {
|
export interface BindingDef {
|
||||||
type: BindingType;
|
type: BindingType;
|
||||||
|
ns: string;
|
||||||
name: string;
|
name: string;
|
||||||
nonMinifiedName: string;
|
nonMinifiedName: string;
|
||||||
securityContext: SecurityContext;
|
securityContext: SecurityContext;
|
||||||
@ -187,7 +188,9 @@ export enum QueryValueType {
|
|||||||
|
|
||||||
export interface ElementDef {
|
export interface ElementDef {
|
||||||
name: string;
|
name: string;
|
||||||
attrs: {[name: string]: string};
|
ns: string;
|
||||||
|
/** ns, name, value */
|
||||||
|
attrs: [string, string, string][];
|
||||||
outputs: ElementOutputDef[];
|
outputs: ElementOutputDef[];
|
||||||
template: ViewDefinition;
|
template: ViewDefinition;
|
||||||
component: NodeDef;
|
component: NodeDef;
|
||||||
|
@ -131,21 +131,6 @@ export function renderNode(view: ViewData, def: NodeDef): any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nodeValue(view: ViewData, index: number): any {
|
|
||||||
const def = view.def.nodes[index];
|
|
||||||
switch (def.type) {
|
|
||||||
case NodeType.Element:
|
|
||||||
return asElementData(view, def.index).renderElement;
|
|
||||||
case NodeType.Text:
|
|
||||||
return asTextData(view, def.index).renderText;
|
|
||||||
case NodeType.Directive:
|
|
||||||
case NodeType.Pipe:
|
|
||||||
case NodeType.Provider:
|
|
||||||
return asProviderData(view, def.index).instance;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function elementEventFullName(target: string, name: string): string {
|
export function elementEventFullName(target: string, name: string): string {
|
||||||
return target ? `${target}:${name}` : name;
|
return target ? `${target}:${name}` : name;
|
||||||
}
|
}
|
||||||
@ -184,13 +169,20 @@ export function splitMatchedQueriesDsl(matchedQueriesDsl: [string | number, Quer
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getParentRenderElement(view: ViewData, renderHost: any, def: NodeDef): any {
|
export function getParentRenderElement(view: ViewData, renderHost: any, def: NodeDef): any {
|
||||||
let parentEl: any;
|
let renderParent = def.renderParent;
|
||||||
if (!def.parent) {
|
if (renderParent) {
|
||||||
parentEl = renderHost;
|
const parent = def.parent;
|
||||||
} else if (def.renderParent) {
|
if (parent && (parent.type !== NodeType.Element || !parent.element.component ||
|
||||||
parentEl = asElementData(view, def.renderParent.index).renderElement;
|
(parent.element.component.provider.componentRenderType &&
|
||||||
|
parent.element.component.provider.componentRenderType.encapsulation ===
|
||||||
|
ViewEncapsulation.Native))) {
|
||||||
|
// only children of non components, or children of components with native encapsulation should
|
||||||
|
// be attached.
|
||||||
|
return asElementData(view, def.renderParent.index).renderElement;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return renderHost;
|
||||||
}
|
}
|
||||||
return parentEl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const VIEW_DEFINITION_CACHE = new WeakMap<any, ViewDefinition>();
|
const VIEW_DEFINITION_CACHE = new WeakMap<any, ViewDefinition>();
|
||||||
@ -332,3 +324,13 @@ function execRenderNodeAction(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NS_PREFIX_RE = /^:([^:]+):(.+)$/;
|
||||||
|
|
||||||
|
export function splitNamespace(name: string): string[] {
|
||||||
|
if (name[0] === ':') {
|
||||||
|
const match = name.match(NS_PREFIX_RE);
|
||||||
|
return [match[1], match[2]];
|
||||||
|
}
|
||||||
|
return ['', name];
|
||||||
|
}
|
||||||
|
@ -55,18 +55,12 @@ export function viewDef(
|
|||||||
node.reverseChildIndex =
|
node.reverseChildIndex =
|
||||||
calculateReverseChildIndex(currentParent, i, node.childCount, nodes.length);
|
calculateReverseChildIndex(currentParent, i, node.childCount, nodes.length);
|
||||||
|
|
||||||
|
// renderParent needs to account for ng-container!
|
||||||
let currentRenderParent: NodeDef;
|
let currentRenderParent: NodeDef;
|
||||||
if (currentParent &&
|
if (currentParent && currentParent.type === NodeType.Element && !currentParent.element.name) {
|
||||||
(currentParent.type !== NodeType.Element || !currentParent.element.component ||
|
currentRenderParent = currentParent.renderParent;
|
||||||
(currentParent.element.component.provider.componentRenderType &&
|
} else {
|
||||||
currentParent.element.component.provider.componentRenderType.encapsulation ===
|
currentRenderParent = currentParent;
|
||||||
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 {
|
|
||||||
currentRenderParent = currentParent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
node.renderParent = currentRenderParent;
|
node.renderParent = currentRenderParent;
|
||||||
|
|
||||||
@ -98,7 +92,7 @@ export function viewDef(
|
|||||||
viewBindingCount += node.bindings.length;
|
viewBindingCount += node.bindings.length;
|
||||||
viewDisposableCount += node.disposableCount;
|
viewDisposableCount += node.disposableCount;
|
||||||
|
|
||||||
if (!currentParent) {
|
if (!currentRenderParent) {
|
||||||
lastRootNode = node;
|
lastRootNode = node;
|
||||||
}
|
}
|
||||||
if (node.type === NodeType.Provider || node.type === NodeType.Directive) {
|
if (node.type === NodeType.Provider || node.type === NodeType.Directive) {
|
||||||
@ -204,10 +198,13 @@ function validateNode(parent: NodeDef, node: NodeDef, nodeCount: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node.query) {
|
if (node.query) {
|
||||||
const parentType = parent ? parent.type : null;
|
if (node.flags & NodeFlags.HasContentQuery && (!parent || parent.type !== NodeType.Directive)) {
|
||||||
if (parentType !== NodeType.Directive) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Illegal State: Query nodes need to be children of directives, at index ${node.index}!`);
|
`Illegal State: Content Query nodes need to be children of directives, at index ${node.index}!`);
|
||||||
|
}
|
||||||
|
if (node.flags & NodeFlags.HasViewQuery && parent) {
|
||||||
|
throw new Error(
|
||||||
|
`Illegal State: View Query nodes have to be top level nodes, at index ${node.index}!`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node.childCount) {
|
if (node.childCount) {
|
||||||
@ -593,8 +590,6 @@ function execQueriesAction(
|
|||||||
for (let i = 0; i < nodeCount; i++) {
|
for (let i = 0; i < nodeCount; i++) {
|
||||||
const nodeDef = view.def.nodes[i];
|
const nodeDef = view.def.nodes[i];
|
||||||
if ((nodeDef.flags & queryFlags) && (nodeDef.flags & staticDynamicQueryFlag)) {
|
if ((nodeDef.flags & queryFlags) && (nodeDef.flags & staticDynamicQueryFlag)) {
|
||||||
const elDef = nodeDef.parent.parent;
|
|
||||||
|
|
||||||
Services.setCurrentNode(view, nodeDef.index);
|
Services.setCurrentNode(view, nodeDef.index);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case QueryAction.CheckAndUpdate:
|
case QueryAction.CheckAndUpdate:
|
||||||
|
@ -10,6 +10,7 @@ import {APP_BOOTSTRAP_LISTENER, APP_INITIALIZER, CompilerFactory, Component, NgM
|
|||||||
import {ApplicationRef, ApplicationRef_} from '@angular/core/src/application_ref';
|
import {ApplicationRef, ApplicationRef_} from '@angular/core/src/application_ref';
|
||||||
import {ErrorHandler} from '@angular/core/src/error_handler';
|
import {ErrorHandler} from '@angular/core/src/error_handler';
|
||||||
import {ComponentRef} from '@angular/core/src/linker/component_factory';
|
import {ComponentRef} from '@angular/core/src/linker/component_factory';
|
||||||
|
import {TestComponentRenderer} from '@angular/core/testing';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
import {DOCUMENT} from '@angular/platform-browser/src/dom/dom_tokens';
|
import {DOCUMENT} from '@angular/platform-browser/src/dom/dom_tokens';
|
||||||
@ -19,21 +20,26 @@ import {ServerModule} from '@angular/platform-server';
|
|||||||
|
|
||||||
import {ComponentFixture, ComponentFixtureNoNgZone, TestBed, async, inject, withModule} from '../testing';
|
import {ComponentFixture, ComponentFixtureNoNgZone, TestBed, async, inject, withModule} from '../testing';
|
||||||
|
|
||||||
@Component({selector: 'comp', template: 'hello'})
|
@Component({selector: 'bootstrap-app', template: 'hello'})
|
||||||
class SomeComponent {
|
class SomeComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('bootstrap', () => {
|
describe('bootstrap', () => {
|
||||||
let mockConsole: MockConsole;
|
let mockConsole: MockConsole;
|
||||||
let fakeDoc: Document;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => { mockConsole = new MockConsole(); });
|
||||||
fakeDoc = getDOM().createHtmlDocument();
|
|
||||||
const el = getDOM().createElement('comp', fakeDoc);
|
function createRootEl() {
|
||||||
getDOM().appendChild(fakeDoc.body, el);
|
const doc = TestBed.get(DOCUMENT);
|
||||||
mockConsole = new MockConsole();
|
const rootEl = <HTMLElement>getDOM().firstChild(
|
||||||
});
|
getDOM().content(getDOM().createTemplate(`<bootstrap-app></bootstrap-app>`)));
|
||||||
|
const oldRoots = getDOM().querySelectorAll(doc, 'bootstrap-app');
|
||||||
|
for (let i = 0; i < oldRoots.length; i++) {
|
||||||
|
getDOM().remove(oldRoots[i]);
|
||||||
|
}
|
||||||
|
getDOM().appendChild(doc.body, rootEl);
|
||||||
|
}
|
||||||
|
|
||||||
type CreateModuleOptions = {providers?: any[], ngDoBootstrap?: any, bootstrap?: any[]};
|
type CreateModuleOptions = {providers?: any[], ngDoBootstrap?: any, bootstrap?: any[]};
|
||||||
|
|
||||||
@ -52,10 +58,7 @@ export function main() {
|
|||||||
const platformModule = getDOM().supportsDOMEvents() ? BrowserModule : ServerModule;
|
const platformModule = getDOM().supportsDOMEvents() ? BrowserModule : ServerModule;
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
providers: [
|
providers: [{provide: ErrorHandler, useValue: errorHandler}, options.providers || []],
|
||||||
{provide: ErrorHandler, useValue: errorHandler}, {provide: DOCUMENT, useValue: fakeDoc},
|
|
||||||
options.providers || []
|
|
||||||
],
|
|
||||||
imports: [platformModule],
|
imports: [platformModule],
|
||||||
declarations: [SomeComponent],
|
declarations: [SomeComponent],
|
||||||
entryComponents: [SomeComponent],
|
entryComponents: [SomeComponent],
|
||||||
@ -74,7 +77,8 @@ export function main() {
|
|||||||
|
|
||||||
it('should throw when reentering tick', inject([ApplicationRef], (ref: ApplicationRef_) => {
|
it('should throw when reentering tick', inject([ApplicationRef], (ref: ApplicationRef_) => {
|
||||||
const view = jasmine.createSpyObj('view', ['detach', 'attachToAppRef']);
|
const view = jasmine.createSpyObj('view', ['detach', 'attachToAppRef']);
|
||||||
const viewRef = jasmine.createSpyObj('viewRef', ['detectChanges']);
|
const viewRef = jasmine.createSpyObj(
|
||||||
|
'viewRef', ['detectChanges', 'detachFromContainer', 'attachToAppRef']);
|
||||||
viewRef.internalView = view;
|
viewRef.internalView = view;
|
||||||
view.ref = viewRef;
|
view.ref = viewRef;
|
||||||
try {
|
try {
|
||||||
@ -101,16 +105,13 @@ export function main() {
|
|||||||
|
|
||||||
it('should be called when a component is bootstrapped',
|
it('should be called when a component is bootstrapped',
|
||||||
inject([ApplicationRef], (ref: ApplicationRef_) => {
|
inject([ApplicationRef], (ref: ApplicationRef_) => {
|
||||||
|
createRootEl();
|
||||||
const compRef = ref.bootstrap(SomeComponent);
|
const compRef = ref.bootstrap(SomeComponent);
|
||||||
expect(capturedCompRefs).toEqual([compRef]);
|
expect(capturedCompRefs).toEqual([compRef]);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('bootstrap', () => {
|
describe('bootstrap', () => {
|
||||||
beforeEach(
|
|
||||||
() => {
|
|
||||||
|
|
||||||
});
|
|
||||||
it('should throw if an APP_INITIIALIZER is not yet resolved',
|
it('should throw if an APP_INITIIALIZER is not yet resolved',
|
||||||
withModule(
|
withModule(
|
||||||
{
|
{
|
||||||
@ -119,6 +120,7 @@ export function main() {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
inject([ApplicationRef], (ref: ApplicationRef_) => {
|
inject([ApplicationRef], (ref: ApplicationRef_) => {
|
||||||
|
createRootEl();
|
||||||
expect(() => ref.bootstrap(SomeComponent))
|
expect(() => ref.bootstrap(SomeComponent))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
'Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.');
|
'Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.');
|
||||||
@ -128,8 +130,10 @@ export function main() {
|
|||||||
|
|
||||||
describe('bootstrapModule', () => {
|
describe('bootstrapModule', () => {
|
||||||
let defaultPlatform: PlatformRef;
|
let defaultPlatform: PlatformRef;
|
||||||
beforeEach(
|
beforeEach(inject([PlatformRef], (_platform: PlatformRef) => {
|
||||||
inject([PlatformRef], (_platform: PlatformRef) => { defaultPlatform = _platform; }));
|
createRootEl();
|
||||||
|
defaultPlatform = _platform;
|
||||||
|
}));
|
||||||
|
|
||||||
it('should wait for asynchronous app initializers', async(() => {
|
it('should wait for asynchronous app initializers', async(() => {
|
||||||
let resolve: (result: any) => void;
|
let resolve: (result: any) => void;
|
||||||
@ -221,8 +225,10 @@ export function main() {
|
|||||||
|
|
||||||
describe('bootstrapModuleFactory', () => {
|
describe('bootstrapModuleFactory', () => {
|
||||||
let defaultPlatform: PlatformRef;
|
let defaultPlatform: PlatformRef;
|
||||||
beforeEach(
|
beforeEach(inject([PlatformRef], (_platform: PlatformRef) => {
|
||||||
inject([PlatformRef], (_platform: PlatformRef) => { defaultPlatform = _platform; }));
|
createRootEl();
|
||||||
|
defaultPlatform = _platform;
|
||||||
|
}));
|
||||||
it('should wait for asynchronous app initializers', async(() => {
|
it('should wait for asynchronous app initializers', async(() => {
|
||||||
let resolve: (result: any) => void;
|
let resolve: (result: any) => void;
|
||||||
const promise: Promise<any> = new Promise((res) => { resolve = res; });
|
const promise: Promise<any> = new Promise((res) => { resolve = res; });
|
||||||
@ -346,7 +352,7 @@ export function main() {
|
|||||||
it('should not allow to attach a view to both, a view container and the ApplicationRef',
|
it('should not allow to attach a view to both, a view container and the ApplicationRef',
|
||||||
() => {
|
() => {
|
||||||
const comp = TestBed.createComponent(MyComp);
|
const comp = TestBed.createComponent(MyComp);
|
||||||
const hostView = comp.componentRef.hostView;
|
let hostView = comp.componentRef.hostView;
|
||||||
const containerComp = TestBed.createComponent(ContainerComp);
|
const containerComp = TestBed.createComponent(ContainerComp);
|
||||||
containerComp.detectChanges();
|
containerComp.detectChanges();
|
||||||
const vc = containerComp.componentInstance.vc;
|
const vc = containerComp.componentInstance.vc;
|
||||||
@ -355,7 +361,7 @@ export function main() {
|
|||||||
vc.insert(hostView);
|
vc.insert(hostView);
|
||||||
expect(() => appRef.attachView(hostView))
|
expect(() => appRef.attachView(hostView))
|
||||||
.toThrowError('This view is already attached to a ViewContainer!');
|
.toThrowError('This view is already attached to a ViewContainer!');
|
||||||
vc.detach(0);
|
hostView = vc.detach(0);
|
||||||
|
|
||||||
appRef.attachView(hostView);
|
appRef.attachView(hostView);
|
||||||
expect(() => vc.insert(hostView))
|
expect(() => vc.insert(hostView))
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
import {AfterContentInit, AfterViewInit, Component, ContentChildren, Directive, Input, QueryList, ViewChildren} from '@angular/core';
|
import {AfterContentInit, AfterViewInit, Component, ContentChildren, Directive, Input, QueryList, ViewChildren} from '@angular/core';
|
||||||
import {TestBed} from '@angular/core/testing';
|
import {TestBed} from '@angular/core/testing';
|
||||||
import {beforeEach, describe, it} from '@angular/core/testing/testing_internal';
|
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import {Component, Directive, HostBinding, Input, NO_ERRORS_SCHEMA} from '@angular/core';
|
import {Component, Directive, HostBinding, Input, NO_ERRORS_SCHEMA} from '@angular/core';
|
||||||
import {ComponentFixture, TestBed, getTestBed} from '@angular/core/testing';
|
import {ComponentFixture, TestBed, getTestBed} from '@angular/core/testing';
|
||||||
import {afterEach, beforeEach, describe, expect, iit, it} from '@angular/core/testing/testing_internal';
|
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
import {DomSanitizer} from '@angular/platform-browser/src/security/dom_sanitization_service';
|
import {DomSanitizer} from '@angular/platform-browser/src/security/dom_sanitization_service';
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ export function main() {
|
|||||||
it('should set attributes on the root node', () => {
|
it('should set attributes on the root node', () => {
|
||||||
const view = createRootView(
|
const view = createRootView(
|
||||||
compViewDef([
|
compViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 0, 'div', {'a': 'b'}),
|
elementDef(NodeFlags.None, null, null, 0, 'div', [['a', 'b']]),
|
||||||
]),
|
]),
|
||||||
{}, [], rootNode);
|
{}, [], rootNode);
|
||||||
expect(rootNode.getAttribute('a')).toBe('b');
|
expect(rootNode.getAttribute('a')).toBe('b');
|
||||||
@ -92,7 +92,7 @@ export function main() {
|
|||||||
rootNode.appendChild(document.createElement('div'));
|
rootNode.appendChild(document.createElement('div'));
|
||||||
const view = createRootView(
|
const view = createRootView(
|
||||||
compViewDef([
|
compViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 0, 'div', {'a': 'b'}),
|
elementDef(NodeFlags.None, null, null, 0, 'div', [['a', 'b']]),
|
||||||
]),
|
]),
|
||||||
{}, [], rootNode);
|
{}, [], rootNode);
|
||||||
expect(rootNode.childNodes.length).toBe(0);
|
expect(rootNode.childNodes.length).toBe(0);
|
||||||
|
@ -57,7 +57,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should set fixed attributes', () => {
|
it('should set fixed attributes', () => {
|
||||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 0, 'div', {'title': 'a'}),
|
elementDef(NodeFlags.None, null, null, 0, 'div', [['title', 'a']]),
|
||||||
])).rootNodes;
|
])).rootNodes;
|
||||||
expect(rootNodes.length).toBe(1);
|
expect(rootNodes.length).toBe(1);
|
||||||
expect(getDOM().getAttribute(rootNodes[0], 'title')).toBe('a');
|
expect(getDOM().getAttribute(rootNodes[0], 'title')).toBe('a');
|
||||||
|
@ -55,10 +55,10 @@ export function main() {
|
|||||||
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
|
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 2, 'div'),
|
elementDef(NodeFlags.None, null, null, 2, 'div'),
|
||||||
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
|
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'child0'})
|
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
|
||||||
])),
|
])),
|
||||||
anchorDef(NodeFlags.None, null, null, 0, embeddedViewDef([
|
anchorDef(NodeFlags.None, null, null, 0, embeddedViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'child1'})
|
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child1']])
|
||||||
]))
|
]))
|
||||||
]));
|
]));
|
||||||
const viewContainerData = asElementData(parentView, 1);
|
const viewContainerData = asElementData(parentView, 1);
|
||||||
@ -85,10 +85,10 @@ export function main() {
|
|||||||
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
|
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 2, 'div'),
|
elementDef(NodeFlags.None, null, null, 2, 'div'),
|
||||||
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
|
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'child0'})
|
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
|
||||||
])),
|
])),
|
||||||
anchorDef(NodeFlags.None, null, null, 0, embeddedViewDef([
|
anchorDef(NodeFlags.None, null, null, 0, embeddedViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'child1'})
|
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child1']])
|
||||||
]))
|
]))
|
||||||
]));
|
]));
|
||||||
const viewContainerData = asElementData(parentView, 1);
|
const viewContainerData = asElementData(parentView, 1);
|
||||||
@ -112,9 +112,9 @@ export function main() {
|
|||||||
it('should include embedded views in root nodes', () => {
|
it('should include embedded views in root nodes', () => {
|
||||||
const {view: parentView} = createAndGetRootNodes(compViewDef([
|
const {view: parentView} = createAndGetRootNodes(compViewDef([
|
||||||
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
|
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'child0'})
|
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
|
||||||
])),
|
])),
|
||||||
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'after'})
|
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'after']])
|
||||||
]));
|
]));
|
||||||
|
|
||||||
const childView0 = Services.createEmbeddedView(parentView, parentView.def.nodes[0]);
|
const childView0 = Services.createEmbeddedView(parentView, parentView.def.nodes[0]);
|
||||||
|
@ -50,12 +50,16 @@ export function main() {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function viewQueryProviders(compView: ViewDefinition) {
|
function viewQueryProviders(nodes: NodeDef[]) {
|
||||||
return [
|
return [
|
||||||
directiveDef(NodeFlags.None, null, 1, QueryService, [], null, null, () => compView),
|
directiveDef(
|
||||||
queryDef(
|
NodeFlags.None, null, 0, QueryService, [], null, null,
|
||||||
NodeFlags.HasViewQuery | NodeFlags.HasDynamicQuery, someQueryId,
|
() => compViewDef([
|
||||||
{'a': QueryBindingType.All})
|
queryDef(
|
||||||
|
NodeFlags.HasViewQuery | NodeFlags.HasDynamicQuery, someQueryId,
|
||||||
|
{'a': QueryBindingType.All}),
|
||||||
|
...nodes
|
||||||
|
])),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,11 +110,11 @@ export function main() {
|
|||||||
describe('view queries', () => {
|
describe('view queries', () => {
|
||||||
it('should query providers in the view', () => {
|
it('should query providers in the view', () => {
|
||||||
const {view} = createAndGetRootNodes(compViewDef([
|
const {view} = createAndGetRootNodes(compViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 2, 'div'),
|
elementDef(NodeFlags.None, null, null, 1, 'div'),
|
||||||
...viewQueryProviders(compViewDef([
|
...viewQueryProviders([
|
||||||
elementDef(NodeFlags.None, null, null, 1, 'span'),
|
elementDef(NodeFlags.None, null, null, 1, 'span'),
|
||||||
aServiceProvider(),
|
aServiceProvider(),
|
||||||
])),
|
]),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
@ -118,15 +122,15 @@ export function main() {
|
|||||||
const comp: QueryService = asProviderData(view, 1).instance;
|
const comp: QueryService = asProviderData(view, 1).instance;
|
||||||
const compView = asProviderData(view, 1).componentView;
|
const compView = asProviderData(view, 1).componentView;
|
||||||
expect(comp.a.length).toBe(1);
|
expect(comp.a.length).toBe(1);
|
||||||
expect(comp.a.first).toBe(asProviderData(compView, 1).instance);
|
expect(comp.a.first).toBe(asProviderData(compView, 2).instance);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not query providers on the host element', () => {
|
it('should not query providers on the host element', () => {
|
||||||
const {view} = createAndGetRootNodes(compViewDef([
|
const {view} = createAndGetRootNodes(compViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 3, 'div'),
|
elementDef(NodeFlags.None, null, null, 2, 'div'),
|
||||||
...viewQueryProviders(compViewDef([
|
...viewQueryProviders([
|
||||||
elementDef(NodeFlags.None, null, null, 0, 'span'),
|
elementDef(NodeFlags.None, null, null, 0, 'span'),
|
||||||
])),
|
]),
|
||||||
aServiceProvider(),
|
aServiceProvider(),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
@ -221,13 +225,13 @@ export function main() {
|
|||||||
|
|
||||||
it('should update view queries if embedded views are added or removed', () => {
|
it('should update view queries if embedded views are added or removed', () => {
|
||||||
const {view} = createAndGetRootNodes(compViewDef([
|
const {view} = createAndGetRootNodes(compViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 2, 'div'),
|
elementDef(NodeFlags.None, null, null, 1, 'div'),
|
||||||
...viewQueryProviders(compViewDef([
|
...viewQueryProviders([
|
||||||
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
|
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
|
||||||
elementDef(NodeFlags.None, null, null, 1, 'div'),
|
elementDef(NodeFlags.None, null, null, 1, 'div'),
|
||||||
aServiceProvider(),
|
aServiceProvider(),
|
||||||
])),
|
])),
|
||||||
])),
|
]),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
@ -236,13 +240,13 @@ export function main() {
|
|||||||
expect(comp.a.length).toBe(0);
|
expect(comp.a.length).toBe(0);
|
||||||
|
|
||||||
const compView = asProviderData(view, 1).componentView;
|
const compView = asProviderData(view, 1).componentView;
|
||||||
const childView = Services.createEmbeddedView(compView, compView.def.nodes[0]);
|
const childView = Services.createEmbeddedView(compView, compView.def.nodes[1]);
|
||||||
attachEmbeddedView(asElementData(compView, 0), 0, childView);
|
attachEmbeddedView(asElementData(compView, 1), 0, childView);
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
|
|
||||||
expect(comp.a.length).toBe(1);
|
expect(comp.a.length).toBe(1);
|
||||||
|
|
||||||
detachEmbeddedView(asElementData(compView, 0), 0);
|
detachEmbeddedView(asElementData(compView, 1), 0);
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
|
|
||||||
expect(comp.a.length).toBe(0);
|
expect(comp.a.length).toBe(0);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import {NgAnalyzedModules} from '@angular/compiler/src/aot/compiler';
|
import {NgAnalyzedModules} from '@angular/compiler/src/aot/compiler';
|
||||||
import {CompileNgModuleMetadata} from '@angular/compiler/src/compile_metadata';
|
import {CompileNgModuleMetadata} from '@angular/compiler/src/compile_metadata';
|
||||||
|
import {CompilerConfig} from '@angular/compiler/src/config';
|
||||||
import {Lexer} from '@angular/compiler/src/expression_parser/lexer';
|
import {Lexer} from '@angular/compiler/src/expression_parser/lexer';
|
||||||
import {Parser} from '@angular/compiler/src/expression_parser/parser';
|
import {Parser} from '@angular/compiler/src/expression_parser/parser';
|
||||||
import {I18NHtmlParser} from '@angular/compiler/src/i18n/i18n_html_parser';
|
import {I18NHtmlParser} from '@angular/compiler/src/i18n/i18n_html_parser';
|
||||||
@ -23,6 +24,7 @@ import {getDeclarationDiagnostics, getTemplateDiagnostics} from './diagnostics';
|
|||||||
import {getHover} from './hover';
|
import {getHover} from './hover';
|
||||||
import {Completion, CompletionKind, Completions, Declaration, Declarations, Definition, Diagnostic, DiagnosticKind, Diagnostics, Hover, LanguageService, LanguageServiceHost, Location, PipeInfo, Pipes, Signature, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable, TemplateSource, TemplateSources} from './types';
|
import {Completion, CompletionKind, Completions, Declaration, Declarations, Definition, Diagnostic, DiagnosticKind, Diagnostics, Hover, LanguageService, LanguageServiceHost, Location, PipeInfo, Pipes, Signature, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable, TemplateSource, TemplateSources} from './types';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of an Angular `LanguageService`.
|
* Create an instance of an Angular `LanguageService`.
|
||||||
*
|
*
|
||||||
@ -114,8 +116,9 @@ class LanguageServiceImpl implements LanguageService {
|
|||||||
const rawHtmlParser = new HtmlParser();
|
const rawHtmlParser = new HtmlParser();
|
||||||
const htmlParser = new I18NHtmlParser(rawHtmlParser);
|
const htmlParser = new I18NHtmlParser(rawHtmlParser);
|
||||||
const expressionParser = new Parser(new Lexer());
|
const expressionParser = new Parser(new Lexer());
|
||||||
|
const config = new CompilerConfig();
|
||||||
const parser = new TemplateParser(
|
const parser = new TemplateParser(
|
||||||
expressionParser, new DomElementSchemaRegistry(), htmlParser, null, []);
|
config, expressionParser, new DomElementSchemaRegistry(), htmlParser, null, []);
|
||||||
const htmlResult = htmlParser.parse(template.source, '');
|
const htmlResult = htmlParser.parse(template.source, '');
|
||||||
const analyzedModules = this.host.getAnalyzedModules();
|
const analyzedModules = this.host.getAnalyzedModules();
|
||||||
let errors: Diagnostic[] = undefined;
|
let errors: Diagnostic[] = undefined;
|
||||||
|
@ -131,7 +131,7 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
|||||||
new DirectiveNormalizer(resourceLoader, urlResolver, htmlParser, config);
|
new DirectiveNormalizer(resourceLoader, urlResolver, htmlParser, config);
|
||||||
|
|
||||||
result = this._resolver = new CompileMetadataResolver(
|
result = this._resolver = new CompileMetadataResolver(
|
||||||
moduleResolver, directiveResolver, pipeResolver, new SummaryResolver(),
|
config, moduleResolver, directiveResolver, pipeResolver, new SummaryResolver(),
|
||||||
elementSchemaRegistry, directiveNormalizer, this._staticSymbolCache, this.reflector,
|
elementSchemaRegistry, directiveNormalizer, this._staticSymbolCache, this.reflector,
|
||||||
(error, type) => this.collectError(error, type && type.filePath));
|
(error, type) => this.collectError(error, type && type.filePath));
|
||||||
}
|
}
|
||||||
|
@ -17,16 +17,6 @@ export class ChangeDetectionPerfRecord {
|
|||||||
constructor(public msPerTick: number, public numTicks: number) {}
|
constructor(public msPerTick: number, public numTicks: number) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Entry point for all Angular debug tools. This object corresponds to the `ng`
|
|
||||||
* global variable accessible in the dev console.
|
|
||||||
*/
|
|
||||||
export class AngularTools {
|
|
||||||
profiler: AngularProfiler;
|
|
||||||
|
|
||||||
constructor(ref: ComponentRef<any>) { this.profiler = new AngularProfiler(ref); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point for all Angular profiling-related debug tools. This object
|
* Entry point for all Angular profiling-related debug tools. This object
|
||||||
* corresponds to the `ng.profiler` in the dev console.
|
* corresponds to the `ng.profiler` in the dev console.
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {ComponentRef} from '@angular/core';
|
import {ComponentRef} from '@angular/core';
|
||||||
import {global} from '../../facade/lang';
|
import {getDOM} from '../../dom/dom_adapter';
|
||||||
|
|
||||||
import {AngularTools} from './common_tools';
|
import {AngularProfiler} from './common_tools';
|
||||||
|
|
||||||
const context = <any>global;
|
const PROFILER_GLOBAL_NAME = 'ng.profiler';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enabled Angular debug tools that are accessible via your browser's
|
* Enabled Angular debug tools that are accessible via your browser's
|
||||||
@ -27,7 +27,7 @@ const context = <any>global;
|
|||||||
* @experimental All debugging apis are currently experimental.
|
* @experimental All debugging apis are currently experimental.
|
||||||
*/
|
*/
|
||||||
export function enableDebugTools<T>(ref: ComponentRef<T>): ComponentRef<T> {
|
export function enableDebugTools<T>(ref: ComponentRef<T>): ComponentRef<T> {
|
||||||
(<any>Object).assign(context.ng, new AngularTools(ref));
|
getDOM().setGlobalVar(PROFILER_GLOBAL_NAME, new AngularProfiler(ref));
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +37,5 @@ export function enableDebugTools<T>(ref: ComponentRef<T>): ComponentRef<T> {
|
|||||||
* @experimental All debugging apis are currently experimental.
|
* @experimental All debugging apis are currently experimental.
|
||||||
*/
|
*/
|
||||||
export function disableDebugTools(): void {
|
export function disableDebugTools(): void {
|
||||||
if (context.ng) {
|
getDOM().setGlobalVar(PROFILER_GLOBAL_NAME, null);
|
||||||
delete context.ng.profiler;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -434,6 +434,9 @@ class DefaultDomRendererV2 implements RendererV2 {
|
|||||||
selectRootElement(selectorOrNode: string|any): any {
|
selectRootElement(selectorOrNode: string|any): any {
|
||||||
let el: any = typeof selectorOrNode === 'string' ? document.querySelector(selectorOrNode) :
|
let el: any = typeof selectorOrNode === 'string' ? document.querySelector(selectorOrNode) :
|
||||||
selectorOrNode;
|
selectorOrNode;
|
||||||
|
if (!el) {
|
||||||
|
throw new Error(`The selector "${selectorOrNode}" did not match any elements`);
|
||||||
|
}
|
||||||
el.textContent = '';
|
el.textContent = '';
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
@ -464,13 +467,21 @@ class DefaultDomRendererV2 implements RendererV2 {
|
|||||||
|
|
||||||
setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean):
|
setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean):
|
||||||
void {
|
void {
|
||||||
el.style[style] = value;
|
if (hasVendorPrefix || hasImportant) {
|
||||||
|
el.style.setProperty(style, value, hasImportant ? 'important' : '');
|
||||||
|
} else {
|
||||||
|
el.style[style] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeStyle(el: any, style: string, hasVendorPrefix: boolean): void {
|
removeStyle(el: any, style: string, hasVendorPrefix: boolean): void {
|
||||||
// IE requires '' instead of null
|
if (hasVendorPrefix) {
|
||||||
// see https://github.com/angular/angular/issues/7916
|
el.style.removeProperty(style);
|
||||||
el.style[style] = '';
|
} else {
|
||||||
|
// IE requires '' instead of null
|
||||||
|
// see https://github.com/angular/angular/issues/7916
|
||||||
|
el.style[style] = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setProperty(el: any, name: string, value: any): void { el[name] = value; }
|
setProperty(el: any, name: string, value: any): void { el[name] = value; }
|
||||||
|
@ -11,7 +11,7 @@ import {ApplicationRef, destroyPlatform} from '@angular/core/src/application_ref
|
|||||||
import {Console} from '@angular/core/src/console';
|
import {Console} from '@angular/core/src/console';
|
||||||
import {ComponentRef} from '@angular/core/src/linker/component_factory';
|
import {ComponentRef} from '@angular/core/src/linker/component_factory';
|
||||||
import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability';
|
import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability';
|
||||||
import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, describe, inject, it} from '@angular/core/testing/testing_internal';
|
import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it} from '@angular/core/testing/testing_internal';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
@ -20,6 +20,10 @@ import {expect} from '@angular/platform-browser/testing/matchers';
|
|||||||
|
|
||||||
import {stringify} from '../../src/facade/lang';
|
import {stringify} from '../../src/facade/lang';
|
||||||
|
|
||||||
|
@Component({selector: 'non-existent', template: ''})
|
||||||
|
class NonExistentComp {
|
||||||
|
}
|
||||||
|
|
||||||
@Component({selector: 'hello-app', template: '{{greeting}} world!'})
|
@Component({selector: 'hello-app', template: '{{greeting}} world!'})
|
||||||
class HelloRootCmp {
|
class HelloRootCmp {
|
||||||
greeting: string;
|
greeting: string;
|
||||||
@ -124,29 +128,32 @@ function bootstrap(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
let fakeDoc: any /** TODO #9100 */, el: any /** TODO #9100 */, el2: any /** TODO #9100 */,
|
let el: any /** TODO #9100 */, el2: any /** TODO #9100 */, testProviders: Provider[],
|
||||||
testProviders: Provider[], lightDom: any /** TODO #9100 */;
|
lightDom: any /** TODO #9100 */;
|
||||||
|
|
||||||
describe('bootstrap factory method', () => {
|
describe('bootstrap factory method', () => {
|
||||||
let compilerConsole: DummyConsole;
|
let compilerConsole: DummyConsole;
|
||||||
|
|
||||||
beforeEachProviders(() => { return [Log]; });
|
beforeEachProviders(() => { return [Log]; });
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(inject([DOCUMENT], (doc: any) => {
|
||||||
destroyPlatform();
|
destroyPlatform();
|
||||||
|
compilerConsole = new DummyConsole();
|
||||||
|
testProviders = [{provide: Console, useValue: compilerConsole}];
|
||||||
|
|
||||||
fakeDoc = getDOM().createHtmlDocument();
|
const oldRoots = getDOM().querySelectorAll(doc, 'hello-app,hello-app-2,light-dom-el');
|
||||||
el = getDOM().createElement('hello-app', fakeDoc);
|
for (let i = 0; i < oldRoots.length; i++) {
|
||||||
el2 = getDOM().createElement('hello-app-2', fakeDoc);
|
getDOM().remove(oldRoots[i]);
|
||||||
lightDom = getDOM().createElement('light-dom-el', fakeDoc);
|
}
|
||||||
getDOM().appendChild(fakeDoc.body, el);
|
|
||||||
getDOM().appendChild(fakeDoc.body, el2);
|
el = getDOM().createElement('hello-app', doc);
|
||||||
|
el2 = getDOM().createElement('hello-app-2', doc);
|
||||||
|
lightDom = getDOM().createElement('light-dom-el', doc);
|
||||||
|
getDOM().appendChild(doc.body, el);
|
||||||
|
getDOM().appendChild(doc.body, el2);
|
||||||
getDOM().appendChild(el, lightDom);
|
getDOM().appendChild(el, lightDom);
|
||||||
getDOM().setText(lightDom, 'loading');
|
getDOM().setText(lightDom, 'loading');
|
||||||
compilerConsole = new DummyConsole();
|
}));
|
||||||
testProviders =
|
|
||||||
[{provide: DOCUMENT, useValue: fakeDoc}, {provide: Console, useValue: compilerConsole}];
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(destroyPlatform);
|
afterEach(destroyPlatform);
|
||||||
|
|
||||||
@ -167,10 +174,11 @@ export function main() {
|
|||||||
const logger = new MockConsole();
|
const logger = new MockConsole();
|
||||||
const errorHandler = new ErrorHandler(false);
|
const errorHandler = new ErrorHandler(false);
|
||||||
errorHandler._console = logger as any;
|
errorHandler._console = logger as any;
|
||||||
bootstrap(HelloRootCmp, [
|
bootstrap(NonExistentComp, [
|
||||||
{provide: ErrorHandler, useValue: errorHandler}
|
{provide: ErrorHandler, useValue: errorHandler}
|
||||||
]).then(null, (reason) => {
|
]).then(null, (reason) => {
|
||||||
expect(reason.message).toContain('The selector "hello-app" did not match any elements');
|
expect(reason.message)
|
||||||
|
.toContain('The selector "non-existent" did not match any elements');
|
||||||
async.done();
|
async.done();
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -184,10 +192,10 @@ export function main() {
|
|||||||
errorHandler._console = logger as any;
|
errorHandler._console = logger as any;
|
||||||
|
|
||||||
const refPromise =
|
const refPromise =
|
||||||
bootstrap(HelloRootCmp, [{provide: ErrorHandler, useValue: errorHandler}]);
|
bootstrap(NonExistentComp, [{provide: ErrorHandler, useValue: errorHandler}]);
|
||||||
refPromise.then(null, (reason: any) => {
|
refPromise.then(null, (reason: any) => {
|
||||||
expect(reason.message)
|
expect(reason.message)
|
||||||
.toContain('The selector "hello-app" did not match any elements');
|
.toContain('The selector "non-existent" did not match any elements');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
@ -199,10 +207,10 @@ export function main() {
|
|||||||
errorHandler._console = logger as any;
|
errorHandler._console = logger as any;
|
||||||
|
|
||||||
const refPromise =
|
const refPromise =
|
||||||
bootstrap(HelloRootCmp, [{provide: ErrorHandler, useValue: errorHandler}]);
|
bootstrap(NonExistentComp, [{provide: ErrorHandler, useValue: errorHandler}]);
|
||||||
refPromise.then(null, (reason) => {
|
refPromise.then(null, (reason) => {
|
||||||
expect(logger.res.join(''))
|
expect(logger.res.join(''))
|
||||||
.toContain('The selector "hello-app" did not match any elements');
|
.toContain('The selector "non-existent" did not match any elements');
|
||||||
async.done();
|
async.done();
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {afterEach, beforeEach, describe, it} from '@angular/core/testing/testing_internal';
|
|
||||||
import {disableDebugTools, enableDebugTools} from '@angular/platform-browser';
|
import {disableDebugTools, enableDebugTools} from '@angular/platform-browser';
|
||||||
|
|
||||||
import {SpyComponentRef, callNgProfilerTimeChangeDetection} from './spies';
|
import {SpyComponentRef, callNgProfilerTimeChangeDetection} from './spies';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user