diff --git a/chrome/content/zotero/collectionTree.jsx b/chrome/content/zotero/collectionTree.jsx index 90e2f1cad6..f0f10e0ff1 100644 --- a/chrome/content/zotero/collectionTree.jsx +++ b/chrome/content/zotero/collectionTree.jsx @@ -2685,34 +2685,39 @@ var CollectionTree = class CollectionTree extends LibraryTree { } } } - // If the filter has been cleared and the selection has not changed, restore the initial scroll position - if (shouldRestoreScrollPosition) { - // For the initial scroll position to make sense, collapse rows that were initially collapsed + // Filter has been cleared: restore collapsed state of collections and scroll position + if (willBeEmpty && !isEmpty) { + let selectedCollectionID = this.getSelectedCollection(true); for (let rowID of this._filterInitialCollapsedRows) { let index = this.getRowIndexByID(rowID); - if (index && this._rows[index].isOpen) { + let row = this._rows[index]; + if (!row || !row.isCollection()) continue; + // Do not collapse ancestory of selected collection + let descendents = new Set(Zotero.Collections.getByParent(row.ref.id, true, false).map(col => col.id)); + if (row.isOpen && !descendents.has(selectedCollectionID)) { this.toggleOpenState(index); } } this._filterInitialCollapsedRows = []; - collectionTable.scrollTop = this._filterInitialScrollPosition; - this._filterInitialScrollPosition = null; + // If collection tree was focused, scroll the selected row to the middle + if (this._treeWasFocused) { + let selectedRow = collectionTable.querySelector(".row.selected"); + let rowRect = selectedRow.getBoundingClientRect(); + let tableRect = collectionTable.getBoundingClientRect(); + let rowMiddle = rowRect.top + rowRect.height / 2; + let tableMiddle = tableRect.top + tableRect.height / 2; + collectionTable.scrollTop = collectionTable.scrollTop + rowMiddle - tableMiddle; + } + // Otherwise, restore the initial scroll position + else { + collectionTable.scrollTop = this._filterInitialScrollPosition; + this._filterInitialScrollPosition = null; + } } // During filtering, scroll to the very top else if (!willBeEmpty) { collectionTable.scrollTop = 0; } - // If the filtering is cleared and the selection has changed, scroll to have the - // newly selected row in the middle - else if (willBeEmpty && !isEmpty) { - let selectedRow = collectionTable.querySelector(".row.selected"); - let rowRect = selectedRow.getBoundingClientRect(); - let tableRect = collectionTable.getBoundingClientRect(); - let rowMiddle = rowRect.top + rowRect.height / 2; - let tableMiddle = tableRect.top + tableRect.height / 2; - let scrollPosition = collectionTable.scrollTop + rowMiddle - tableMiddle; - collectionTable.scrollTop = scrollPosition; - } // Focus the collection tree if (focusTree) { collectionTable.parentNode.focus(); diff --git a/test/tests/collectionTreeTest.js b/test/tests/collectionTreeTest.js index 6a31e182e9..4f3cd34d21 100644 --- a/test/tests/collectionTreeTest.js +++ b/test/tests/collectionTreeTest.js @@ -1616,6 +1616,8 @@ describe("Zotero.CollectionTree", function () { }); it('should collapse collections collapsed before filtering', async function () { + // Select collection 1 + await cv.selectByID(`C${collection1.id}`); // Collapse top level collections 1 and 6 for (let c of [collection1, collection6]) { let index = cv.getRowIndexByID("C" + c.id); @@ -1644,6 +1646,22 @@ describe("Zotero.CollectionTree", function () { assert.isFalse(colOneRow.isOpen); let colSixRow = cv.getRow(cv.getRowIndexByID("C" + collection6.id)); assert.isFalse(colSixRow.isOpen); + + // Filter by 'collection' - this will expand all collections + await cv.setFilter('collection'); + assert.isTrue(cv.getRow(cv.getRowIndexByID("C" + collection1.id)).isOpen); + assert.isTrue(cv.getRow(cv.getRowIndexByID("C" + collection2.id)).isOpen); + assert.isTrue(cv.getRow(cv.getRowIndexByID("C" + collection6.id)).isOpen); + + // Select collection 8 and clear filter + await cv.selectByID(`C${collection8.id}`); + await cv.setFilter(""); + + // Collection 1 should be collapsed because it was collapsed before filtering + assert.isFalse(cv.getRow(cv.getRowIndexByID("C" + collection1.id)).isOpen); + // Collection 6 should be expanded because it's child (collection 8) is selected + assert.isTrue(cv.getRow(cv.getRowIndexByID("C" + collection6.id)).isOpen); + }); for (let type of ['collection', 'search']) {