diff --git a/chrome/content/zotero/collectionTree.jsx b/chrome/content/zotero/collectionTree.jsx index b46b65cf98..0b6e11ff46 100644 --- a/chrome/content/zotero/collectionTree.jsx +++ b/chrome/content/zotero/collectionTree.jsx @@ -640,11 +640,8 @@ var CollectionTree = class CollectionTree extends LibraryTree { this.tree.invalidate(); return; } - if (action == 'refresh') { - // If trash is refreshed, we probably need to update the icon from full to empty - if (type == 'trash') { - this.tree.invalidate(); - } + if (action == 'refresh' && type != 'trash') { + // Trash handled below return; } if (type == 'feed' && (action == 'unreadCountUpdated' || action == 'statusChanged')) { @@ -826,6 +823,11 @@ var CollectionTree = class CollectionTree extends LibraryTree { } } } + else if (action == 'refresh' && type == 'trash') { + // We need to update the trash's status (full or empty), and if empty, + // the row might be removed + await this.reload(); + } this.forceUpdate(); var promise = this.waitForSelect(); @@ -2307,7 +2309,7 @@ var CollectionTree = class CollectionTree extends LibraryTree { } if (showTrash) { - let deletedItems = await Zotero.Items.getDeleted(libraryID); + let deletedItems = await Zotero.Items.getDeleted(libraryID, true); if (deletedItems.length || Zotero.Prefs.get("showTrashWhenEmpty")) { var ref = { libraryID: libraryID diff --git a/chrome/content/zotero/itemTree.jsx b/chrome/content/zotero/itemTree.jsx index d8229d2389..604691fcc9 100644 --- a/chrome/content/zotero/itemTree.jsx +++ b/chrome/content/zotero/itemTree.jsx @@ -446,11 +446,20 @@ var ItemTree = class ItemTree extends LibraryTree { let row = this.getRowIndexByID(id); if (row === false) continue; let item = Zotero.Items.get(id); - if (!item.deleted && !item.numChildren()) { + // Remove parent row if it isn't deleted and doesn't have any deleted children + // (shown by the numChildren including deleted being the same as numChildren not including deleted) + if (!item.deleted && (!item.isRegularItem() || item.numChildren(true) == item.numChildren(false))) { rows.push(row); + // And all its children in the tree + for (let child = row + 1; child < this.rowCount && this.getLevel(child) > this.getLevel(row); child++) { + rows.push(child); + } } } - this._removeRows(rows); + if (rows.length) { + this._removeRows(rows); + this.tree.invalidate(); + } } return; diff --git a/chrome/content/zotero/xpcom/data/items.js b/chrome/content/zotero/xpcom/data/items.js index 6525722096..73daf8e8bf 100644 --- a/chrome/content/zotero/xpcom/data/items.js +++ b/chrome/content/zotero/xpcom/data/items.js @@ -1502,6 +1502,7 @@ Zotero.Items = function() { ); } Zotero.debug("Emptied " + deleted.length + " item(s) from trash in " + (new Date() - t) + " ms"); + Zotero.Notifier.trigger('refresh', 'trash', libraryID); } return deleted.length; diff --git a/test/tests/itemTest.js b/test/tests/itemTest.js index 09cb88f02b..f31095142f 100644 --- a/test/tests/itemTest.js +++ b/test/tests/itemTest.js @@ -1465,6 +1465,10 @@ describe("Zotero.Item", function () { await annotation2.saveTx(); }); + after(async function () { + await annotation2.eraseTx(); + }); + it("should return annotations not in trash", async function () { var items = attachment.getAnnotations(); assert.sameMembers(items, [annotation1]); diff --git a/test/tests/itemTreeTest.js b/test/tests/itemTreeTest.js index 99852a0274..de27f09b6d 100644 --- a/test/tests/itemTreeTest.js +++ b/test/tests/itemTreeTest.js @@ -684,7 +684,7 @@ describe("Zotero.ItemTree", function() { }); describe("Trash", function () { - it.skip("should remove untrashed parent item when last trashed child is deleted", function* () { + it("should remove untrashed parent item when last trashed child is deleted", function* () { var userLibraryID = Zotero.Libraries.userLibraryID; var item = yield createDataObject('item'); var note = yield createDataObject(