Skip to content

Commit 1303386

Browse files
committed
feat(cdk/tree): maintain a cache of parents and node groups
1 parent 8cc604f commit 1303386

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).
@@ -328,7 +342,10 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
328342
this.insertNode(data[currentIndex!], currentIndex!, viewContainer, parentData);
329343
} else if (currentIndex == null) {
330344
viewContainer.remove(adjustedPreviousIndex!);
345+
const group = this._getNodeGroup(item.item);
331346
this._levels.delete(item.item);
347+
this._parents.delete(item.item);
348+
group.splice(group.indexOf(item.item), 1);
332349
} else {
333350
const view = viewContainer.get(adjustedPreviousIndex!);
334351
viewContainer.move(view!, currentIndex);
@@ -382,6 +399,19 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
382399
context.level = 0;
383400
}
384401
this._levels.set(nodeData, context.level);
402+
const parent = parentData ?? this._findParentForNode(nodeData, index);
403+
this._parents.set(nodeData, parent);
404+
405+
// Determine where to insert this new node into the group, then insert it.
406+
// We do this by looking at the previous node in our flattened node list. If it's in the same
407+
// group, we place the current node after. Otherwise, we place it at the start of the group.
408+
const currentGroup = this._groups.get(context.level) ?? new Map<T | null, T[]>();
409+
const group = currentGroup.get(parent) ?? [];
410+
const previousNode = this._dataNodes?.[index - 1];
411+
const groupInsertionIndex = (previousNode && group.indexOf(previousNode) + 1) ?? 0;
412+
group.splice(groupInsertionIndex, 0, nodeData);
413+
currentGroup.set(parent, group);
414+
this._groups.set(context.level, currentGroup);
385415

386416
// Use default tree nodeOutlet, or nested node's nodeOutlet
387417
const container = viewContainer ? viewContainer : this._nodeOutlet.viewContainer;
@@ -712,6 +742,32 @@ export class CdkTree<T, K = T> implements AfterContentChecked, CollectionViewer,
712742
return observableOf(nodes);
713743
}
714744
}
745+
746+
private _getNodeGroup(node: T) {
747+
const level = this._levels.get(node);
748+
const parent = this._parents.get(node);
749+
const group = this._groups.get(level ?? 0)?.get(parent ?? null);
750+
return group ?? [node];
751+
}
752+
753+
private _findParentForNode(node: T, index: number) {
754+
// In all cases, we have a mapping from node to level; all we need to do here is backtrack in
755+
// our flattened list of nodes to determine the first node that's of a level lower than the
756+
// provided node.
757+
if (!this._dataNodes) {
758+
return null;
759+
}
760+
const currentLevel = this._levels.get(node) ?? 0;
761+
for (let parentIndex = index; parentIndex >= 0; parentIndex--) {
762+
const parentNode = this._dataNodes[parentIndex];
763+
const parentLevel = this._levels.get(parentNode) ?? 0;
764+
765+
if (parentLevel < currentLevel) {
766+
return parentNode;
767+
}
768+
}
769+
return null;
770+
}
715771
}
716772

717773
/**

0 commit comments

Comments
 (0)