Change:
introduced a  API to the tree via I'm pretty sure that method's implementation can be achieved outside the tree itself. There are , and methods on it. If so, please remove the API method and implement on the search usage side.
This was to the tree with the idea in mind that it would be useful elsewhere like the file explorer. And in fact I'd really like to have the same behavior on the file explorer. So moving it into search code is not the right thing to do but it could go into some TreeHelper class outside of the tree itself.
No need to overload with classes. A simple util function would do.
I don't think this is actually achievable outside the tree itself with the current tree API. It needs to calculate the tree depth to collapse to, and the navigator from just returns elements of the tree without the context of where they are in the tree. IMO, it makes sense for this method to stay on the tree since it's coupled with the tree's data
Good point. But this is really only used for search. I don't really buy into the generic usefulness of this as an API call, which needs to be maintained for the entire tree's lifecycle. As far as I am aware, search trees can only go 2/3 levels deep, depending on whether there are multiple folders in the workspace or not. That knowledge is kept in the search's tree user; the same entity knows exactly what it should collapse or otherwise. Can't it just call the right calls?

Discussion:
collapseAll(elements?: any[], recursive?: boolean): WinJS.Promise; /** <del> * Collapses several elements. * Collapses all elements at the greatest tree depth that has expanded elements. * The returned promise returns a boolean for whether the elements were collapsed or not. */ collapseDeepestExpandedLevel(): WinJS.Promise; /** </del> * Toggles an element's expansion state. */ toggleExpansion(element: any, recursive?: boolean): WinJS.Promise;

return this.model.collapseAll(elements, recursive); } <del> public collapseDeepestExpandedLevel(): WinJS.Promise { return this.model.collapseDeepestExpandedLevel(); } </del> public toggleExpansion(element: any, recursive: boolean = false): WinJS.Promise { return this.model.toggleExpansion(element, recursive); }

return result; } <del> public getChildren(): Item[] { var child = this.firstChild; var results = []; while (child) { results.push(child); child = child.next; } return results; } </del> private isAncestorOf(item: Item): boolean { while (item) { if (item.id === this.id) {

return WinJS.Promise.join(promises); } <del> public collapseDeepestExpandedLevel(): WinJS.Promise { var levelToCollapse = this.findDeepestExpandedLevel(this.input, 0); var items = [this.input]; for (var i = 0; i < levelToCollapse; i++) { items = arrays.flatten(items.map(node => node.getChildren())); } var promises = items.map(child => this.collapse(child, false)); return WinJS.Promise.join(promises); } private findDeepestExpandedLevel(item: Item, currentLevel: number): number { var expandedChildren = item.getChildren().filter(child => child.isExpanded()); if (!expandedChildren.length) { return currentLevel; } return Math.max(...expandedChildren.map(child => this.findDeepestExpandedLevel(child, currentLevel + 1))); } </del> public toggleExpansion(element: any, recursive: boolean = false): WinJS.Promise { return this.isExpanded(element) ? this.collapse(element, recursive) : this.expand(element); }

}); }); <del> test('collapseDeepestExpandedLevel', () => { return model.setInput(SAMPLE.DEEP2).then(() => { return model.expand(SAMPLE.DEEP2.children[0]).then(() => { return model.expand(SAMPLE.DEEP2.children[0].children[0]).then(() => { assert(model.isExpanded(SAMPLE.DEEP2.children[0])); assert(model.isExpanded(SAMPLE.DEEP2.children[0].children[0])); return model.collapseDeepestExpandedLevel().then(() => { assert(model.isExpanded(SAMPLE.DEEP2.children[0])); assert(!model.isExpanded(SAMPLE.DEEP2.children[0].children[0])); }); }); }); }); }); </del> test('auto expand single child folders', () => { return model.setInput(SAMPLE.DEEP).then(() => { return model.expand(SAMPLE.DEEP.children[0]).then(() => {

return TPromise.as(null); // Global action disabled if user is in edit mode from another action } <del> viewer.collapseDeepestExpandedLevel(); </del> <ins> /** * The hierarchy is FolderMatch, FileMatch, Match. If the top level is FileMatches, then there is only * one level to collapse so collapse everything. If FolderMatch, check if there are visible grandchildren, * i.e. if Matches are returned by the navigator, and if so, collapse to them, otherwise collapse all levels. */ const navigator = viewer.getNavigator(); let node = navigator.first(); let collapseFileMatchLevel = false; if (node instanceof FolderMatch) { while (node = navigator.next()) { if (node instanceof Match) { collapseFileMatchLevel = true; break; } } } if (collapseFileMatchLevel) { node = navigator.first(); do { if (node instanceof FileMatch) { viewer.collapse(node); } } while (node = navigator.next()); } else { viewer.collapseAll(); } </ins> viewer.clearSelection(); viewer.clearFocus(); viewer.domFocus();