diff --git a/chrome/content/zotero/containers/tagSelectorContainer.jsx b/chrome/content/zotero/containers/tagSelectorContainer.jsx index 833bb56af2..bb5b59147a 100644 --- a/chrome/content/zotero/containers/tagSelectorContainer.jsx +++ b/chrome/content/zotero/containers/tagSelectorContainer.jsx @@ -140,7 +140,7 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent { ? await rows[0].getTags(...args) : await Zotero.CollectionTreeRow.getTagsAcrossRows(rows, ...args); // Multiple rows (collections, or collections across libraries) can return - // the same tag, so dedupe by name + // the same tag, so dedupe by name and type return this._dedupeTags(tags); } catch (e) { @@ -163,8 +163,9 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent { let seen = new Set(); let result = []; for (let tag of tags) { - if (!seen.has(tag.tag)) { - seen.add(tag.tag); + let key = tag.type + ':' + tag.tag; + if (!seen.has(key)) { + seen.add(key); result.push(tag); } } @@ -173,6 +174,7 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent { /** * Get all tags across the selected libraries (for "Display All Tags"), deduped by name + * and type * * @param {Number[]} [tagIDs] - Limit to the given tag IDs */ diff --git a/test/tests/tagSelectorTest.js b/test/tests/tagSelectorTest.js index 37bb410efe..d4f4d55e99 100644 --- a/test/tests/tagSelectorTest.js +++ b/test/tests/tagSelectorTest.js @@ -95,6 +95,38 @@ describe("Tag Selector", function () { assert.sameMembers(getRegularTags(), ['A', 'B']); }); + it("should show a manual tag when automatic tags are hidden and an automatic tag has the same name", async function () { + var collection = await createDataObject('collection'); + var item1 = createUnsavedDataObject('item', { collections: [collection.id] }); + item1.setTags([{ tag: "A", type: 1 }]); + var item2 = createUnsavedDataObject('item', { collections: [collection.id] }); + item2.setTags(["A"]); + await Zotero.DB.executeTransaction(async function () { + await item1.save(); + await item2.save(); + }); + var emptyCollection = await createDataObject('collection'); + await select(win, emptyCollection); + await waitForCallback(() => !tagSelector.state.tags.length); + + // Same-name tags come back in no particular order, so return the automatic one first + var getAllWithin = Zotero.Tags.getAllWithin; + var stub = sinon.stub(Zotero.Tags, 'getAllWithin').callsFake(async function (...args) { + let tags = await getAllWithin.apply(this, args); + return tags.sort((a, b) => b.type - a.type); + }); + tagSelector.toggleShowAutomatic(false); + try { + await select(win, collection); + await waitForCallback(() => tagSelector.state.tags.length); + assert.sameMembers(getRegularTags(), ['A']); + } + finally { + stub.restore(); + tagSelector.toggleShowAutomatic(true); + } + }); + it("should show tags from annotations for attachments in scope", async function () { var collection = await createDataObject('collection'); await select(win, collection);