indexTreeModel.ts 14.8 KB
Newer Older
J
Joao Moreno 已提交
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

J
Joao Moreno 已提交
6
import { ISpliceable } from 'vs/base/common/sequence';
J
Joao Moreno 已提交
7
import { Iterator, ISequence } from 'vs/base/common/iterator';
J
Joao Moreno 已提交
8
import { Emitter, Event, EventBufferer } from 'vs/base/common/event';
J
Joao Moreno 已提交
9
import { tail2 } from 'vs/base/common/arrays';
J
Joao Moreno 已提交
10
import { ITreeFilterDataResult, TreeVisibility, ITreeFilter, ITreeModel, ITreeNode, ITreeElement } from 'vs/base/browser/ui/tree/tree';
J
Joao Moreno 已提交
11

J
Joao Moreno 已提交
12
interface IMutableTreeNode<T, TFilterData> extends ITreeNode<T, TFilterData> {
13 14
	readonly parent: IMutableTreeNode<T, TFilterData> | undefined;
	readonly children: IMutableTreeNode<T, TFilterData>[];
15
	collapsible: boolean;
J
Joao Moreno 已提交
16
	collapsed: boolean;
J
Joao Moreno 已提交
17
	renderNodeCount: number;
J
Joao Moreno 已提交
18
	visible: boolean;
J
Joao Moreno 已提交
19
	filterData: TFilterData | undefined;
J
Joao Moreno 已提交
20
}
J
Joao Moreno 已提交
21

J
Joao Moreno 已提交
22
function isFilterResult<T>(obj: any): obj is ITreeFilterDataResult<T> {
23 24 25
	return typeof obj === 'object' && 'visibility' in obj && 'data' in obj;
}

J
Joao Moreno 已提交
26
function treeNodeToElement<T>(node: IMutableTreeNode<T, any>): ITreeElement<T> {
J
Joao Moreno 已提交
27
	const { element, collapsed } = node;
J
Joao Moreno 已提交
28
	const children = Iterator.map(Iterator.fromArray(node.children), treeNodeToElement);
J
Joao Moreno 已提交
29 30

	return { element, children, collapsed };
J
Joao Moreno 已提交
31 32
}

33
function getVisibleState(visibility: boolean | TreeVisibility): TreeVisibility {
J
Joao Moreno 已提交
34
	switch (visibility) {
35 36 37
		case true: return TreeVisibility.Visible;
		case false: return TreeVisibility.Hidden;
		default: return visibility;
J
Joao Moreno 已提交
38 39 40
	}
}

J
Joao Moreno 已提交
41
export interface IIndexTreeModelOptions<T, TFilterData> {
J
Joao Moreno 已提交
42
	collapseByDefault?: boolean; // defaults to false
J
Joao Moreno 已提交
43 44 45
	filter?: ITreeFilter<T, TFilterData>;
}

J
Joao Moreno 已提交
46
export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = void> implements ITreeModel<T, TFilterData, number[]> {
47

J
Joao Moreno 已提交
48
	private root: IMutableTreeNode<T, TFilterData>;
J
Joao Moreno 已提交
49
	private eventBufferer = new EventBufferer(); // TODO@joao is this really necessary
J
Joao Moreno 已提交
50

J
Joao Moreno 已提交
51
	private _onDidChangeCollapseState = new Emitter<ITreeNode<T, TFilterData>>();
J
Joao Moreno 已提交
52 53 54 55
	readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>> = this.eventBufferer.wrapEvent(this._onDidChangeCollapseState.event);

	private _onDidChangeRenderNodeCount = new Emitter<ITreeNode<T, TFilterData>>();
	readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>> = this.eventBufferer.wrapEvent(this._onDidChangeRenderNodeCount.event);
56

J
Joao Moreno 已提交
57
	private collapseByDefault: boolean;
J
Joao Moreno 已提交
58
	private filter?: ITreeFilter<T, TFilterData>;
59

J
Joao Moreno 已提交
60
	constructor(private list: ISpliceable<ITreeNode<T, TFilterData>>, rootElement: T, options: IIndexTreeModelOptions<T, TFilterData> = {}) {
J
Joao Moreno 已提交
61
		this.collapseByDefault = typeof options.collapseByDefault === 'undefined' ? false : options.collapseByDefault;
62
		this.filter = options.filter;
J
Joao Moreno 已提交
63 64 65 66 67 68 69 70 71 72 73 74

		this.root = {
			parent: undefined,
			element: rootElement,
			children: [],
			depth: 0,
			collapsible: false,
			collapsed: false,
			renderNodeCount: 0,
			visible: true,
			filterData: undefined
		};
75
	}
J
Joao Moreno 已提交
76

J
Joao Moreno 已提交
77 78 79 80 81 82 83
	splice(
		location: number[],
		deleteCount: number,
		toInsert?: ISequence<ITreeElement<T>>,
		onDidCreateNode?: (node: ITreeNode<T, TFilterData>) => void,
		onDidDeleteNode?: (node: ITreeNode<T, TFilterData>) => void
	): Iterator<ITreeElement<T>> {
J
Joao Moreno 已提交
84
		if (location.length === 0) {
J
Joao Moreno 已提交
85 86 87
			throw new Error('Invalid tree location');
		}

J
Joao Moreno 已提交
88
		const { parentNode, listIndex, revealed } = this.getParentNodeWithListIndex(location);
J
Joao Moreno 已提交
89
		const treeListElementsToInsert: ITreeNode<T, TFilterData>[] = [];
90
		const nodesToInsertIterator = Iterator.map(Iterator.from(toInsert), el => this.createTreeNode(el, parentNode, parentNode.visible ? TreeVisibility.Visible : TreeVisibility.Hidden, revealed, treeListElementsToInsert, onDidCreateNode));
J
Joao Moreno 已提交
91 92

		const nodesToInsert: IMutableTreeNode<T, TFilterData>[] = [];
J
Joao Moreno 已提交
93
		let renderNodeCount = 0;
J
Joao Moreno 已提交
94 95 96

		Iterator.forEach(nodesToInsertIterator, node => {
			nodesToInsert.push(node);
J
Joao Moreno 已提交
97
			renderNodeCount += node.renderNodeCount;
J
Joao Moreno 已提交
98 99
		});

J
Joao Moreno 已提交
100 101
		const lastIndex = location[location.length - 1];
		const deletedNodes = parentNode.children.splice(lastIndex, deleteCount, ...nodesToInsert);
J
Joao Moreno 已提交
102

103
		if (revealed) {
J
Joao Moreno 已提交
104
			const visibleDeleteCount = deletedNodes.reduce((r, node) => r + node.renderNodeCount, 0);
105

J
Joao Moreno 已提交
106
			this._updateAncestorsRenderNodeCount(parentNode, renderNodeCount - visibleDeleteCount);
107
			this.list.splice(listIndex, visibleDeleteCount, treeListElementsToInsert);
J
Joao Moreno 已提交
108
		}
J
Joao Moreno 已提交
109

110
		if (deletedNodes.length > 0 && onDidDeleteNode) {
J
Joao Moreno 已提交
111 112 113 114 115 116 117 118
			const visit = (node: ITreeNode<T, TFilterData>) => {
				onDidDeleteNode(node);
				node.children.forEach(visit);
			};

			deletedNodes.forEach(visit);
		}

J
Joao Moreno 已提交
119
		return Iterator.map(Iterator.fromArray(deletedNodes), treeNodeToElement);
J
Joao Moreno 已提交
120 121
	}

J
Joao Moreno 已提交
122
	getListIndex(location: number[]): number {
J
Joao Moreno 已提交
123
		return this.getTreeNodeWithListIndex(location).listIndex;
J
Joao Moreno 已提交
124 125
	}

J
Joao Moreno 已提交
126
	setCollapsed(location: number[], collapsed?: boolean, recursive = false): boolean {
J
Joao Moreno 已提交
127
		const { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location);
J
Joao Moreno 已提交
128 129 130 131 132 133

		if (typeof collapsed === 'undefined') {
			collapsed = !node.collapsed;
		}

		return this._setCollapsed(node, listIndex, revealed, collapsed, recursive);
J
Joao Moreno 已提交
134 135
	}

J
Joao Moreno 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
	private _setCollapsed(node: IMutableTreeNode<T, TFilterData>, listIndex: number, revealed: boolean, collapsed: boolean, recursive: boolean): boolean {
		const result = this._setNodeCollapsed(node, collapsed, recursive);

		if (!revealed || !node.visible) {
			return result;
		}

		const previousRenderNodeCount = node.renderNodeCount;
		const toInsert = this.updateNodeAfterCollapseChange(node);

		const deleteCount = previousRenderNodeCount - (listIndex === -1 ? 0 : 1);

		this.list.splice(listIndex + 1, deleteCount, toInsert.slice(1));
		this._onDidChangeCollapseState.fire(node);

		return result;
J
Joao Moreno 已提交
152
	}
J
Joao Moreno 已提交
153

J
Joao Moreno 已提交
154 155
	private _setNodeCollapsed(node: IMutableTreeNode<T, TFilterData>, collapsed: boolean, recursive: boolean): boolean {
		let result = node.collapsible && node.collapsed !== collapsed;
J
Joao Moreno 已提交
156

J
Joao Moreno 已提交
157 158 159
		if (node.collapsible) {
			node.collapsed = collapsed;
		}
J
Joao Moreno 已提交
160

J
Joao Moreno 已提交
161 162 163
		if (recursive) {
			for (const child of node.children) {
				result = this._setNodeCollapsed(child, collapsed, true) || result;
J
Joao Moreno 已提交
164
			}
J
Joao Moreno 已提交
165 166 167 168 169 170 171 172 173 174 175
		}

		return result;
	}

	expandAll(): void {
		this.setCollapsed([], false, true);
	}

	collapseAll(): void {
		this.setCollapsed([], true, true);
J
Joao Moreno 已提交
176
	}
177

178 179 180 181
	isCollapsible(location: number[]): boolean {
		return this.getTreeNode(location).collapsible;
	}

182
	isCollapsed(location: number[]): boolean {
J
Joao Moreno 已提交
183
		return this.getTreeNode(location).collapsed;
184 185
	}

J
Joao Moreno 已提交
186
	refilter(): void {
J
Joao Moreno 已提交
187
		const previousRenderNodeCount = this.root.renderNodeCount;
J
Joao Moreno 已提交
188
		const toInsert = this.updateNodeAfterFilterChange(this.root);
J
Joao Moreno 已提交
189
		this.list.splice(0, previousRenderNodeCount, toInsert);
J
Joao Moreno 已提交
190 191
	}

J
Joao Moreno 已提交
192 193 194
	private createTreeNode(
		treeElement: ITreeElement<T>,
		parent: IMutableTreeNode<T, TFilterData>,
195
		parentVisibility: TreeVisibility,
J
Joao Moreno 已提交
196 197 198 199
		revealed: boolean,
		treeListElements: ITreeNode<T, TFilterData>[],
		onDidCreateNode?: (node: ITreeNode<T, TFilterData>) => void
	): IMutableTreeNode<T, TFilterData> {
J
Joao Moreno 已提交
200 201 202 203 204
		const node: IMutableTreeNode<T, TFilterData> = {
			parent,
			element: treeElement.element,
			children: [],
			depth: parent.depth + 1,
J
Joao Moreno 已提交
205 206
			collapsible: typeof treeElement.collapsible === 'boolean' ? treeElement.collapsible : (typeof treeElement.collapsed !== 'undefined'),
			collapsed: typeof treeElement.collapsed === 'undefined' ? this.collapseByDefault : treeElement.collapsed,
J
Joao Moreno 已提交
207
			renderNodeCount: 1,
J
Joao Moreno 已提交
208 209 210
			visible: true,
			filterData: undefined
		};
J
Joao Moreno 已提交
211

212
		const visibility = this._filterNode(node, parentVisibility);
J
Joao Moreno 已提交
213

J
Joao Moreno 已提交
214
		if (revealed) {
215 216 217
			treeListElements.push(node);
		}

J
Joao Moreno 已提交
218
		const childElements = Iterator.from(treeElement.children);
219 220
		const childRevealed = revealed && visibility !== TreeVisibility.Hidden && !node.collapsed;
		const childNodes = Iterator.map(childElements, el => this.createTreeNode(el, node, visibility, childRevealed, treeListElements, onDidCreateNode));
J
Joao Moreno 已提交
221

222
		let hasVisibleDescendants = false;
J
Joao Moreno 已提交
223
		let renderNodeCount = 1;
224 225 226 227

		Iterator.forEach(childNodes, child => {
			node.children.push(child);
			hasVisibleDescendants = hasVisibleDescendants || child.visible;
J
Joao Moreno 已提交
228
			renderNodeCount += child.renderNodeCount;
229 230
		});

231
		node.collapsible = node.collapsible || node.children.length > 0;
232
		node.visible = visibility === TreeVisibility.Recurse ? hasVisibleDescendants : (visibility === TreeVisibility.Visible);
J
Joao Moreno 已提交
233

J
Joao Moreno 已提交
234
		if (!node.visible) {
J
Joao Moreno 已提交
235
			node.renderNodeCount = 0;
J
Joao Moreno 已提交
236 237 238 239

			if (revealed) {
				treeListElements.pop();
			}
J
Joao Moreno 已提交
240
		} else if (!node.collapsed) {
J
Joao Moreno 已提交
241
			node.renderNodeCount = renderNodeCount;
242 243
		}

J
Joao Moreno 已提交
244 245 246 247
		if (onDidCreateNode) {
			onDidCreateNode(node);
		}

248 249 250
		return node;
	}

J
Joao Moreno 已提交
251
	private updateNodeAfterCollapseChange(node: IMutableTreeNode<T, TFilterData>): ITreeNode<T, TFilterData>[] {
J
Joao Moreno 已提交
252
		const previousRenderNodeCount = node.renderNodeCount;
253 254
		const result: ITreeNode<T, TFilterData>[] = [];

J
Joao Moreno 已提交
255
		this._updateNodeAfterCollapseChange(node, result);
J
Joao Moreno 已提交
256
		this._updateAncestorsRenderNodeCount(node.parent, result.length - previousRenderNodeCount);
J
Joao Moreno 已提交
257 258 259 260 261 262 263 264 265 266

		return result;
	}

	private _updateNodeAfterCollapseChange(node: IMutableTreeNode<T, TFilterData>, result: ITreeNode<T, TFilterData>[]): number {
		if (node.visible === false) {
			return 0;
		}

		result.push(node);
J
Joao Moreno 已提交
267
		node.renderNodeCount = 1;
J
Joao Moreno 已提交
268 269 270

		if (!node.collapsed) {
			for (const child of node.children) {
J
Joao Moreno 已提交
271
				node.renderNodeCount += this._updateNodeAfterCollapseChange(child, result);
272
			}
J
Joao Moreno 已提交
273 274
		}

J
Joao Moreno 已提交
275
		this._onDidChangeRenderNodeCount.fire(node);
J
Joao Moreno 已提交
276
		return node.renderNodeCount;
J
Joao Moreno 已提交
277 278 279
	}

	private updateNodeAfterFilterChange(node: IMutableTreeNode<T, TFilterData>): ITreeNode<T, TFilterData>[] {
J
Joao Moreno 已提交
280
		const previousRenderNodeCount = node.renderNodeCount;
J
Joao Moreno 已提交
281 282
		const result: ITreeNode<T, TFilterData>[] = [];

283
		this._updateNodeAfterFilterChange(node, node.visible ? TreeVisibility.Visible : TreeVisibility.Hidden, result);
J
Joao Moreno 已提交
284
		this._updateAncestorsRenderNodeCount(node.parent, result.length - previousRenderNodeCount);
J
Joao Moreno 已提交
285 286 287 288

		return result;
	}

289 290
	private _updateNodeAfterFilterChange(node: IMutableTreeNode<T, TFilterData>, parentVisibility: TreeVisibility, result: ITreeNode<T, TFilterData>[], revealed = true): boolean {
		let visibility: TreeVisibility;
J
Joao Moreno 已提交
291

J
Joao Moreno 已提交
292
		if (node !== this.root) {
293
			visibility = this._filterNode(node, parentVisibility);
294

295
			if (visibility === TreeVisibility.Hidden) {
J
Joao Moreno 已提交
296
				node.visible = false;
J
Joao Moreno 已提交
297
				return false;
298 299
			}

J
Joao Moreno 已提交
300 301 302
			if (revealed) {
				result.push(node);
			}
J
Joao Moreno 已提交
303
		}
J
Joao Moreno 已提交
304

J
Joao Moreno 已提交
305
		const resultStartLength = result.length;
J
Joao Moreno 已提交
306
		node.renderNodeCount = node === this.root ? 0 : 1;
307

J
Joao Moreno 已提交
308
		let hasVisibleDescendants = false;
309
		if (!node.collapsed || visibility! !== TreeVisibility.Hidden) {
J
Joao Moreno 已提交
310
			for (const child of node.children) {
311
				hasVisibleDescendants = this._updateNodeAfterFilterChange(child, visibility!, result, revealed && !node.collapsed) || hasVisibleDescendants;
J
Joao Moreno 已提交
312
			}
J
Joao Moreno 已提交
313
		}
J
Joao Moreno 已提交
314

J
Joao Moreno 已提交
315
		if (node !== this.root) {
316
			node.visible = visibility! === TreeVisibility.Recurse ? hasVisibleDescendants : (visibility! === TreeVisibility.Visible);
J
Joao Moreno 已提交
317
		}
J
Joao Moreno 已提交
318

J
Joao Moreno 已提交
319
		if (!node.visible) {
J
Joao Moreno 已提交
320
			node.renderNodeCount = 0;
321

J
Joao Moreno 已提交
322 323 324 325
			if (revealed) {
				result.pop();
			}
		} else if (!node.collapsed) {
J
Joao Moreno 已提交
326
			node.renderNodeCount += result.length - resultStartLength;
J
Joao Moreno 已提交
327
		}
328

J
Joao Moreno 已提交
329
		this._onDidChangeRenderNodeCount.fire(node);
J
Joao Moreno 已提交
330 331
		return node.visible;
	}
J
Joao Moreno 已提交
332

333
	private _updateAncestorsRenderNodeCount(node: IMutableTreeNode<T, TFilterData> | undefined, diff: number): void {
J
Joao Moreno 已提交
334 335
		if (diff === 0) {
			return;
J
Joao Moreno 已提交
336 337
		}

338
		while (node) {
J
Joao Moreno 已提交
339
			node.renderNodeCount += diff;
J
Joao Moreno 已提交
340
			this._onDidChangeRenderNodeCount.fire(node);
341
			node = node.parent;
J
Joao Moreno 已提交
342 343 344
		}
	}

345 346
	private _filterNode(node: IMutableTreeNode<T, TFilterData>, parentVisibility: TreeVisibility): TreeVisibility {
		const result = this.filter ? this.filter.filter(node.element, parentVisibility) : TreeVisibility.Visible;
347

J
Joao Moreno 已提交
348
		if (typeof result === 'boolean') {
J
Joao Moreno 已提交
349
			node.filterData = undefined;
S
Sandeep Somavarapu 已提交
350
			return result ? TreeVisibility.Visible : TreeVisibility.Hidden;
J
Joao Moreno 已提交
351 352
		} else if (isFilterResult<TFilterData>(result)) {
			node.filterData = result.data;
J
Joao Moreno 已提交
353
			return getVisibleState(result.visibility);
354 355
		} else {
			node.filterData = undefined;
J
Joao Moreno 已提交
356
			return getVisibleState(result);
357
		}
J
Joao Moreno 已提交
358 359
	}

J
Joao Moreno 已提交
360
	// cheap
J
Joao Moreno 已提交
361
	private getTreeNode(location: number[], node: IMutableTreeNode<T, TFilterData> = this.root): IMutableTreeNode<T, TFilterData> {
362
		if (!location || location.length === 0) {
J
Joao Moreno 已提交
363 364 365 366 367 368 369 370 371
			return node;
		}

		const [index, ...rest] = location;

		if (index < 0 || index > node.children.length) {
			throw new Error('Invalid tree location');
		}

J
Joao Moreno 已提交
372
		return this.getTreeNode(rest, node.children[index]);
J
Joao Moreno 已提交
373 374
	}

J
Joao Moreno 已提交
375 376
	// expensive
	private getTreeNodeWithListIndex(location: number[]): { node: IMutableTreeNode<T, TFilterData>, listIndex: number, revealed: boolean } {
J
Joao Moreno 已提交
377 378 379 380
		if (location.length === 0) {
			return { node: this.root, listIndex: -1, revealed: true };
		}

J
Joao Moreno 已提交
381
		const { parentNode, listIndex, revealed } = this.getParentNodeWithListIndex(location);
J
Joao Moreno 已提交
382
		const index = location[location.length - 1];
J
Joao Moreno 已提交
383 384 385 386 387 388 389

		if (index < 0 || index > parentNode.children.length) {
			throw new Error('Invalid tree location');
		}

		const node = parentNode.children[index];

390
		return { node, listIndex, revealed };
J
Joao Moreno 已提交
391 392
	}

J
Joao Moreno 已提交
393
	private getParentNodeWithListIndex(location: number[], node: IMutableTreeNode<T, TFilterData> = this.root, listIndex: number = 0, revealed = true): { parentNode: IMutableTreeNode<T, TFilterData>; listIndex: number; revealed: boolean; } {
J
Joao Moreno 已提交
394 395 396 397 398
		const [index, ...rest] = location;

		if (index < 0 || index > node.children.length) {
			throw new Error('Invalid tree location');
		}
J
Joao Moreno 已提交
399

400
		// TODO@joao perf!
J
Joao Moreno 已提交
401
		for (let i = 0; i < index; i++) {
J
Joao Moreno 已提交
402
			listIndex += node.children[i].renderNodeCount;
403
		}
J
Joao Moreno 已提交
404

405
		revealed = revealed && !node.collapsed;
J
Joao Moreno 已提交
406 407

		if (rest.length === 0) {
408
			return { parentNode: node, listIndex, revealed };
J
Joao Moreno 已提交
409 410
		}

J
Joao Moreno 已提交
411
		return this.getParentNodeWithListIndex(rest, node.children[index], listIndex + 1, revealed);
J
Joao Moreno 已提交
412
	}
J
Joao Moreno 已提交
413

J
Joao Moreno 已提交
414 415 416 417
	getNode(location: number[] = []): ITreeNode<T, TFilterData> {
		return this.getTreeNode(location);
	}

J
Joao Moreno 已提交
418 419
	// TODO@joao perf!
	getNodeLocation(node: ITreeNode<T, TFilterData>): number[] {
M
Matt Bierner 已提交
420
		const location: number[] = [];
J
Joao Moreno 已提交
421 422 423 424 425 426 427 428 429

		while (node.parent) {
			location.push(node.parent.children.indexOf(node));
			node = node.parent;
		}

		return location.reverse();
	}

J
Joao Moreno 已提交
430
	getParentNodeLocation(location: number[]): number[] {
J
Joao Moreno 已提交
431
		if (location.length <= 1) {
J
Joao Moreno 已提交
432
			return [];
J
Joao Moreno 已提交
433 434 435 436
		}

		return tail2(location)[0];
	}
J
Joao Moreno 已提交
437

J
Joao Moreno 已提交
438
	getParentElement(location: number[]): T {
J
Joao Moreno 已提交
439
		const parentLocation = this.getParentNodeLocation(location);
J
Joao Moreno 已提交
440
		const node = this.getTreeNode(parentLocation);
J
Joao Moreno 已提交
441
		return node.element;
J
Joao Moreno 已提交
442 443
	}

J
Joao Moreno 已提交
444
	getFirstElementChild(location: number[]): T | undefined {
J
Joao Moreno 已提交
445
		const node = this.getTreeNode(location);
J
Joao Moreno 已提交
446 447

		if (node.children.length === 0) {
J
Joao Moreno 已提交
448
			return undefined;
J
Joao Moreno 已提交
449 450 451 452 453
		}

		return node.children[0].element;
	}

J
Joao Moreno 已提交
454
	getLastElementAncestor(location: number[] = []): T | undefined {
J
Joao Moreno 已提交
455
		const node = this.getTreeNode(location);
J
Joao Moreno 已提交
456 457

		if (node.children.length === 0) {
J
Joao Moreno 已提交
458
			return undefined;
J
Joao Moreno 已提交
459 460 461 462 463
		}

		return this._getLastElementAncestor(node);
	}

J
Joao Moreno 已提交
464
	private _getLastElementAncestor(node: ITreeNode<T, TFilterData>): T {
J
Joao Moreno 已提交
465 466 467 468 469 470
		if (node.children.length === 0) {
			return node.element;
		}

		return this._getLastElementAncestor(node.children[node.children.length - 1]);
	}
J
Joao Moreno 已提交
471
}