From 6ae0c6055ebedda0724f28223ba745a9e12d8186 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sat, 3 Feb 2018 04:09:55 -0500 Subject: [PATCH] Allow dragging parent items to collection if children are selected This is a simplified version of the fix from #872. Unlike the proposal in #36, this doesn't require all child items to be selected, since in a search some children might be grayed out. If the child of an unselected parent item is included, the drag isn't allowed. Closes #36 (cherry picked from commit 38411fb56cca3680470b02b760cf5d64e259ecd1) --- .../zotero/xpcom/collectionTreeView.js | 2 ++ chrome/content/zotero/xpcom/data/items.js | 19 +++++++++++++++++++ test/tests/itemsTest.js | 19 +++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/chrome/content/zotero/xpcom/collectionTreeView.js b/chrome/content/zotero/xpcom/collectionTreeView.js index 253cedbf7..a2c97b959 100644 --- a/chrome/content/zotero/xpcom/collectionTreeView.js +++ b/chrome/content/zotero/xpcom/collectionTreeView.js @@ -1606,6 +1606,7 @@ Zotero.CollectionTreeView.prototype.canDropCheck = function (row, orient, dataTr if (dataType == 'zotero/item') { var ids = data; var items = Zotero.Items.get(ids); + items = Zotero.Items.keepParents(items); var skip = true; for (let item of items) { // Can only drag top-level items @@ -2115,6 +2116,7 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r } if (targetTreeRow.isPublications()) { + items = Zotero.Items.keepParents(items); let io = this._treebox.treeBody.ownerDocument.defaultView .ZoteroPane.showPublicationsWizard(items); if (!io) { diff --git a/chrome/content/zotero/xpcom/data/items.js b/chrome/content/zotero/xpcom/data/items.js index 2854d61d6..4bd91ee93 100644 --- a/chrome/content/zotero/xpcom/data/items.js +++ b/chrome/content/zotero/xpcom/data/items.js @@ -1186,6 +1186,25 @@ Zotero.Items = function() { }; + /** + * Returns an array of items with children of selected parents removed + * + * @return {Zotero.Item[]} + */ + this.keepParents = function (items) { + var parentItems = new Set( + items + .filter(item => item.isTopLevelItem()) + .map(item => item.id) + ); + return items.filter(item => { + var parentItemID = item.parentItemID; + // Not a child item or not a child of one of the passed items + return !parentItemID || !parentItems.has(parentItemID); + }); + } + + /* * Generate SQL to retrieve firstCreator field * diff --git a/test/tests/itemsTest.js b/test/tests/itemsTest.js index 1f09fc9cb..ba0200c1e 100644 --- a/test/tests/itemsTest.js +++ b/test/tests/itemsTest.js @@ -480,4 +480,23 @@ describe("Zotero.Items", function () { assert.instanceOf(feedItem, Zotero.FeedItem); }); }); + + describe("#keepParents()", function () { + it("should remove child items of passed items", async function () { + var item1 = await createDataObject('item'); + var item2 = await createDataObject('item', { itemType: 'note', parentItemID: item1.id }); + var item3 = await createDataObject('item', { itemType: 'note', parentItemID: item1.id }); + var item4 = await createDataObject('item'); + var item5 = await createDataObject('item', { itemType: 'note', parentItemID: item4.id }); + var otherItem = await createDataObject('item'); + var item6 = await createDataObject('item', { itemType: 'note', parentItemID: otherItem.id }); + + var items = Zotero.Items.keepParents([item1, item2, item3, item4, item5, item6]); + assert.sameMembers( + // Convert to ids for clearer output + items.map(item => item.id), + [item1, item4, item6].map(item => item.id) + ); + }); + }); });