refactor(compiler): remove `view.rootNodes` and `view.projectableNodes`
They are replaced by generated visitor functions `view.visitRootNodes` / `view.visitProjectableNodes`.
This commit is contained in:
parent
b3e3cd3add
commit
bda1909ede
|
@ -162,11 +162,6 @@ export class Identifiers {
|
|||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||
runtime: view_utils.checkBinding
|
||||
};
|
||||
static flattenNestedViewRenderNodes: IdentifierSpec = {
|
||||
name: 'flattenNestedViewRenderNodes',
|
||||
moduleUrl: VIEW_UTILS_MODULE_URL,
|
||||
runtime: view_utils.flattenNestedViewRenderNodes
|
||||
};
|
||||
static devModeEqual:
|
||||
IdentifierSpec = {name: 'devModeEqual', moduleUrl: CD_MODULE_URL, runtime: devModeEqual};
|
||||
static interpolate: IdentifierSpec = {
|
||||
|
|
|
@ -19,7 +19,7 @@ import {ProviderAst, ProviderAstType, ReferenceAst, TemplateAst} from '../templa
|
|||
|
||||
import {CompileMethod} from './compile_method';
|
||||
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
|
||||
import {CompileView} from './compile_view';
|
||||
import {CompileView, CompileViewRootNode} from './compile_view';
|
||||
import {InjectMethodVars, ViewProperties} from './constants';
|
||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewFactoryDependency} from './deps';
|
||||
import {getPropertyInView, injectFromViewParentInjector} from './util';
|
||||
|
@ -51,7 +51,7 @@ export class CompileElement extends CompileNode {
|
|||
private _queries = new Map<any, CompileQuery[]>();
|
||||
private _componentConstructorViewQueryLists: o.Expression[] = [];
|
||||
|
||||
public contentNodesByNgContentIndex: Array<o.Expression>[] = null;
|
||||
public contentNodesByNgContentIndex: Array<CompileViewRootNode>[] = null;
|
||||
public embeddedView: CompileView;
|
||||
public referenceTokens: {[key: string]: CompileTokenMetadata};
|
||||
|
||||
|
@ -293,7 +293,7 @@ export class CompileElement extends CompileNode {
|
|||
this.view.createMethod, this.view.updateContentQueriesMethod)));
|
||||
}
|
||||
|
||||
addContentNode(ngContentIndex: number, nodeExpr: o.Expression) {
|
||||
addContentNode(ngContentIndex: number, nodeExpr: CompileViewRootNode) {
|
||||
this.contentNodesByNgContentIndex[ngContentIndex].push(nodeExpr);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,18 @@ import {CompilePipe} from './compile_pipe';
|
|||
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
|
||||
import {getPropertyInView, getViewFactoryName} from './util';
|
||||
|
||||
export enum CompileViewRootNodeType {
|
||||
Node,
|
||||
ViewContainer,
|
||||
NgContent
|
||||
}
|
||||
|
||||
export class CompileViewRootNode {
|
||||
constructor(
|
||||
public type: CompileViewRootNodeType, public expr: o.Expression,
|
||||
public ngContentIndex?: number) {}
|
||||
}
|
||||
|
||||
export class CompileView implements NameResolver {
|
||||
public viewType: ViewType;
|
||||
public viewQueries: Map<any, CompileQuery[]>;
|
||||
|
@ -30,8 +42,10 @@ export class CompileView implements NameResolver {
|
|||
public viewChildren: o.Expression[] = [];
|
||||
|
||||
public nodes: CompileNode[] = [];
|
||||
// root nodes or AppElements for ViewContainers
|
||||
public rootNodesOrAppElements: o.Expression[] = [];
|
||||
|
||||
public rootNodes: CompileViewRootNode[] = [];
|
||||
public lastRenderNode: o.Expression = o.NULL_EXPR;
|
||||
|
||||
public viewContainerAppElements: o.Expression[] = [];
|
||||
|
||||
public createMethod: CompileMethod;
|
||||
|
|
|
@ -45,7 +45,6 @@ export class ViewConstructorVars {
|
|||
|
||||
export class ViewProperties {
|
||||
static renderer = o.THIS_EXPR.prop('renderer');
|
||||
static projectableNodes = o.THIS_EXPR.prop('projectableNodes');
|
||||
static viewUtils = o.THIS_EXPR.prop('viewUtils');
|
||||
}
|
||||
|
||||
|
|
|
@ -69,29 +69,6 @@ export function getViewFactoryName(
|
|||
return `viewFactory_${component.type.name}${embeddedTemplateIndex}`;
|
||||
}
|
||||
|
||||
export function createFlatArray(expressions: o.Expression[]): o.Expression {
|
||||
var lastNonArrayExpressions: o.Expression[] = [];
|
||||
var result: o.Expression = o.literalArr([]);
|
||||
for (var i = 0; i < expressions.length; i++) {
|
||||
var expr = expressions[i];
|
||||
if (expr.type instanceof o.ArrayType) {
|
||||
if (lastNonArrayExpressions.length > 0) {
|
||||
result =
|
||||
result.callMethod(o.BuiltinMethod.ConcatArray, [o.literalArr(lastNonArrayExpressions)]);
|
||||
lastNonArrayExpressions = [];
|
||||
}
|
||||
result = result.callMethod(o.BuiltinMethod.ConcatArray, [expr]);
|
||||
} else {
|
||||
lastNonArrayExpressions.push(expr);
|
||||
}
|
||||
}
|
||||
if (lastNonArrayExpressions.length > 0) {
|
||||
result =
|
||||
result.callMethod(o.BuiltinMethod.ConcatArray, [o.literalArr(lastNonArrayExpressions)]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getHandleEventMethodName(elementIndex: number): string {
|
||||
return `handleEvent_${elementIndex}`;
|
||||
}
|
|
@ -15,14 +15,15 @@ import {isPresent} from '../facade/lang';
|
|||
import {Identifiers, identifierToken, resolveIdentifier} from '../identifiers';
|
||||
import {createClassStmt} from '../output/class_builder';
|
||||
import * as o from '../output/output_ast';
|
||||
import {ParseSourceSpan} from '../parse_util';
|
||||
import {ChangeDetectorStatus, ViewType, isDefaultChangeDetectionStrategy} from '../private_import_core';
|
||||
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
|
||||
|
||||
import {CompileElement, CompileNode} from './compile_element';
|
||||
import {CompileView} from './compile_view';
|
||||
import {CompileView, CompileViewRootNode, CompileViewRootNodeType} from './compile_view';
|
||||
import {ChangeDetectorStatusEnum, DetectChangesVars, InjectMethodVars, ViewConstructorVars, ViewEncapsulationEnum, ViewProperties, ViewTypeEnum} from './constants';
|
||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewFactoryDependency} from './deps';
|
||||
import {createFlatArray, getViewFactoryName} from './util';
|
||||
import {getViewFactoryName} from './util';
|
||||
|
||||
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
|
||||
const CLASS_ATTR = 'class';
|
||||
|
@ -38,9 +39,12 @@ export function buildView(
|
|||
Array<ViewFactoryDependency|ComponentFactoryDependency|DirectiveWrapperDependency>):
|
||||
number {
|
||||
var builderVisitor = new ViewBuilderVisitor(view, targetDependencies);
|
||||
templateVisitAll(
|
||||
builderVisitor, template,
|
||||
view.declarationElement.isNull() ? view.declarationElement : view.declarationElement.parent);
|
||||
const parentEl =
|
||||
view.declarationElement.isNull() ? view.declarationElement : view.declarationElement.parent;
|
||||
templateVisitAll(builderVisitor, template, parentEl);
|
||||
if (view.viewType === ViewType.EMBEDDED) {
|
||||
view.lastRenderNode = builderVisitor.getOrCreateLastRenderNode();
|
||||
}
|
||||
return builderVisitor.nestedViewCount;
|
||||
}
|
||||
|
||||
|
@ -73,10 +77,16 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
|||
if (this._isRootNode(parent)) {
|
||||
// store appElement as root node only for ViewContainers
|
||||
if (this.view.viewType !== ViewType.COMPONENT) {
|
||||
this.view.rootNodesOrAppElements.push(vcAppEl || node.renderNode);
|
||||
this.view.rootNodes.push(new CompileViewRootNode(
|
||||
vcAppEl ? CompileViewRootNodeType.ViewContainer : CompileViewRootNodeType.Node,
|
||||
vcAppEl || node.renderNode));
|
||||
}
|
||||
} else if (isPresent(parent.component) && isPresent(ngContentIndex)) {
|
||||
parent.addContentNode(ngContentIndex, vcAppEl || node.renderNode);
|
||||
parent.addContentNode(
|
||||
ngContentIndex,
|
||||
new CompileViewRootNode(
|
||||
vcAppEl ? CompileViewRootNodeType.ViewContainer : CompileViewRootNodeType.Node,
|
||||
vcAppEl || node.renderNode));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,6 +107,23 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
getOrCreateLastRenderNode(): o.Expression {
|
||||
const view = this.view;
|
||||
if (view.rootNodes.length === 0 ||
|
||||
view.rootNodes[view.rootNodes.length - 1].type !== CompileViewRootNodeType.Node) {
|
||||
var fieldName = `_el_${view.nodes.length}`;
|
||||
view.fields.push(
|
||||
new o.ClassField(fieldName, o.importType(view.genConfig.renderTypes.renderElement)));
|
||||
view.createMethod.addStmt(o.THIS_EXPR.prop(fieldName)
|
||||
.set(ViewProperties.renderer.callMethod(
|
||||
'createTemplateAnchor', [o.NULL_EXPR, o.NULL_EXPR]))
|
||||
.toStmt());
|
||||
view.rootNodes.push(
|
||||
new CompileViewRootNode(CompileViewRootNodeType.Node, o.THIS_EXPR.prop(fieldName)))
|
||||
}
|
||||
return view.rootNodes[view.rootNodes.length - 1].expr;
|
||||
}
|
||||
|
||||
visitBoundText(ast: BoundTextAst, parent: CompileElement): any {
|
||||
return this._visitText(ast, '', parent);
|
||||
}
|
||||
|
@ -129,9 +156,6 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
|||
// have debug information for them...
|
||||
this.view.createMethod.resetDebugInfo(null, ast);
|
||||
var parentRenderNode = this._getParentRenderNode(parent);
|
||||
var nodesExpression = ViewProperties.projectableNodes.key(
|
||||
o.literal(ast.index),
|
||||
new o.ArrayType(o.importType(this.view.genConfig.renderTypes.renderNode)));
|
||||
if (parentRenderNode !== o.NULL_EXPR) {
|
||||
this.view.createMethod.addStmt(
|
||||
ViewProperties.renderer
|
||||
|
@ -139,18 +163,20 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
|||
'projectNodes',
|
||||
[
|
||||
parentRenderNode,
|
||||
o.importExpr(resolveIdentifier(Identifiers.flattenNestedViewRenderNodes))
|
||||
.callFn([nodesExpression])
|
||||
o.THIS_EXPR.callMethod('projectedNodes', [o.literal(ast.index)])
|
||||
])
|
||||
.toStmt());
|
||||
} else if (this._isRootNode(parent)) {
|
||||
if (this.view.viewType !== ViewType.COMPONENT) {
|
||||
// store root nodes only for embedded/host views
|
||||
this.view.rootNodesOrAppElements.push(nodesExpression);
|
||||
this.view.rootNodes.push(
|
||||
new CompileViewRootNode(CompileViewRootNodeType.NgContent, null, ast.index));
|
||||
}
|
||||
} else {
|
||||
if (isPresent(parent.component) && isPresent(ast.ngContentIndex)) {
|
||||
parent.addContentNode(ast.ngContentIndex, nodesExpression);
|
||||
parent.addContentNode(
|
||||
ast.ngContentIndex,
|
||||
new CompileViewRootNode(CompileViewRootNodeType.NgContent, null, ast.index));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -220,18 +246,8 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
|||
compileElement.afterChildren(this.view.nodes.length - nodeIndex - 1);
|
||||
|
||||
if (isPresent(compViewExpr)) {
|
||||
var codeGenContentNodes: o.Expression;
|
||||
if (this.view.component.type.isHost) {
|
||||
codeGenContentNodes = ViewProperties.projectableNodes;
|
||||
} else {
|
||||
codeGenContentNodes = o.literalArr(
|
||||
compileElement.contentNodesByNgContentIndex.map(nodes => createFlatArray(nodes)));
|
||||
}
|
||||
this.view.createMethod.addStmt(
|
||||
compViewExpr
|
||||
.callMethod(
|
||||
'create', [compileElement.getComponent(), codeGenContentNodes, o.NULL_EXPR])
|
||||
.toStmt());
|
||||
compViewExpr.callMethod('create', [compileElement.getComponent(), o.NULL_EXPR]).toStmt());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -457,7 +473,8 @@ function createViewClass(
|
|||
generateDetectChangesMethod(view)),
|
||||
new o.ClassMethod('dirtyParentQueriesInternal', [], view.dirtyParentQueriesMethod.finish()),
|
||||
new o.ClassMethod('destroyInternal', [], generateDestroyMethod(view)),
|
||||
new o.ClassMethod('detachInternal', [], view.detachMethod.finish())
|
||||
new o.ClassMethod('detachInternal', [], view.detachMethod.finish()),
|
||||
generateVisitRootNodesMethod(view), generateVisitProjectableNodesMethod(view)
|
||||
].filter((method) => method.body.length > 0);
|
||||
var superClass = view.genConfig.genDebugInfo ? Identifiers.DebugAppView : Identifiers.AppView;
|
||||
|
||||
|
@ -554,7 +571,7 @@ function generateCreateMethod(view: CompileView): o.Statement[] {
|
|||
.callMethod(
|
||||
'init',
|
||||
[
|
||||
createFlatArray(view.rootNodesOrAppElements),
|
||||
view.lastRenderNode,
|
||||
o.literalArr(view.nodes.map(node => node.renderNode)),
|
||||
o.literalArr(view.disposables),
|
||||
])
|
||||
|
@ -634,3 +651,61 @@ function getChangeDetectionMode(view: CompileView): ChangeDetectorStatus {
|
|||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
function generateVisitRootNodesMethod(view: CompileView): o.ClassMethod {
|
||||
const cbVar = o.variable('cb');
|
||||
const ctxVar = o.variable('ctx');
|
||||
const stmts: o.Statement[] = generateVisitNodesStmts(view.rootNodes, cbVar, ctxVar);
|
||||
return new o.ClassMethod(
|
||||
'visitRootNodesInternal',
|
||||
[new o.FnParam(cbVar.name, o.DYNAMIC_TYPE), new o.FnParam(ctxVar.name, o.DYNAMIC_TYPE)],
|
||||
stmts);
|
||||
}
|
||||
|
||||
function generateVisitProjectableNodesMethod(view: CompileView): o.ClassMethod {
|
||||
const nodeIndexVar = o.variable('nodeIndex');
|
||||
const ngContentIndexVar = o.variable('ngContentIndex');
|
||||
const cbVar = o.variable('cb');
|
||||
const ctxVar = o.variable('ctx');
|
||||
const stmts: o.Statement[] = [];
|
||||
view.nodes.forEach((node) => {
|
||||
if (node instanceof CompileElement && node.component) {
|
||||
node.contentNodesByNgContentIndex.forEach((projectedNodes, ngContentIndex) => {
|
||||
stmts.push(new o.IfStmt(
|
||||
nodeIndexVar.equals(o.literal(node.nodeIndex))
|
||||
.and(ngContentIndexVar.equals(o.literal(ngContentIndex))),
|
||||
generateVisitNodesStmts(projectedNodes, cbVar, ctxVar)));
|
||||
});
|
||||
}
|
||||
});
|
||||
return new o.ClassMethod(
|
||||
'visitProjectableNodesInternal',
|
||||
[
|
||||
new o.FnParam(nodeIndexVar.name, o.NUMBER_TYPE),
|
||||
new o.FnParam(ngContentIndexVar.name, o.NUMBER_TYPE),
|
||||
new o.FnParam(cbVar.name, o.DYNAMIC_TYPE), new o.FnParam(ctxVar.name, o.DYNAMIC_TYPE)
|
||||
],
|
||||
stmts);
|
||||
}
|
||||
|
||||
function generateVisitNodesStmts(
|
||||
nodes: CompileViewRootNode[], cb: o.Expression, ctx: o.Expression): o.Statement[] {
|
||||
const stmts: o.Statement[] = [];
|
||||
nodes.forEach((node) => {
|
||||
switch (node.type) {
|
||||
case CompileViewRootNodeType.Node:
|
||||
stmts.push(cb.callFn([node.expr, ctx]).toStmt());
|
||||
break;
|
||||
case CompileViewRootNodeType.ViewContainer:
|
||||
stmts.push(cb.callFn([node.expr.prop('nativeElement'), ctx]).toStmt());
|
||||
stmts.push(node.expr.callMethod('visitNestedViewRootNodes', [cb, ctx]).toStmt());
|
||||
break;
|
||||
case CompileViewRootNodeType.NgContent:
|
||||
stmts.push(
|
||||
o.THIS_EXPR.callMethod('visitProjectedNodes', [o.literal(node.ngContentIndex), cb, ctx])
|
||||
.toStmt());
|
||||
break;
|
||||
}
|
||||
});
|
||||
return stmts;
|
||||
}
|
||||
|
|
|
@ -10,8 +10,10 @@ import {ChangeDetectorRef} from '../change_detection/change_detection';
|
|||
import {Injector} from '../di/injector';
|
||||
import {unimplemented} from '../facade/errors';
|
||||
import {Type} from '../type';
|
||||
|
||||
import {AppElement} from './element';
|
||||
import {ElementRef} from './element_ref';
|
||||
import {AppView} from './view';
|
||||
import {ViewRef} from './view_ref';
|
||||
import {ViewUtils} from './view_utils';
|
||||
|
||||
|
@ -104,8 +106,15 @@ export class ComponentFactory<C> {
|
|||
projectableNodes = [];
|
||||
}
|
||||
// Note: Host views don't need a declarationAppElement!
|
||||
var hostView = this._viewFactory(vu, injector, null);
|
||||
var hostElement = hostView.create(EMPTY_CONTEXT, projectableNodes, rootSelectorOrNode);
|
||||
var hostView: AppView<any> = this._viewFactory(vu, injector, null);
|
||||
hostView.visitProjectableNodesInternal =
|
||||
(nodeIndex: number, ngContentIndex: number, cb: any, ctx: any) => {
|
||||
const nodes = projectableNodes[ngContentIndex] || [];
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
cb(nodes[i], ctx);
|
||||
}
|
||||
};
|
||||
var hostElement = hostView.create(EMPTY_CONTEXT, rootSelectorOrNode);
|
||||
return new ComponentRef_<C>(hostElement, this._componentType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,14 @@ export class AppElement {
|
|||
}
|
||||
}
|
||||
|
||||
visitNestedViewRootNodes<C>(cb: (node: any, ctx: C) => void, c: C): void {
|
||||
if (this.nestedViews) {
|
||||
for (var i = 0; i < this.nestedViews.length; i++) {
|
||||
this.nestedViews[i].visitRootNodesInternal(cb, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapNestedViews(nestedViewClass: any, callback: Function): any[] {
|
||||
var result: any[] /** TODO #9100 */ = [];
|
||||
if (isPresent(this.nestedViews)) {
|
||||
|
|
|
@ -48,7 +48,7 @@ export class TemplateRef_<C> extends TemplateRef<C> {
|
|||
createEmbeddedView(context: C): EmbeddedViewRef<C> {
|
||||
var view: AppView<C> = this._viewFactory(
|
||||
this._appElement.parentView.viewUtils, this._appElement.parentInjector, this._appElement);
|
||||
view.create(context || <any>{}, null, null);
|
||||
view.create(context || <any>{}, null);
|
||||
return view.ref;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import {ElementInjector} from './element_injector';
|
|||
import {ExpressionChangedAfterItHasBeenCheckedError, ViewDestroyedError, ViewWrappedError} from './errors';
|
||||
import {ViewRef_} from './view_ref';
|
||||
import {ViewType} from './view_type';
|
||||
import {ViewUtils, ensureSlotCount, flattenNestedViewRenderNodes} from './view_utils';
|
||||
import {ViewUtils, addToArray} from './view_utils';
|
||||
|
||||
var _scope_check: WtfScopeFn = wtfCreateScope(`AppView#check(ascii id)`);
|
||||
|
||||
|
@ -30,15 +30,13 @@ var _scope_check: WtfScopeFn = wtfCreateScope(`AppView#check(ascii id)`);
|
|||
*/
|
||||
export abstract class AppView<T> {
|
||||
ref: ViewRef_<T>;
|
||||
rootNodesOrAppElements: any[];
|
||||
lastRootNode: any;
|
||||
allNodes: any[];
|
||||
disposables: Function[];
|
||||
viewContainerElement: AppElement = null;
|
||||
|
||||
numberOfChecks: number = 0;
|
||||
|
||||
projectableNodes: Array<any|any[]>;
|
||||
|
||||
renderer: Renderer;
|
||||
|
||||
private _hasExternalHostElement: boolean;
|
||||
|
@ -67,25 +65,9 @@ export abstract class AppView<T> {
|
|||
|
||||
get destroyed(): boolean { return this.cdMode === ChangeDetectorStatus.Destroyed; }
|
||||
|
||||
create(context: T, givenProjectableNodes: Array<any|any[]>, rootSelectorOrNode: string|any):
|
||||
AppElement {
|
||||
create(context: T, rootSelectorOrNode: string|any): AppElement {
|
||||
this.context = context;
|
||||
var projectableNodes: any[];
|
||||
switch (this.type) {
|
||||
case ViewType.COMPONENT:
|
||||
projectableNodes = ensureSlotCount(givenProjectableNodes, this.componentType.slotCount);
|
||||
break;
|
||||
case ViewType.EMBEDDED:
|
||||
projectableNodes = this.declarationAppElement.parentView.projectableNodes;
|
||||
break;
|
||||
case ViewType.HOST:
|
||||
// Note: Don't ensure the slot count for the projectableNodes as we store
|
||||
// them only for the contained component view (which will later check the slot count...)
|
||||
projectableNodes = givenProjectableNodes;
|
||||
break;
|
||||
}
|
||||
this._hasExternalHostElement = isPresent(rootSelectorOrNode);
|
||||
this.projectableNodes = projectableNodes;
|
||||
return this.createInternal(rootSelectorOrNode);
|
||||
}
|
||||
|
||||
|
@ -95,8 +77,8 @@ export abstract class AppView<T> {
|
|||
*/
|
||||
createInternal(rootSelectorOrNode: string|any): AppElement { return null; }
|
||||
|
||||
init(rootNodesOrAppElements: any[], allNodes: any[], disposables: Function[]) {
|
||||
this.rootNodesOrAppElements = rootNodesOrAppElements;
|
||||
init(lastRootNode: any, allNodes: any[], disposables: Function[]) {
|
||||
this.lastRootNode = lastRootNode;
|
||||
this.allNodes = allNodes;
|
||||
this.disposables = disposables;
|
||||
if (this.type === ViewType.COMPONENT) {
|
||||
|
@ -180,15 +162,41 @@ export abstract class AppView<T> {
|
|||
return isPresent(this.declarationAppElement) ? this.declarationAppElement.parentView : null;
|
||||
}
|
||||
|
||||
get flatRootNodes(): any[] { return flattenNestedViewRenderNodes(this.rootNodesOrAppElements); }
|
||||
|
||||
get lastRootNode(): any {
|
||||
var lastNode = this.rootNodesOrAppElements.length > 0 ?
|
||||
this.rootNodesOrAppElements[this.rootNodesOrAppElements.length - 1] :
|
||||
null;
|
||||
return _findLastRenderNode(lastNode);
|
||||
get flatRootNodes(): any[] {
|
||||
const nodes: any[] = [];
|
||||
this.visitRootNodesInternal(addToArray, nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
projectedNodes(ngContentIndex: number): any[] {
|
||||
const nodes: any[] = [];
|
||||
this.visitProjectedNodes(ngContentIndex, addToArray, nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
visitProjectedNodes<C>(ngContentIndex: number, cb: (node: any, ctx: C) => void, c: C): void {
|
||||
const appEl = this.declarationAppElement;
|
||||
switch (this.type) {
|
||||
case ViewType.EMBEDDED:
|
||||
appEl.parentView.visitProjectedNodes(ngContentIndex, cb, c);
|
||||
break;
|
||||
case ViewType.COMPONENT:
|
||||
appEl.parentView.visitProjectableNodesInternal(appEl.index, ngContentIndex, cb, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
visitRootNodesInternal<C>(cb: (node: any, ctx: C) => void, c: C): void {}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
visitProjectableNodesInternal<C>(
|
||||
nodeIndex: number, ngContentIndex: number, cb: (node: any, ctx: C) => void, c: C): void {}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
|
@ -258,11 +266,10 @@ export class DebugAppView<T> extends AppView<T> {
|
|||
super(clazz, componentType, type, viewUtils, parentInjector, declarationAppElement, cdMode);
|
||||
}
|
||||
|
||||
create(context: T, givenProjectableNodes: Array<any|any[]>, rootSelectorOrNode: string|any):
|
||||
AppElement {
|
||||
create(context: T, rootSelectorOrNode: string|any): AppElement {
|
||||
this._resetDebug();
|
||||
try {
|
||||
return super.create(context, givenProjectableNodes, rootSelectorOrNode);
|
||||
return super.create(context, rootSelectorOrNode);
|
||||
} catch (e) {
|
||||
this._rethrowWithContext(e);
|
||||
throw e;
|
||||
|
@ -339,24 +346,3 @@ export class DebugAppView<T> extends AppView<T> {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
function _findLastRenderNode(node: any): any {
|
||||
var lastNode: any;
|
||||
if (node instanceof AppElement) {
|
||||
var appEl = <AppElement>node;
|
||||
lastNode = appEl.nativeElement;
|
||||
if (isPresent(appEl.nestedViews)) {
|
||||
// Note: Views might have no root nodes at all!
|
||||
for (var i = appEl.nestedViews.length - 1; i >= 0; i--) {
|
||||
var nestedView = appEl.nestedViews[i];
|
||||
if (nestedView.rootNodesOrAppElements.length > 0) {
|
||||
lastNode = _findLastRenderNode(
|
||||
nestedView.rootNodesOrAppElements[nestedView.rootNodesOrAppElements.length - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lastNode = node;
|
||||
}
|
||||
return lastNode;
|
||||
}
|
||||
|
|
|
@ -48,44 +48,8 @@ export class ViewUtils {
|
|||
}
|
||||
}
|
||||
|
||||
export function flattenNestedViewRenderNodes(nodes: any[]): any[] {
|
||||
return _flattenNestedViewRenderNodes(nodes, []);
|
||||
}
|
||||
|
||||
function _flattenNestedViewRenderNodes(nodes: any[], renderNodes: any[]): any[] {
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var node = nodes[i];
|
||||
if (node instanceof AppElement) {
|
||||
var appEl = <AppElement>node;
|
||||
renderNodes.push(appEl.nativeElement);
|
||||
if (isPresent(appEl.nestedViews)) {
|
||||
for (var k = 0; k < appEl.nestedViews.length; k++) {
|
||||
_flattenNestedViewRenderNodes(appEl.nestedViews[k].rootNodesOrAppElements, renderNodes);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
renderNodes.push(node);
|
||||
}
|
||||
}
|
||||
return renderNodes;
|
||||
}
|
||||
|
||||
const EMPTY_ARR: any[] = [];
|
||||
|
||||
export function ensureSlotCount(projectableNodes: any[][], expectedSlotCount: number): any[][] {
|
||||
var res: any[][];
|
||||
if (!projectableNodes) {
|
||||
res = EMPTY_ARR;
|
||||
} else if (projectableNodes.length < expectedSlotCount) {
|
||||
var givenSlotCount = projectableNodes.length;
|
||||
res = new Array(expectedSlotCount);
|
||||
for (var i = 0; i < expectedSlotCount; i++) {
|
||||
res[i] = (i < givenSlotCount) ? projectableNodes[i] : EMPTY_ARR;
|
||||
}
|
||||
} else {
|
||||
res = projectableNodes;
|
||||
}
|
||||
return res;
|
||||
export function addToArray(e: any, array: any[]) {
|
||||
array.push(e);
|
||||
}
|
||||
|
||||
export const MAX_INTERPOLATION_VALUES = 9;
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
*/
|
||||
|
||||
import {Component, Directive, ElementRef, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
||||
import {getAllDebugNodes} from '@angular/core/src/debug/debug_node';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {beforeEach, describe, it} from '@angular/core/testing/testing_internal';
|
||||
import {beforeEach, ddescribe, describe, iit, it} from '@angular/core/testing/testing_internal';
|
||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||
|
@ -236,6 +235,13 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should support moving non projected light dom around', () => {
|
||||
let sourceDirective: ManualViewportDirective;
|
||||
|
||||
@Directive({selector: '[manual]'})
|
||||
class ManualViewportDirective {
|
||||
constructor(public templateRef: TemplateRef<Object>) { sourceDirective = this; }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule(
|
||||
{declarations: [Empty, ProjectDirective, ManualViewportDirective]});
|
||||
TestBed.overrideComponent(MainComp, {
|
||||
|
@ -248,17 +254,6 @@ export function main() {
|
|||
});
|
||||
const main = TestBed.createComponent(MainComp);
|
||||
|
||||
var sourceDirective: any;
|
||||
|
||||
// We can't use the child nodes to get a hold of this because it's not in the dom
|
||||
// at
|
||||
// all.
|
||||
getAllDebugNodes().forEach((debug) => {
|
||||
if (debug.providerTokens.indexOf(ManualViewportDirective) !== -1) {
|
||||
sourceDirective = debug.injector.get(ManualViewportDirective);
|
||||
}
|
||||
});
|
||||
|
||||
var projectDirective: ProjectDirective =
|
||||
main.debugElement.queryAllNodes(By.directive(ProjectDirective))[0].injector.get(
|
||||
ProjectDirective);
|
||||
|
|
|
@ -43,8 +43,7 @@ class _View_TreeRootComponent_Host0 extends import1.AppView<any> {
|
|||
viewFactory_TreeRootComponent0(this.viewUtils, this.injector(0), this._appEl_0);
|
||||
this._TreeRootComponent_0_4 = new import3.TreeRootComponent();
|
||||
this._appEl_0.initComponent(this._TreeRootComponent_0_4, [], this._TreeRootComponent_0_4_View);
|
||||
this._TreeRootComponent_0_4_View.create(
|
||||
this._TreeRootComponent_0_4, this.projectableNodes, (null as any));
|
||||
this._TreeRootComponent_0_4_View.create(this._TreeRootComponent_0_4, (null as any));
|
||||
this.init([].concat([this._el_0]), [this._el_0], []);
|
||||
return this._appEl_0;
|
||||
}
|
||||
|
@ -147,6 +146,7 @@ class _View_TreeRootComponent1 extends import1.AppView<any> {
|
|||
this._TreeComponent0_0_4View.updateData(this.parent.context.data);
|
||||
this._TreeComponent0_0_4View.detectChangesInternal(throwOnChange);
|
||||
}
|
||||
visitRootNodesInternal(cb: any, context: any) { cb(this._el_0, context); }
|
||||
}
|
||||
function viewFactory_TreeRootComponent1(
|
||||
viewUtils: import4.ViewUtils, parentInjector: import5.Injector,
|
||||
|
|
Loading…
Reference in New Issue