Skip to content

Commit 50a6100

Browse files
committed
feat(cdk/tree): maintain a cache of parents and node groups
1 parent bdbd829 commit 50a6100

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

src/cdk/tree/tree.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,20 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
9696
/** Level of nodes */
9797
private _levels: Map<T, number> = new Map<T, number>();
9898

99+
/** The immediate parents for a node. This is `null` if there is no parent. */
100+
private _parents: Map<T, T | null> = new Map<T, T | null>();
101+
102+
/**
103+
* The internal node groupings for each node; we use this, primarily for flattened trees, to
104+
* determine where a particular node is within each group.
105+
*
106+
* The structure of this is that:
107+
* - the outer index is the level
108+
* - the inner index is the parent node for this particular group. If there is no parent node, we
109+
* use `null`.
110+
*/
111+
private _groups: Map<number, Map<T | null, T[]>> = new Map<number, Map<T | null, T[]>>();
112+
99113
/**
100114
* Provides a stream containing the latest data array to render. Influenced by the tree's
101115
* stream of view window (what dataNodes are currently on screen).
@@ -339,7 +353,10 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
339353
this.insertNode(data[currentIndex!], currentIndex!, viewContainer, parentData);
340354
} else if (currentIndex == null) {
341355
viewContainer.remove(adjustedPreviousIndex!);
356+
const group = this._getNodeGroup(item.item);
342357
this._levels.delete(item.item);
358+
this._parents.delete(item.item);
359+
group.splice(group.indexOf(item.item), 1);
343360
} else {
344361
const view = viewContainer.get(adjustedPreviousIndex!);
345362
viewContainer.move(view!, currentIndex);
@@ -393,6 +410,19 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
393410
context.level = 0;
394411
}
395412
this._levels.set(nodeData, context.level);
413+
const parent = parentData ?? this._findParentForNode(nodeData, index);
414+
this._parents.set(nodeData, parent);
415+
416+
// Determine where to insert this new node into the group, then insert it.
417+
// We do this by looking at the previous node in our flattened node list. If it's in the same
418+
// group, we place the current node after. Otherwise, we place it at the start of the group.
419+
const currentGroup = this._groups.get(context.level) ?? new Map<T | null, T[]>();
420+
const group = currentGroup.get(parent) ?? [];
421+
const previousNode = this._dataNodes?.[index - 1];
422+
const groupInsertionIndex = (previousNode && group.indexOf(previousNode) + 1) ?? 0;
423+
group.splice(groupInsertionIndex, 0, nodeData);
424+
currentGroup.set(parent, group);
425+
this._groups.set(context.level, currentGroup);
396426

397427
// Use default tree nodeOutlet, or nested node's nodeOutlet
398428
const container = viewContainer ? viewContainer : this._nodeOutlet.viewContainer;
@@ -706,6 +736,32 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
706736
);
707737
}
708738
}
739+
740+
private _getNodeGroup(node: T) {
741+
const level = this._levels.get(node);
742+
const parent = this._parents.get(node);
743+
const group = this._groups.get(level ?? 0)?.get(parent ?? null);
744+
return group ?? [node];
745+
}
746+
747+
private _findParentForNode(node: T, index: number) {
748+
// In all cases, we have a mapping from node to level; all we need to do here is backtrack in
749+
// our flattened list of nodes to determine the first node that's of a level lower than the
750+
// provided node.
751+
if (!this._dataNodes) {
752+
return null;
753+
}
754+
const currentLevel = this._levels.get(node) ?? 0;
755+
for (let parentIndex = index; parentIndex >= 0; parentIndex--) {
756+
const parentNode = this._dataNodes[parentIndex];
757+
const parentLevel = this._levels.get(parentNode) ?? 0;
758+
759+
if (parentLevel < currentLevel) {
760+
return parentNode;
761+
}
762+
}
763+
return null;
764+
}
709765
}
710766

711767
/**

0 commit comments

Comments
 (0)