Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/core/src/render3/di.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {Type} from '../type';

import {assertGreaterThan, assertLessThan, assertNotNull} from './assert';
import {addToViewTree, assertPreviousIsParent, createLContainer, createLNodeObject, createTView, getDirectiveInstance, getPreviousOrParentNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions';
import {LContainer} from './interfaces/container';
import {ComponentTemplate, DirectiveDef, DirectiveDefList, PipeDefList} from './interfaces/definition';
import {LInjector} from './interfaces/injector';
import {LContainerNode, LElementNode, LNode, LNodeType, LViewNode, TNodeFlags} from './interfaces/node';
Expand Down Expand Up @@ -573,6 +572,8 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainer
const lContainerNode: LContainerNode = createLNodeObject(
LNodeType.Container, vcRefHost.view, vcRefHost.parent !, undefined, lContainer, null);

// TODO(kara): Separate into own TNode when moving parent/child properties
lContainerNode.tNode = vcRefHost.tNode;
vcRefHost.dynamicLContainerNode = lContainerNode;

addToViewTree(vcRefHost.view, lContainer);
Expand Down
97 changes: 51 additions & 46 deletions packages/core/src/render3/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {CurrentMatchesList, LView, LViewFlags, LifecycleStage, RootContext, TDat

import {LContainerNode, LElementNode, LNode, LNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue,} from './interfaces/node';
import {assertNodeType} from './node_assert';
import {appendChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode} from './node_manipulation';
import {appendChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode, getNextLNode} from './node_manipulation';
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, PipeDefList, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
Expand Down Expand Up @@ -346,7 +346,6 @@ export function createLNodeObject(
view: currentView,
parent: parent as any,
child: null,
next: null,
nodeInjector: parent ? parent.nodeInjector : null,
data: state,
queries: queries,
Expand All @@ -359,22 +358,31 @@ export function createLNodeObject(
/**
* A common way of creating the LNode to make sure that all of them have same shape to
* keep the execution code monomorphic and fast.
*
* @param index The index at which the LNode should be saved (null if view, since they are not
* saved)
* @param type The type of LNode to create
* @param native The native element for this LNode, if applicable
* @param name The tag name of the associated native element, if applicable
* @param attrs Any attrs for the native element, if applicable
* @param data Any data that should be saved on the LNode
*/
export function createLNode(
index: number | null, type: LNodeType.Element, native: RElement | RText | null,
lView?: LView | null): LElementNode;
name: string | null, attrs: string[] | null, lView?: LView | null): LElementNode;
export function createLNode(
index: null, type: LNodeType.View, native: null, lView: LView): LViewNode;
index: null, type: LNodeType.View, native: null, name: null, attrs: null,
lView: LView): LViewNode;
export function createLNode(
index: number, type: LNodeType.Container, native: undefined,
lContainer: LContainer): LContainerNode;
index: number, type: LNodeType.Container, native: undefined, name: string | null,
attrs: string[] | null, lContainer: LContainer): LContainerNode;
export function createLNode(
index: number, type: LNodeType.Projection, native: null,
index: number, type: LNodeType.Projection, native: null, name: null, attrs: string[] | null,
lProjection: LProjection): LProjectionNode;
export function createLNode(
index: number | null, type: LNodeType, native: RText | RElement | null | undefined,
state?: null | LView | LContainer | LProjection): LElementNode&LTextNode&LViewNode&
LContainerNode&LProjectionNode {
name: string | null, attrs: string[] | null, state?: null | LView | LContainer |
LProjection): LElementNode&LTextNode&LViewNode&LContainerNode&LProjectionNode {
const parent = isParent ? previousOrParentNode :
previousOrParentNode && previousOrParentNode.parent as LNode;
let queries =
Expand All @@ -397,10 +405,12 @@ export function createLNode(

// Every node adds a value to the static data array to avoid a sparse array
if (index >= tData.length) {
tData[index] = null;
} else {
node.tNode = tData[index] as TNode;
const tNode = tData[index] = createTNode(index, name, attrs, null);
if (!isParent && previousOrParentNode) {
previousOrParentNode.tNode !.next = tNode;
}
}
node.tNode = tData[index] as TNode;

// Now link ourselves into the tree.
if (isParent) {
Expand All @@ -415,14 +425,6 @@ export function createLNode(
} else {
// We are adding component view, so we don't link parent node child to this node.
}
} else if (previousOrParentNode) {
ngDevMode && assertNull(
previousOrParentNode.next,
`previousOrParentNode's next property should not have been set ${index}.`);
previousOrParentNode.next = node;
if (previousOrParentNode.dynamicLContainerNode) {
previousOrParentNode.dynamicLContainerNode.next = node;
}
}
}
previousOrParentNode = node;
Expand Down Expand Up @@ -463,7 +465,7 @@ export function renderTemplate<T>(
rendererFactory = providedRendererFactory;
const tView = getOrCreateTView(template, directives || null, pipes || null);
host = createLNode(
null, LNodeType.Element, hostNode,
null, LNodeType.Element, hostNode, null, null,
createLView(
-1, providedRendererFactory.createRenderer(null, null), tView, null, {},
LViewFlags.CheckAlways, sanitizer));
Expand Down Expand Up @@ -500,7 +502,7 @@ export function renderEmbeddedTemplate<T>(
const lView = createLView(
-1, renderer, tView, template, context, LViewFlags.CheckAlways, getCurrentSanitizer());

viewNode = createLNode(null, LNodeType.View, null, lView);
viewNode = createLNode(null, LNodeType.View, null, null, null, lView);
rf = RenderFlags.Create;
}
oldView = enterView(viewNode.data, viewNode);
Expand Down Expand Up @@ -585,7 +587,10 @@ export function elementStart(

ngDevMode && ngDevMode.rendererCreateElement++;
const native: RElement = renderer.createElement(name);
const node: LElementNode = createLNode(index, LNodeType.Element, native !, null);
ngDevMode && assertDataInRange(index - 1);

const node: LElementNode =
createLNode(index, LNodeType.Element, native !, name, attrs || null, null);

if (attrs) setUpAttributes(native, attrs);
appendChild(node.parent !, native, currentView);
Expand All @@ -608,9 +613,7 @@ function createDirectivesAndLocals(
const node = previousOrParentNode;
if (firstTemplatePass) {
ngDevMode && ngDevMode.firstTemplatePass++;
ngDevMode && assertDataInRange(index - 1);
node.tNode = tData[index] = createTNode(name, attrs || null, inlineViews ? [] : null);
cacheMatchingDirectivesForNode(node.tNode, currentView.tView, localRefs || null);
cacheMatchingDirectivesForNode(node.tNode !, currentView.tView, localRefs || null);
} else {
instantiateDirectivesDirectly();
}
Expand Down Expand Up @@ -870,14 +873,13 @@ export function hostElement(
sanitizer?: Sanitizer | null): LElementNode {
resetApplicationState();
const node = createLNode(
0, LNodeType.Element, rNode,
0, LNodeType.Element, rNode, null, null,
createLView(
-1, renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs), null, null,
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, sanitizer));

if (firstTemplatePass) {
node.tNode = createTNode(tag as string, null, null);
node.tNode.flags = TNodeFlags.isComponent;
node.tNode !.flags = TNodeFlags.isComponent;
if (def.diPublic) def.diPublic(def);
currentView.tView.directives = [def];
}
Expand Down Expand Up @@ -1028,24 +1030,26 @@ export function elementProperty<T>(
/**
* Constructs a TNode object from the arguments.
*
* @param index The index of the TNode in TView.data
* @param tagName The tag name of the node
* @param attrs The attributes defined on this ndoe
* @param attrs The attributes defined on this node
* @param tViews Any TViews attached to this node
* @param localNames A list of local names and their matching indices
* @returns the TNode object
*/
function createTNode(
tagName: string | null, attrs: string[] | null, tViews: TView[] | null): TNode {
index: number, tagName: string | null, attrs: string[] | null, tViews: TView[] | null): TNode {
ngDevMode && ngDevMode.tNode++;
return {
index: index,
flags: 0,
tagName: tagName,
attrs: attrs,
localNames: null,
initialInputs: undefined,
inputs: undefined,
outputs: undefined,
tViews: tViews
tViews: tViews,
next: null
};
}

Expand Down Expand Up @@ -1240,7 +1244,8 @@ export function text(index: number, value?: any): void {
currentView.bindingStartIndex, -1, 'text nodes should be created before bindings');
ngDevMode && ngDevMode.rendererCreateTextNode++;
const textNode = createTextNode(value, renderer);
const node = createLNode(index, LNodeType.Element, textNode);
const node = createLNode(index, LNodeType.Element, textNode, null, null);

// Text nodes are self closing.
isParent = false;
appendChild(node.parent !, textNode, currentView);
Expand Down Expand Up @@ -1473,7 +1478,10 @@ export function container(
const currentParent = isParent ? previousOrParentNode : previousOrParentNode.parent !;
const lContainer = createLContainer(currentParent, currentView, template);

const node = createLNode(index, LNodeType.Container, undefined, lContainer);
const node = createLNode(
index, LNodeType.Container, undefined, tagName || null, attrs || null, lContainer);

if (firstTemplatePass && template == null) node.tNode !.tViews = [];

// Containers are added to the current view tree instead of their embedded views
// because views can be removed and re-inserted.
Expand Down Expand Up @@ -1610,7 +1618,7 @@ export function embeddedViewStart(viewBlockId: number): RenderFlags {
newView.queries = lContainer.queries.enterView(lContainer.nextIndex);
}

enterView(newView, viewNode = createLNode(null, LNodeType.View, null, newView));
enterView(newView, viewNode = createLNode(null, LNodeType.View, null, null, null, newView));
}
return getRenderFlags(viewNode.data);
}
Expand Down Expand Up @@ -1673,7 +1681,7 @@ export function embeddedViewEnd(): void {
function setRenderParentInProjectedNodes(
renderParent: LElementNode | null, viewNode: LViewNode): void {
if (renderParent != null) {
let node = viewNode.child;
let node: LNode|null = viewNode.child;
while (node) {
if (node.type === LNodeType.Projection) {
let nodeToProject: LNode|null = (node as LProjectionNode).data.head;
Expand All @@ -1685,7 +1693,7 @@ function setRenderParentInProjectedNodes(
nodeToProject = nodeToProject === lastNodeToProject ? null : nodeToProject.pNextOrParent;
}
}
node = node.next;
node = getNextLNode(node);
}
}
}
Expand Down Expand Up @@ -1749,8 +1757,8 @@ export function projectionDef(
distributedNodes[i] = [];
}

const componentNode = findComponentHost(currentView);
let componentChild = componentNode.child;
const componentNode: LElementNode = findComponentHost(currentView);
let componentChild: LNode|null = componentNode.child;

while (componentChild !== null) {
// execute selector matching logic if and only if:
Expand All @@ -1763,7 +1771,7 @@ export function projectionDef(
distributedNodes[0].push(componentChild);
}

componentChild = componentChild.next;
componentChild = getNextLNode(componentChild);
}

ngDevMode && assertDataNext(index);
Expand Down Expand Up @@ -1810,11 +1818,8 @@ function appendToProjectionNode(
*/
export function projection(
nodeIndex: number, localIndex: number, selectorIndex: number = 0, attrs?: string[]): void {
const node = createLNode(nodeIndex, LNodeType.Projection, null, {head: null, tail: null});

if (node.tNode == null) {
node.tNode = createTNode(null, attrs || null, null);
}
const node = createLNode(
nodeIndex, LNodeType.Projection, null, null, attrs || null, {head: null, tail: null});

// `<ng-content>` has no content
isParent = false;
Expand Down
25 changes: 14 additions & 11 deletions packages/core/src/render3/interfaces/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,6 @@ export interface LNode {
*/
child: LNode|null;

/**
* The next sibling node. Necessary so we can propagate through the root nodes of a view
* to insert them or remove them from the DOM.
*/
next: LNode|null;

/**
* If regular LElementNode, then `data` will be null.
* If LElementNode with component, then `data` contains LView.
Expand Down Expand Up @@ -139,7 +133,6 @@ export interface LElementNode extends LNode {
readonly native: RElement;

child: LContainerNode|LElementNode|LTextNode|LProjectionNode|null;
next: LContainerNode|LElementNode|LTextNode|LProjectionNode|null;

/** If Component then data has LView (light DOM) */
readonly data: LView|null;
Expand All @@ -153,7 +146,6 @@ export interface LTextNode extends LNode {
/** The text node associated with this node. */
native: RText;
child: null;
next: LContainerNode|LElementNode|LTextNode|LProjectionNode|null;

/** LTextNodes can be inside LElementNodes or inside LViewNodes. */
readonly parent: LElementNode|LViewNode;
Expand All @@ -165,7 +157,6 @@ export interface LTextNode extends LNode {
export interface LViewNode extends LNode {
readonly native: null;
child: LContainerNode|LElementNode|LTextNode|LProjectionNode|null;
next: LViewNode|null;

/** LViewNodes can only be added to LContainerNodes. */
readonly parent: LContainerNode|null;
Expand All @@ -185,7 +176,6 @@ export interface LContainerNode extends LNode {
native: RElement|RText|null|undefined;
readonly data: LContainer;
child: null;
next: LContainerNode|LElementNode|LTextNode|LProjectionNode|null;

/** Containers can be added to elements or views. */
readonly parent: LElementNode|LViewNode|null;
Expand All @@ -195,7 +185,6 @@ export interface LContainerNode extends LNode {
export interface LProjectionNode extends LNode {
readonly native: null;
child: null;
next: LContainerNode|LElementNode|LTextNode|LProjectionNode|null;

readonly data: LProjection;

Expand All @@ -216,6 +205,14 @@ export interface LProjectionNode extends LNode {
* see: https://en.wikipedia.org/wiki/Flyweight_pattern for more on the Flyweight pattern
*/
export interface TNode {
/**
* Index of the TNode in TView.data and corresponding LNode in LView.data.
*
* This is necessary to get from any TNode to its corresponding LNode when
* traversing the node tree.
*/
index: number;

/**
* This number stores two values using its bits:
*
Expand Down Expand Up @@ -303,6 +300,12 @@ export interface TNode {
* If this TNode corresponds to an LElementNode, tViews will be null .
*/
tViews: TView|TView[]|null;

/**
* The next sibling node. Necessary so we can propagate through the root nodes of a view
* to insert them or remove them from the DOM.
*/
next: TNode|null;
}

/** Static data for an LElementNode */
Expand Down
Loading