From ca4ced1e9f84edb4263b53722527c640a6bdd775 Mon Sep 17 00:00:00 2001 From: Dan Stillman <dstillman@zotero.org> Date: Thu, 25 Aug 2022 05:15:25 -0400 Subject: [PATCH] Add Zotero.Item::topLevelItem and Zotero.Items.getTopLevel(items) --- chrome/content/zotero/xpcom/data/item.js | 11 ++++++++++- chrome/content/zotero/xpcom/data/items.js | 11 +++++++++++ test/tests/itemTest.js | 20 ++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index 8327625210..5eb9467335 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -153,7 +153,16 @@ Zotero.defineProperty(Zotero.Item.prototype, 'parentItemKey', { Zotero.defineProperty(Zotero.Item.prototype, 'parentItem', { get: function() { return Zotero.Items.get(this.parentID) || undefined; }, }); - +Zotero.defineProperty(Zotero.Item.prototype, 'topLevelItem', { + get: function () { + var item = this; // eslint-disable-line consistent-this + var parentItem; + while ((parentItem = item.parentItem)) { + item = parentItem; + } + return item; + } +}); Zotero.defineProperty(Zotero.Item.prototype, 'firstCreator', { get: function() { return this._firstCreator; } diff --git a/chrome/content/zotero/xpcom/data/items.js b/chrome/content/zotero/xpcom/data/items.js index bf10c7b7f9..9344de6ef9 100644 --- a/chrome/content/zotero/xpcom/data/items.js +++ b/chrome/content/zotero/xpcom/data/items.js @@ -1735,6 +1735,17 @@ Zotero.Items = function() { }; + /** + * Get the top-level items of all passed items + * + * @param {Zotero.Item[]} items + * @return {Zotero.Item[]} + */ + this.getTopLevel = function (items) { + return [...new Set(items.map(item => item.topLevelItem))]; + }; + + /** * Returns an array of items with children of selected parents removed * diff --git a/test/tests/itemTest.js b/test/tests/itemTest.js index b2f594e757..de0edd3d2b 100644 --- a/test/tests/itemTest.js +++ b/test/tests/itemTest.js @@ -483,6 +483,26 @@ describe("Zotero.Item", function () { }); }); + describe("#topLevelItem", function () { + it("should return self for top-level item", async function () { + var item = await createDataObject('item'); + assert.equal(item, item.topLevelItem); + }); + + it("should return parent item for note", async function () { + var item = await createDataObject('item'); + var note = await createDataObject('item', { itemType: 'note', parentItemID: item.id }); + assert.equal(item, note.topLevelItem); + }); + + it("should return top-level item for annotation", async function () { + var item = await createDataObject('item'); + var attachment = await importPDFAttachment(item); + var annotation = await createAnnotation('highlight', attachment); + assert.equal(item, annotation.topLevelItem); + }); + }); + describe("#getCreators()", function () { it("should update after creators are removed", function* () { var item = createUnsavedDataObject('item');