parent
5a624fa1be
commit
5df626bbe1
|
@ -9,8 +9,7 @@
|
||||||
import {LContainerNode, LElementNode, LTextNode} from './node';
|
import {LContainerNode, LElementNode, LTextNode} from './node';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An LProjection is a pointer to the first and the last projected nodes.
|
* Linked list of projected nodes (using the pNextOrParent property).
|
||||||
* It is a linked list (using the pNextOrParent property).
|
|
||||||
*/
|
*/
|
||||||
export interface LProjection {
|
export interface LProjection {
|
||||||
head: LElementNode|LTextNode|LContainerNode|null;
|
head: LElementNode|LTextNode|LContainerNode|null;
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {Renderer3} from './renderer';
|
||||||
* they are invoked from the template. Each embedded view and component view has its
|
* they are invoked from the template. Each embedded view and component view has its
|
||||||
* own `LView`. When processing a particular view, we set the `currentView` to that
|
* own `LView`. When processing a particular view, we set the `currentView` to that
|
||||||
* `LView`. When that view is done processing, the `currentView` is set back to
|
* `LView`. When that view is done processing, the `currentView` is set back to
|
||||||
* whatever the original `currentView` was before(the parent `LView`).
|
* whatever the original `currentView` was before (the parent `LView`).
|
||||||
*
|
*
|
||||||
* Keeping separate state for each view facilities view insertion / deletion, so we
|
* Keeping separate state for each view facilities view insertion / deletion, so we
|
||||||
* don't have to edit the data array based on which views are present.
|
* don't have to edit the data array based on which views are present.
|
||||||
|
|
|
@ -18,25 +18,25 @@ import {assertNodeType} from './node_assert';
|
||||||
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
|
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the first DOM node following the given logical node in the same parent DOM element.
|
* Returns the first RNode following the given LNode in the same parent DOM element.
|
||||||
*
|
*
|
||||||
* This is needed in order to insert the given node with insertBefore.
|
* This is needed in order to insert the given node with insertBefore.
|
||||||
*
|
*
|
||||||
* @param node The node whose following DOM node must be found.
|
* @param node The node whose following DOM node must be found.
|
||||||
* @param stopNode A parent node at which the lookup in the tree should be stopped, or null if the
|
* @param stopNode A parent node at which the lookup in the tree should be stopped, or null if the
|
||||||
* lookup should not be stopped until the result is found.
|
* lookup should not be stopped until the result is found.
|
||||||
* @returns Node before which the provided node should be inserted or null if the lookup was stopped
|
* @returns RNode before which the provided node should be inserted or null if the lookup was
|
||||||
|
* stopped
|
||||||
* or if there is no native node after the given logical node in the same native parent.
|
* or if there is no native node after the given logical node in the same native parent.
|
||||||
*/
|
*/
|
||||||
function findBeforeNode(node: LNode | null, stopNode: LNode | null): RElement|RText|null {
|
function findNextRNodeSibling(node: LNode | null, stopNode: LNode | null): RElement|RText|null {
|
||||||
let currentNode = node;
|
let currentNode = node;
|
||||||
while (currentNode && currentNode !== stopNode) {
|
while (currentNode && currentNode !== stopNode) {
|
||||||
const currentNodeType = currentNode.flags && LNodeFlags.TYPE_MASK;
|
|
||||||
let pNextOrParent = currentNode.pNextOrParent;
|
let pNextOrParent = currentNode.pNextOrParent;
|
||||||
if (pNextOrParent) {
|
if (pNextOrParent) {
|
||||||
let pNextOrParentType = pNextOrParent.flags & LNodeFlags.TYPE_MASK;
|
let pNextOrParentType = pNextOrParent.flags & LNodeFlags.TYPE_MASK;
|
||||||
while (pNextOrParentType !== LNodeFlags.Projection) {
|
while (pNextOrParentType !== LNodeFlags.Projection) {
|
||||||
const nativeNode = findFirstNativeNode(pNextOrParent);
|
const nativeNode = findFirstRNode(pNextOrParent);
|
||||||
if (nativeNode) {
|
if (nativeNode) {
|
||||||
return nativeNode;
|
return nativeNode;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ function findBeforeNode(node: LNode | null, stopNode: LNode | null): RElement|RT
|
||||||
} else {
|
} else {
|
||||||
let currentSibling = currentNode.next;
|
let currentSibling = currentNode.next;
|
||||||
while (currentSibling) {
|
while (currentSibling) {
|
||||||
const nativeNode = findFirstNativeNode(currentSibling);
|
const nativeNode = findFirstRNode(currentSibling);
|
||||||
if (nativeNode) {
|
if (nativeNode) {
|
||||||
return nativeNode;
|
return nativeNode;
|
||||||
}
|
}
|
||||||
|
@ -68,72 +68,78 @@ function findBeforeNode(node: LNode | null, stopNode: LNode | null): RElement|RT
|
||||||
/**
|
/**
|
||||||
* Get the next node in the LNode tree, taking into account the place where a node is
|
* Get the next node in the LNode tree, taking into account the place where a node is
|
||||||
* projected (in the shadow DOM) rather than where it comes from (in the light DOM).
|
* projected (in the shadow DOM) rather than where it comes from (in the light DOM).
|
||||||
* If the node is not projected, the return value is simply node.next.
|
*
|
||||||
* If the node is projected, the return value is node.pNextOrParent if node.pNextOrParent is
|
|
||||||
* not a projection node (which marks the end of the linked list).
|
|
||||||
* Otherwise the return value is null.
|
|
||||||
* @param node The node whose next node in the LNode tree must be found.
|
* @param node The node whose next node in the LNode tree must be found.
|
||||||
* @return The next sibling in the LNode tree.
|
* @return LNode|null The next sibling in the LNode tree.
|
||||||
*/
|
*/
|
||||||
function getNextNode(node: LNode): LNode|null {
|
function getNextLNodeWithProjection(node: LNode): LNode|null {
|
||||||
const pNextOrParent = node.pNextOrParent;
|
const pNextOrParent = node.pNextOrParent;
|
||||||
|
|
||||||
if (pNextOrParent) {
|
if (pNextOrParent) {
|
||||||
return (pNextOrParent.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Projection ? null :
|
// The node is projected
|
||||||
pNextOrParent;
|
const isLastProjectedNode =
|
||||||
} else {
|
(pNextOrParent.flags & LNodeFlags.TYPE_MASK) === LNodeFlags.Projection;
|
||||||
return node.next;
|
// returns pNextOrParent if we are not at the end of the list, null otherwise
|
||||||
|
return isLastProjectedNode ? null : pNextOrParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns node.next because the the node is not projected
|
||||||
|
return node.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the next node in the LNode tree, taking into account the place where a node is
|
* Find the next node in the LNode tree, taking into account the place where a node is
|
||||||
* projected (in the shadow DOM) rather than where it comes from (in the light DOM).
|
* projected (in the shadow DOM) rather than where it comes from (in the light DOM).
|
||||||
|
*
|
||||||
* If there is no sibling node, this function goes to the next sibling of the parent node...
|
* If there is no sibling node, this function goes to the next sibling of the parent node...
|
||||||
* until it reaches rootNode (at which point null is returned).
|
* until it reaches rootNode (at which point null is returned).
|
||||||
*
|
*
|
||||||
* @param initialNode The node whose following node in the LNode tree must be found.
|
* @param initialNode The node whose following node in the LNode tree must be found.
|
||||||
* @param rootNode The root node at which the lookup should stop.
|
* @param rootNode The root node at which the lookup should stop.
|
||||||
* @return The following node in the LNode tree.
|
* @return LNode|null The following node in the LNode tree.
|
||||||
*/
|
*/
|
||||||
function getNextOrParentSiblingNode(initialNode: LNode, rootNode: LNode): LNode|null {
|
function getNextOrParentSiblingNode(initialNode: LNode, rootNode: LNode): LNode|null {
|
||||||
let node: LNode|null = initialNode;
|
let node: LNode|null = initialNode;
|
||||||
let nextNode = getNextNode(node);
|
let nextNode = getNextLNodeWithProjection(node);
|
||||||
while (node && !nextNode) {
|
while (node && !nextNode) {
|
||||||
// if node.pNextOrParent is not null here, it is not the next node
|
// if node.pNextOrParent is not null here, it is not the next node
|
||||||
// (because, at this point, nextNode is null, so it is the parent)
|
// (because, at this point, nextNode is null, so it is the parent)
|
||||||
node = node.pNextOrParent || node.parent;
|
node = node.pNextOrParent || node.parent;
|
||||||
if (node === rootNode) node = null;
|
if (node === rootNode) {
|
||||||
nextNode = node && getNextNode(node);
|
return null;
|
||||||
|
}
|
||||||
|
nextNode = node && getNextLNodeWithProjection(node);
|
||||||
}
|
}
|
||||||
return nextNode;
|
return nextNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the first DOM node inside the given logical node.
|
* Returns the first RNode inside the given LNode.
|
||||||
*
|
*
|
||||||
* @param node The node whose first DOM node must be found
|
* @param node The node whose first DOM node must be found
|
||||||
* @returns The first native node of the given logical node or null if there is none.
|
* @returns RNode The first RNode of the given LNode or null if there is none.
|
||||||
*/
|
*/
|
||||||
function findFirstNativeNode(rootNode: LNode): RElement|RText|null {
|
function findFirstRNode(rootNode: LNode): RElement|RText|null {
|
||||||
let node: LNode|null = rootNode;
|
let node: LNode|null = rootNode;
|
||||||
while (node) {
|
while (node) {
|
||||||
const type = node.flags & LNodeFlags.TYPE_MASK;
|
const type = node.flags & LNodeFlags.TYPE_MASK;
|
||||||
let nextNode: LNode|null = null;
|
let nextNode: LNode|null = null;
|
||||||
if (type === LNodeFlags.Element) {
|
if (type === LNodeFlags.Element) {
|
||||||
|
// A LElementNode has a matching RNode in LElementNode.native
|
||||||
return (node as LElementNode).native;
|
return (node as LElementNode).native;
|
||||||
} else if (type === LNodeFlags.Container) {
|
} else if (type === LNodeFlags.Container) {
|
||||||
|
// For container look at the first node of the view next
|
||||||
const childContainerData: LContainer = (node as LContainerNode).data;
|
const childContainerData: LContainer = (node as LContainerNode).data;
|
||||||
nextNode = childContainerData.views.length ? childContainerData.views[0].child : null;
|
nextNode = childContainerData.views.length ? childContainerData.views[0].child : null;
|
||||||
} else if (type === LNodeFlags.Projection) {
|
} else if (type === LNodeFlags.Projection) {
|
||||||
|
// For Projection look at the first projected node
|
||||||
nextNode = (node as LProjectionNode).data.head;
|
nextNode = (node as LProjectionNode).data.head;
|
||||||
} else {
|
} else {
|
||||||
|
// Otherwise look at the first child
|
||||||
nextNode = (node as LViewNode).child;
|
nextNode = (node as LViewNode).child;
|
||||||
}
|
}
|
||||||
if (nextNode === null) {
|
|
||||||
node = getNextOrParentSiblingNode(node, rootNode);
|
node = nextNode === null ? getNextOrParentSiblingNode(node, rootNode) : nextNode;
|
||||||
} else {
|
|
||||||
node = nextNode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -279,11 +285,11 @@ export function insertView(
|
||||||
// and we should wait until that parent processes its nodes (otherwise, we will insert this view's
|
// and we should wait until that parent processes its nodes (otherwise, we will insert this view's
|
||||||
// nodes twice - once now and once when its parent inserts its views).
|
// nodes twice - once now and once when its parent inserts its views).
|
||||||
if (container.data.renderParent !== null) {
|
if (container.data.renderParent !== null) {
|
||||||
let beforeNode = findBeforeNode(newView, container);
|
let beforeNode = findNextRNodeSibling(newView, container);
|
||||||
if (!beforeNode) {
|
if (!beforeNode) {
|
||||||
let containerNextNativeNode = container.native;
|
let containerNextNativeNode = container.native;
|
||||||
if (containerNextNativeNode === undefined) {
|
if (containerNextNativeNode === undefined) {
|
||||||
containerNextNativeNode = container.native = findBeforeNode(container, null);
|
containerNextNativeNode = container.native = findNextRNodeSibling(container, null);
|
||||||
}
|
}
|
||||||
beforeNode = containerNextNativeNode;
|
beforeNode = containerNextNativeNode;
|
||||||
}
|
}
|
||||||
|
@ -470,7 +476,7 @@ export function insertChild(node: LNode, currentView: LView): void {
|
||||||
if (canInsertNativeNode(parent, currentView)) {
|
if (canInsertNativeNode(parent, currentView)) {
|
||||||
// We only add element if not in View or not projected.
|
// We only add element if not in View or not projected.
|
||||||
|
|
||||||
let nativeSibling: RNode|null = findBeforeNode(node, null);
|
let nativeSibling: RNode|null = findNextRNodeSibling(node, null);
|
||||||
const renderer = currentView.renderer;
|
const renderer = currentView.renderer;
|
||||||
(renderer as ProceduralRenderer3).listen ?
|
(renderer as ProceduralRenderer3).listen ?
|
||||||
(renderer as ProceduralRenderer3)
|
(renderer as ProceduralRenderer3)
|
||||||
|
|
Loading…
Reference in New Issue