refactor(compiler): remove view.rootNodes
and view.projectableNodes
They are replaced by generated visitor functions `view.visitRootNodes` / `view.visitProjectableNodes`.
This commit is contained in:
@ -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);
|
||||
|
Reference in New Issue
Block a user