2015-05-19 21:05:58 +00:00
|
|
|
|
describe("Item pane", function () {
|
2024-04-22 01:15:22 +00:00
|
|
|
|
var win, doc, ZoteroPane, Zotero_Tabs, ZoteroContextPane, itemsView;
|
|
|
|
|
|
|
|
|
|
async function waitForPreviewBoxRender(box) {
|
|
|
|
|
let success = await waitForCallback(
|
|
|
|
|
() => box._asyncRenderItemID && !box._asyncRendering);
|
|
|
|
|
if (!success) {
|
|
|
|
|
throw new Error("Wait for box render time out");
|
|
|
|
|
}
|
|
|
|
|
await box._preview._renderPromise;
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function waitForPreviewBoxReader(box, itemID) {
|
|
|
|
|
await waitForPreviewBoxRender(box);
|
|
|
|
|
let success = await waitForCallback(
|
|
|
|
|
() => box._preview._reader?.itemID == itemID, 100, 3000);
|
|
|
|
|
if (!success) {
|
|
|
|
|
throw new Error("Wait for box preview reader time out");
|
|
|
|
|
}
|
|
|
|
|
await box._preview._reader._initPromise;
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isPreviewDisplayed(box) {
|
|
|
|
|
return !!(box._preview.hasPreview
|
|
|
|
|
&& win.getComputedStyle(box._preview).display !== "none");
|
|
|
|
|
}
|
2015-05-19 21:05:58 +00:00
|
|
|
|
|
|
|
|
|
before(function* () {
|
|
|
|
|
win = yield loadZoteroPane();
|
|
|
|
|
doc = win.document;
|
2024-04-22 01:15:22 +00:00
|
|
|
|
ZoteroPane = win.ZoteroPane;
|
|
|
|
|
Zotero_Tabs = win.Zotero_Tabs;
|
|
|
|
|
ZoteroContextPane = win.ZoteroContextPane;
|
2015-05-19 21:05:58 +00:00
|
|
|
|
itemsView = win.ZoteroPane.itemsView;
|
|
|
|
|
});
|
|
|
|
|
after(function () {
|
|
|
|
|
win.close();
|
|
|
|
|
});
|
2024-05-10 12:23:26 +00:00
|
|
|
|
|
|
|
|
|
describe("Item pane header", function () {
|
|
|
|
|
let itemData = {
|
|
|
|
|
itemType: 'book',
|
|
|
|
|
title: 'Birds - A Primer of Ornithology (Teach Yourself Books)',
|
|
|
|
|
creators: [{
|
|
|
|
|
creatorType: 'author',
|
|
|
|
|
lastName: 'Hyde',
|
|
|
|
|
firstName: 'George E.'
|
|
|
|
|
}]
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
before(async function () {
|
|
|
|
|
await Zotero.Styles.init();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
after(function () {
|
|
|
|
|
Zotero.Prefs.clear('itemPaneHeader');
|
|
|
|
|
Zotero.Prefs.clear('itemPaneHeader.bibEntry.style');
|
|
|
|
|
Zotero.Prefs.clear('itemPaneHeader.bibEntry.locale');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should be hidden when set to None mode", async function () {
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader', 'none');
|
|
|
|
|
await createDataObject('item', itemData);
|
|
|
|
|
assert.isTrue(doc.querySelector('pane-header').hidden);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should show title when set to Title mode", async function () {
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader', 'title');
|
|
|
|
|
let item = await createDataObject('item', itemData);
|
|
|
|
|
|
|
|
|
|
assert.isFalse(doc.querySelector('pane-header .title').hidden);
|
|
|
|
|
assert.isTrue(doc.querySelector('pane-header .creator-year').hidden);
|
|
|
|
|
assert.isTrue(doc.querySelector('pane-header .bib-entry').hidden);
|
|
|
|
|
|
|
|
|
|
assert.equal(doc.querySelector('pane-header .title editable-text').value, item.getField('title'));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should show title/creator/year when set to Title/Creator/Year mode", async function () {
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader', 'titleCreatorYear');
|
|
|
|
|
let item = await createDataObject('item', itemData);
|
|
|
|
|
item.setField('date', '1962-05-01');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
|
|
|
|
|
assert.isTrue(doc.querySelector('pane-header .bib-entry').hidden);
|
|
|
|
|
assert.isFalse(doc.querySelector('pane-header .title').hidden);
|
|
|
|
|
assert.isFalse(doc.querySelector('pane-header .creator-year').hidden);
|
|
|
|
|
|
|
|
|
|
assert.equal(doc.querySelector('pane-header .title editable-text').value, item.getField('title'));
|
|
|
|
|
let creatorYearText = doc.querySelector('pane-header .creator-year').textContent;
|
|
|
|
|
assert.include(creatorYearText, 'Hyde');
|
|
|
|
|
assert.include(creatorYearText, '1962');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should show bib entry when set to Bibliography Entry mode", async function () {
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader', 'bibEntry');
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader.bibEntry.style', 'http://www.zotero.org/styles/apa');
|
|
|
|
|
await createDataObject('item', itemData);
|
|
|
|
|
|
|
|
|
|
assert.isFalse(doc.querySelector('pane-header .bib-entry').hidden);
|
|
|
|
|
assert.isTrue(doc.querySelector('pane-header .title').hidden);
|
|
|
|
|
assert.isTrue(doc.querySelector('pane-header .creator-year').hidden);
|
|
|
|
|
|
|
|
|
|
let bibEntry = doc.querySelector('pane-header .bib-entry').shadowRoot.firstElementChild.textContent;
|
|
|
|
|
assert.equal(bibEntry.trim(), 'Hyde, G. E. (n.d.). Birds—A Primer of Ornithology (Teach Yourself Books).');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should update bib entry on item change when set to Bibliography Entry mode", async function () {
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader', 'bibEntry');
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader.bibEntry.style', 'http://www.zotero.org/styles/apa');
|
|
|
|
|
let item = await createDataObject('item', itemData);
|
|
|
|
|
|
|
|
|
|
let bibEntryElem = doc.querySelector('pane-header .bib-entry').shadowRoot.firstElementChild;
|
|
|
|
|
|
|
|
|
|
assert.equal(bibEntryElem.textContent.trim(), 'Hyde, G. E. (n.d.). Birds—A Primer of Ornithology (Teach Yourself Books).');
|
|
|
|
|
|
|
|
|
|
item.setField('date', '1962-05-01');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
assert.equal(bibEntryElem.textContent.trim(), 'Hyde, G. E. (1962). Birds—A Primer of Ornithology (Teach Yourself Books).');
|
|
|
|
|
|
|
|
|
|
item.setCreators([
|
|
|
|
|
{
|
|
|
|
|
creatorType: 'author',
|
|
|
|
|
lastName: 'Smith',
|
|
|
|
|
firstName: 'John'
|
|
|
|
|
}
|
|
|
|
|
]);
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
assert.equal(bibEntryElem.textContent.trim(), 'Smith, J. (1962). Birds—A Primer of Ornithology (Teach Yourself Books).');
|
|
|
|
|
|
|
|
|
|
item.setField('title', 'Birds');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
assert.equal(bibEntryElem.textContent.trim(), 'Smith, J. (1962). Birds.');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should update bib entry on style change when set to Bibliography Entry mode", async function () {
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader', 'bibEntry');
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader.bibEntry.style', 'http://www.zotero.org/styles/apa');
|
|
|
|
|
await createDataObject('item', itemData);
|
|
|
|
|
|
|
|
|
|
let bibEntryElem = doc.querySelector('pane-header .bib-entry').shadowRoot.firstElementChild;
|
|
|
|
|
|
|
|
|
|
assert.equal(bibEntryElem.textContent.trim(), 'Hyde, G. E. (n.d.). Birds—A Primer of Ornithology (Teach Yourself Books).');
|
|
|
|
|
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader.bibEntry.style', 'http://www.zotero.org/styles/chicago-author-date');
|
|
|
|
|
assert.equal(bibEntryElem.textContent.trim(), 'Hyde, George E. n.d. Birds - A Primer of Ornithology (Teach Yourself Books).');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should update bib entry on locale change when set to Bibliography Entry mode", async function () {
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader', 'bibEntry');
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader.bibEntry.style', 'http://www.zotero.org/styles/apa');
|
|
|
|
|
await createDataObject('item', itemData);
|
|
|
|
|
|
|
|
|
|
let bibEntryElem = doc.querySelector('pane-header .bib-entry').shadowRoot.firstElementChild;
|
|
|
|
|
|
|
|
|
|
assert.equal(bibEntryElem.textContent.trim(), 'Hyde, G. E. (n.d.). Birds—A Primer of Ornithology (Teach Yourself Books).');
|
|
|
|
|
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader.bibEntry.locale', 'de-DE');
|
|
|
|
|
assert.equal(bibEntryElem.textContent.trim(), 'Hyde, G. E. (o. J.). Birds—A Primer of Ornithology (Teach Yourself Books).');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should fall back to Title/Creator/Year when citation style is missing", async function () {
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader', 'bibEntry');
|
|
|
|
|
Zotero.Prefs.set('itemPaneHeader.bibEntry.style', 'http://www.zotero.org/styles/an-id-that-does-not-match-any-citation-style');
|
|
|
|
|
await createDataObject('item', itemData);
|
|
|
|
|
|
|
|
|
|
assert.isTrue(doc.querySelector('pane-header .bib-entry').hidden);
|
|
|
|
|
assert.isFalse(doc.querySelector('pane-header .title').hidden);
|
|
|
|
|
assert.isFalse(doc.querySelector('pane-header .creator-year').hidden);
|
|
|
|
|
});
|
|
|
|
|
});
|
2015-05-19 21:05:58 +00:00
|
|
|
|
|
|
|
|
|
describe("Info pane", function () {
|
2024-05-11 08:02:59 +00:00
|
|
|
|
it("should place Title after Item Type and before creators", async function () {
|
|
|
|
|
var item = await createDataObject('item');
|
|
|
|
|
var itemPane = win.ZoteroPane.itemPane;
|
|
|
|
|
var fields = [...itemPane.querySelectorAll('.meta-label')]
|
|
|
|
|
.map(x => x.getAttribute('fieldname'));
|
|
|
|
|
assert.equal(fields[0], 'itemType');
|
|
|
|
|
assert.equal(fields[1], 'title');
|
|
|
|
|
assert.isTrue(fields[2].startsWith('creator'));
|
|
|
|
|
});
|
|
|
|
|
|
2015-05-19 21:05:58 +00:00
|
|
|
|
it("should refresh on item update", function* () {
|
|
|
|
|
var item = new Zotero.Item('book');
|
|
|
|
|
var id = yield item.saveTx();
|
|
|
|
|
|
|
|
|
|
var itemBox = doc.getElementById('zotero-editpane-item-box');
|
2023-12-21 20:10:04 +00:00
|
|
|
|
var label = itemBox.querySelectorAll('[fieldname="series"]')[1];
|
|
|
|
|
assert.equal(label.value, '');
|
2015-05-19 21:05:58 +00:00
|
|
|
|
|
2023-12-21 20:10:04 +00:00
|
|
|
|
item.setField('series', 'Test');
|
2015-05-19 21:05:58 +00:00
|
|
|
|
yield item.saveTx();
|
|
|
|
|
|
2023-12-21 20:10:04 +00:00
|
|
|
|
label = itemBox.querySelectorAll('[fieldname="series"]')[1];
|
|
|
|
|
assert.equal(label.value, 'Test');
|
2015-05-19 21:05:58 +00:00
|
|
|
|
|
|
|
|
|
yield Zotero.Items.erase(id);
|
2024-04-22 01:15:22 +00:00
|
|
|
|
});
|
2016-06-29 09:24:14 +00:00
|
|
|
|
|
|
|
|
|
|
2022-06-20 04:47:14 +00:00
|
|
|
|
it("should swap creator names", async function () {
|
2016-06-29 09:24:14 +00:00
|
|
|
|
var item = new Zotero.Item('book');
|
|
|
|
|
item.setCreators([
|
|
|
|
|
{
|
|
|
|
|
firstName: "First",
|
|
|
|
|
lastName: "Last",
|
|
|
|
|
creatorType: "author"
|
|
|
|
|
}
|
|
|
|
|
]);
|
2022-06-20 04:47:14 +00:00
|
|
|
|
await item.saveTx();
|
2016-06-29 09:24:14 +00:00
|
|
|
|
|
|
|
|
|
var itemBox = doc.getElementById('zotero-editpane-item-box');
|
2023-12-21 20:10:04 +00:00
|
|
|
|
var lastName = itemBox.querySelector('#itembox-field-value-creator-0-lastName');
|
|
|
|
|
var parent = lastName.closest(".creator-type-value");
|
2022-06-20 04:47:14 +00:00
|
|
|
|
assert.property(parent, 'oncontextmenu');
|
2023-12-21 20:10:04 +00:00
|
|
|
|
assert.isFunction(parent.oncontextmenu);
|
2016-06-29 09:24:14 +00:00
|
|
|
|
|
2023-04-04 18:52:10 +00:00
|
|
|
|
var menupopup = itemBox.querySelector('#zotero-creator-transform-menu');
|
2016-06-29 09:24:14 +00:00
|
|
|
|
// Fake a right-click
|
|
|
|
|
doc.popupNode = parent;
|
|
|
|
|
menupopup.openPopup(
|
|
|
|
|
parent, "after_start", 0, 0, true, false, new MouseEvent('click', { button: 2 })
|
|
|
|
|
);
|
|
|
|
|
var menuitem = menupopup.getElementsByTagName('menuitem')[0];
|
|
|
|
|
menuitem.click();
|
2022-06-20 04:47:14 +00:00
|
|
|
|
await waitForItemEvent('modify');
|
2016-06-29 09:24:14 +00:00
|
|
|
|
|
|
|
|
|
var creator = item.getCreators()[0];
|
|
|
|
|
assert.propertyVal(creator, 'firstName', 'Last');
|
|
|
|
|
assert.propertyVal(creator, 'lastName', 'First');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2023-04-28 00:38:48 +00:00
|
|
|
|
it("shouldn't show Swap Names option for single-field mode", async function () {
|
2016-06-29 09:24:14 +00:00
|
|
|
|
var item = new Zotero.Item('book');
|
|
|
|
|
item.setCreators([
|
|
|
|
|
{
|
|
|
|
|
name: "Name",
|
|
|
|
|
creatorType: "author"
|
|
|
|
|
}
|
|
|
|
|
]);
|
2023-04-28 00:38:48 +00:00
|
|
|
|
await item.saveTx();
|
2016-06-29 09:24:14 +00:00
|
|
|
|
|
|
|
|
|
var itemBox = doc.getElementById('zotero-editpane-item-box');
|
2023-12-21 20:10:04 +00:00
|
|
|
|
var label = itemBox.querySelector('#itembox-field-value-creator-0-lastName');
|
|
|
|
|
var firstlast = label.closest('.creator-type-value');
|
|
|
|
|
firstlast.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, button: 2 }));
|
2023-04-28 00:38:48 +00:00
|
|
|
|
|
|
|
|
|
var menuitem = doc.getElementById('creator-transform-swap-names');
|
|
|
|
|
assert.isTrue(menuitem.hidden);
|
2016-06-29 09:24:14 +00:00
|
|
|
|
});
|
2023-12-21 20:10:04 +00:00
|
|
|
|
|
|
|
|
|
it("should reorder creators", async function () {
|
|
|
|
|
var item = new Zotero.Item('book');
|
|
|
|
|
item.setCreators([
|
|
|
|
|
{
|
|
|
|
|
lastName: "One",
|
|
|
|
|
creatorType: "author"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
lastName: "Two",
|
|
|
|
|
creatorType: "author"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
lastName: "Three",
|
|
|
|
|
creatorType: "author"
|
|
|
|
|
}
|
|
|
|
|
]);
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
|
|
|
|
|
var itemBox = doc.getElementById('zotero-editpane-item-box');
|
|
|
|
|
// Move One to the last spot
|
|
|
|
|
itemBox.moveCreator(0, null, 3);
|
|
|
|
|
await waitForItemEvent('modify');
|
|
|
|
|
let thirdLastName = itemBox.querySelector("[fieldname='creator-2-lastName']").value;
|
|
|
|
|
assert.equal(thirdLastName, "One");
|
|
|
|
|
|
|
|
|
|
// Move One to the second spot
|
|
|
|
|
itemBox.moveCreator(2, null, 1);
|
|
|
|
|
await waitForItemEvent('modify');
|
|
|
|
|
let secondLastname = itemBox.querySelector("[fieldname='creator-1-lastName']").value;
|
|
|
|
|
assert.equal(secondLastname, "One");
|
|
|
|
|
|
|
|
|
|
// Move Two down
|
|
|
|
|
itemBox.moveCreator(0, 'down');
|
|
|
|
|
await waitForItemEvent('modify');
|
|
|
|
|
secondLastname = itemBox.querySelector("[fieldname='creator-1-lastName']").value;
|
|
|
|
|
let firstLastName = itemBox.querySelector("[fieldname='creator-0-lastName']").value;
|
|
|
|
|
assert.equal(secondLastname, "Two");
|
|
|
|
|
assert.equal(firstLastName, "One");
|
|
|
|
|
|
|
|
|
|
// Move Three up
|
|
|
|
|
itemBox.moveCreator(2, 'up');
|
|
|
|
|
await waitForItemEvent('modify');
|
|
|
|
|
secondLastname = itemBox.querySelector("[fieldname='creator-1-lastName']").value;
|
|
|
|
|
thirdLastName = itemBox.querySelector("[fieldname='creator-2-lastName']").value;
|
|
|
|
|
assert.equal(secondLastname, "Three");
|
|
|
|
|
assert.equal(thirdLastName, "Two");
|
|
|
|
|
});
|
2016-06-29 09:24:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Note: This issue applies to all context menus in the item box (text transform, name swap),
|
|
|
|
|
// though the others aren't tested. This might go away with the XUL->HTML transition.
|
|
|
|
|
it.skip("should save open field after changing creator type", function* () {
|
|
|
|
|
var item = new Zotero.Item('book');
|
|
|
|
|
item.setCreators([
|
|
|
|
|
{
|
|
|
|
|
firstName: "First",
|
|
|
|
|
lastName: "Last",
|
|
|
|
|
creatorType: "author"
|
|
|
|
|
}
|
|
|
|
|
]);
|
|
|
|
|
var id = yield item.saveTx();
|
|
|
|
|
|
|
|
|
|
var itemBox = doc.getElementById('zotero-editpane-item-box');
|
2023-04-04 18:52:10 +00:00
|
|
|
|
var label = itemBox.querySelector('[fieldname="place"]');
|
2016-06-29 09:24:14 +00:00
|
|
|
|
label.click();
|
2023-04-04 18:52:10 +00:00
|
|
|
|
var textbox = itemBox.querySelector('[fieldname="place"]');
|
2016-06-29 09:24:14 +00:00
|
|
|
|
textbox.value = "Place";
|
|
|
|
|
|
2023-04-04 18:52:10 +00:00
|
|
|
|
var menuLabel = itemBox.querySelector('[fieldname="creator-0-typeID"]');
|
2016-06-29 09:24:14 +00:00
|
|
|
|
menuLabel.click();
|
|
|
|
|
var menupopup = itemBox._creatorTypeMenu;
|
|
|
|
|
var menuItems = menupopup.getElementsByTagName('menuitem');
|
|
|
|
|
menuItems[1].click();
|
|
|
|
|
yield waitForItemEvent('modify');
|
|
|
|
|
|
|
|
|
|
assert.equal(item.getField('place'), 'Place');
|
|
|
|
|
assert.equal(Zotero.CreatorTypes.getName(item.getCreators()[0].creatorTypeID), 'contributor');
|
|
|
|
|
|
|
|
|
|
// Wait for no-op saveTx()
|
|
|
|
|
yield Zotero.Promise.delay(1);
|
|
|
|
|
});
|
2018-01-05 08:40:57 +00:00
|
|
|
|
|
|
|
|
|
it("should accept 'now' for Accessed", async function () {
|
|
|
|
|
var item = await createDataObject('item');
|
|
|
|
|
|
|
|
|
|
var itemBox = doc.getElementById('zotero-editpane-item-box');
|
2023-12-21 20:10:04 +00:00
|
|
|
|
var textbox = itemBox.querySelector('[fieldname="accessDate"]');
|
2018-01-05 08:40:57 +00:00
|
|
|
|
textbox.value = 'now';
|
|
|
|
|
// Blur events don't necessarily trigger if window doesn't have focus
|
|
|
|
|
itemBox.hideEditor(textbox);
|
|
|
|
|
|
|
|
|
|
await waitForItemEvent('modify');
|
|
|
|
|
|
|
|
|
|
assert.approximately(
|
|
|
|
|
Zotero.Date.sqlToDate(item.getField('accessDate'), true).getTime(),
|
|
|
|
|
Date.now(),
|
2018-01-05 11:04:53 +00:00
|
|
|
|
5000
|
2018-01-05 08:40:57 +00:00
|
|
|
|
);
|
|
|
|
|
});
|
2022-08-08 15:48:33 +00:00
|
|
|
|
|
|
|
|
|
it("should persist fieldMode after hiding a creator name editor", async function () {
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
item.setCreators([
|
|
|
|
|
{
|
|
|
|
|
name: "First Last",
|
|
|
|
|
creatorType: "author",
|
|
|
|
|
fieldMode: 1
|
|
|
|
|
}
|
|
|
|
|
]);
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
|
|
|
|
|
let itemBox = doc.getElementById('zotero-editpane-item-box');
|
2023-04-04 18:52:10 +00:00
|
|
|
|
|
2023-12-21 20:10:04 +00:00
|
|
|
|
itemBox.querySelector('[fieldname="creator-0-lastName"]').click();
|
2023-04-28 00:38:48 +00:00
|
|
|
|
itemBox.hideEditor(itemBox.querySelector('input[fieldname="creator-0-lastName"]'));
|
2022-08-08 15:48:33 +00:00
|
|
|
|
|
|
|
|
|
assert.equal(
|
2023-12-21 20:10:04 +00:00
|
|
|
|
itemBox.querySelector('[fieldname="creator-0-lastName"]').getAttribute('fieldMode'),
|
2022-08-08 15:48:33 +00:00
|
|
|
|
'1'
|
|
|
|
|
);
|
|
|
|
|
});
|
2024-04-22 01:15:22 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe("Attachments pane", function () {
|
|
|
|
|
let paneID = "attachments";
|
|
|
|
|
|
|
|
|
|
beforeEach(function () {
|
|
|
|
|
Zotero.Prefs.set("panes.attachments.open", true);
|
|
|
|
|
Zotero.Prefs.set("showAttachmentPreview", true);
|
|
|
|
|
Zotero_Tabs.select("zotero-pane");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
afterEach(function () {
|
|
|
|
|
Zotero_Tabs.select("zotero-pane");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should show attachments pane in library for regular item", async function () {
|
|
|
|
|
// Regular item: show
|
|
|
|
|
let attachmentsBox = ZoteroPane.itemPane._itemDetails.getPane(paneID);
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
await ZoteroPane.selectItem(item.id);
|
|
|
|
|
assert.isFalse(attachmentsBox.hidden);
|
|
|
|
|
|
|
|
|
|
// Child attachment: hide
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
let attachment = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
await ZoteroPane.selectItem(attachment.id);
|
|
|
|
|
assert.isTrue(attachmentsBox.hidden);
|
|
|
|
|
|
|
|
|
|
// Standalone attachment: hide
|
|
|
|
|
let attachment1 = await importFileAttachment('test.pdf');
|
|
|
|
|
await ZoteroPane.selectItem(attachment1.id);
|
|
|
|
|
assert.isTrue(attachmentsBox.hidden);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should not show attachments pane preview in reader best-matched attachment item", async function () {
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
let attachment = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
await ZoteroPane.viewItems([attachment]);
|
|
|
|
|
let tabID = Zotero_Tabs.selectedID;
|
|
|
|
|
let itemDetails = ZoteroContextPane.context._getItemContext(tabID);
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
assert.isFalse(attachmentsBox.hidden);
|
|
|
|
|
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
|
|
|
|
|
assert.isFalse(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should not show attachments pane in reader standalone attachment item", async function () {
|
|
|
|
|
let attachment = await importFileAttachment('test.pdf');
|
|
|
|
|
await ZoteroPane.viewItems([attachment]);
|
|
|
|
|
let tabID = Zotero_Tabs.selectedID;
|
|
|
|
|
let itemDetails = ZoteroContextPane.context._getItemContext(tabID);
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
assert.isTrue(attachmentsBox.hidden);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should show attachments pane preview in reader non-best-matched attachment item", async function () {
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let bestAttachments = await item.getBestAttachments();
|
|
|
|
|
await ZoteroPane.viewItems([bestAttachments[1]]);
|
|
|
|
|
// Ensure context pane is open
|
|
|
|
|
ZoteroContextPane.splitter.setAttribute("state", "open");
|
|
|
|
|
await waitForFrame();
|
|
|
|
|
let tabID = Zotero_Tabs.selectedID;
|
|
|
|
|
let itemDetails = ZoteroContextPane.context._getItemContext(tabID);
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
assert.isFalse(attachmentsBox.hidden);
|
|
|
|
|
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
await waitForPreviewBoxRender(attachmentsBox);
|
|
|
|
|
assert.isTrue(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should not render attachments pane preview when show preview is disabled", async function () {
|
|
|
|
|
Zotero.Prefs.set("showAttachmentPreview", false);
|
|
|
|
|
|
|
|
|
|
let itemDetails = ZoteroPane.itemPane._itemDetails;
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
await ZoteroPane.selectItem(item.id);
|
|
|
|
|
assert.isFalse(attachmentsBox.hidden);
|
|
|
|
|
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
|
|
|
|
|
assert.isFalse(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should only render after attachments pane becomes visible", async function () {
|
|
|
|
|
// Resize to very small height to ensure the attachment box is not in view
|
|
|
|
|
let height = doc.documentElement.clientHeight;
|
|
|
|
|
win.resizeTo(null, 100);
|
|
|
|
|
|
|
|
|
|
let itemDetails = ZoteroPane.itemPane._itemDetails;
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
let preview = attachmentsBox._preview;
|
|
|
|
|
// Force discard previous preview
|
|
|
|
|
await preview.discard(true);
|
|
|
|
|
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await ZoteroPane.selectItem(item.id);
|
|
|
|
|
assert.isFalse(itemDetails.isPaneVisible(paneID));
|
|
|
|
|
// Do not use _isAlreadyRendered, since that changes the render flag state
|
|
|
|
|
assert.equal(attachmentsBox._syncRenderItemID, item.id);
|
|
|
|
|
assert.notEqual(attachmentsBox._asyncRenderItemID, item.id);
|
|
|
|
|
assert.isFalse(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
await waitForPreviewBoxRender(attachmentsBox);
|
|
|
|
|
assert.isTrue(itemDetails.isPaneVisible(paneID));
|
|
|
|
|
assert.equal(attachmentsBox._syncRenderItemID, item.id);
|
|
|
|
|
assert.equal(attachmentsBox._asyncRenderItemID, item.id);
|
|
|
|
|
|
|
|
|
|
assert.isTrue(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
assert.isTrue(preview.hasPreview);
|
|
|
|
|
win.resizeTo(null, height);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should update attachments pane when attachments changed", async function () {
|
|
|
|
|
// https://forums.zotero.org/discussion/113632/zotero-7-beta-pdf-attachment-preview-and-annotations-not-refreshed-after-adding-annotations
|
|
|
|
|
|
|
|
|
|
let itemDetails = ZoteroPane.itemPane._itemDetails;
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
let preview = attachmentsBox._preview;
|
|
|
|
|
// Force discard previous preview
|
|
|
|
|
await preview.discard(true);
|
|
|
|
|
|
|
|
|
|
// Pin the pane to ensure it's rendered
|
|
|
|
|
itemDetails.pinnedPane = paneID;
|
|
|
|
|
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
|
|
|
|
|
await ZoteroPane.selectItem(item.id);
|
|
|
|
|
assert.isTrue(await waitForPreviewBoxRender(attachmentsBox));
|
|
|
|
|
// No preview
|
|
|
|
|
assert.isFalse(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
// No row
|
|
|
|
|
assert.equal(attachmentsBox.querySelectorAll("attachment-row").length, 0);
|
|
|
|
|
|
|
|
|
|
// Add an attachment
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.png');
|
|
|
|
|
let _attachment1 = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
await ZoteroPane.selectItem(item.id);
|
|
|
|
|
await itemDetails._renderPromise;
|
|
|
|
|
await waitForPreviewBoxRender(attachmentsBox);
|
|
|
|
|
// Image preview for item with image attachment
|
|
|
|
|
assert.isTrue(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
assert.equal(preview.previewType, "image");
|
|
|
|
|
// 1 row
|
|
|
|
|
assert.equal(attachmentsBox.querySelectorAll("attachment-row").length, 1);
|
|
|
|
|
|
|
|
|
|
// Add an PDF attachment, which will be best match and update the preview
|
|
|
|
|
file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
let attachment2 = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
await waitForPreviewBoxReader(attachmentsBox, attachment2.id);
|
|
|
|
|
await Zotero.Promise.delay(100);
|
|
|
|
|
// PDF preview
|
|
|
|
|
assert.isTrue(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
assert.equal(preview.previewType, "pdf");
|
|
|
|
|
// 2 rows
|
|
|
|
|
assert.equal(attachmentsBox.querySelectorAll("attachment-row").length, 2);
|
|
|
|
|
|
|
|
|
|
// Created annotations should be update in preview and attachment row
|
|
|
|
|
let annotation = await createAnnotation('highlight', attachment2);
|
|
|
|
|
await Zotero.Promise.delay(100);
|
|
|
|
|
// Annotation updated in preview reader
|
|
|
|
|
let readerAnnotation
|
|
|
|
|
= preview._reader._internalReader._annotationManager._annotations.find(
|
|
|
|
|
a => a.libraryID === annotation.libraryID && a.id === annotation.key
|
|
|
|
|
);
|
|
|
|
|
assert.exists(readerAnnotation);
|
|
|
|
|
|
|
|
|
|
assert.equal(attachmentsBox.querySelectorAll("attachment-row").length, 2);
|
|
|
|
|
let attachmentRow = attachmentsBox.querySelector(`attachment-row[attachment-id="${attachment2.id}"]`);
|
|
|
|
|
assert.isFalse(attachmentRow._annotationButton.hidden);
|
|
|
|
|
// 1 annotation
|
|
|
|
|
assert.equal(attachmentRow._annotationButton.querySelector('.label').textContent, "1");
|
|
|
|
|
|
|
|
|
|
// Deleted annotations should be removed from preview and attachment row
|
|
|
|
|
await annotation.eraseTx();
|
|
|
|
|
await Zotero.Promise.delay(100);
|
|
|
|
|
// Annotation removed from preview reader
|
|
|
|
|
readerAnnotation
|
|
|
|
|
= preview._reader._internalReader._annotationManager._annotations.find(
|
|
|
|
|
a => a.libraryID === annotation.libraryID && a.id === annotation.key
|
|
|
|
|
);
|
|
|
|
|
assert.notExists(readerAnnotation);
|
|
|
|
|
// Row might be recreated
|
|
|
|
|
attachmentRow = attachmentsBox.querySelector(`attachment-row[attachment-id="${attachment2.id}"]`);
|
|
|
|
|
assert.isTrue(attachmentRow._annotationButton.hidden);
|
|
|
|
|
// 0 annotation
|
|
|
|
|
assert.equal(attachmentRow._annotationButton.querySelector('.label').textContent, "0");
|
|
|
|
|
|
|
|
|
|
// Delete attachment
|
|
|
|
|
await attachment2.eraseTx();
|
|
|
|
|
await Zotero.Promise.delay(100);
|
|
|
|
|
// Image preview for item with image attachment
|
|
|
|
|
assert.isTrue(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
assert.equal(preview.previewType, "image");
|
|
|
|
|
// 1 row
|
|
|
|
|
assert.equal(attachmentsBox.querySelectorAll("attachment-row").length, 1);
|
|
|
|
|
// The corresponding row should be removed
|
|
|
|
|
attachmentRow = attachmentsBox.querySelector(`attachment-row[attachment-id="${attachment2.id}"]`);
|
|
|
|
|
assert.notExists(attachmentRow);
|
|
|
|
|
|
|
|
|
|
// Unpin
|
|
|
|
|
itemDetails.pinnedPane = "";
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should keep attachments pane preview status after switching tab", async function () {
|
|
|
|
|
// https://forums.zotero.org/discussion/113658/zotero-7-beta-preview-appearing-in-the-item-pane-of-the-pdf-tab
|
|
|
|
|
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
let attachment = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Open reader
|
|
|
|
|
await ZoteroPane.viewItems([attachment]);
|
|
|
|
|
let tabID = Zotero_Tabs.selectedID;
|
|
|
|
|
await Zotero.Reader.getByTabID(tabID)._waitForReader();
|
|
|
|
|
// Ensure context pane is open
|
|
|
|
|
ZoteroContextPane.splitter.setAttribute("state", "open");
|
|
|
|
|
await waitForFrame();
|
|
|
|
|
|
|
|
|
|
let itemDetails = ZoteroContextPane.context._getItemContext(tabID);
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
assert.isFalse(attachmentsBox.hidden);
|
|
|
|
|
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
assert.isFalse(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
|
|
|
|
|
// Select library tab
|
|
|
|
|
Zotero_Tabs.select("zotero-pane");
|
|
|
|
|
let libraryItemDetails = ZoteroPane.itemPane._itemDetails;
|
|
|
|
|
let libraryAttachmentsBox = libraryItemDetails.getPane(paneID);
|
|
|
|
|
await ZoteroPane.selectItem(item.id);
|
|
|
|
|
await waitForScrollToPane(libraryItemDetails, paneID);
|
|
|
|
|
// Collapse section
|
|
|
|
|
libraryAttachmentsBox.querySelector('collapsible-section > .head').click();
|
|
|
|
|
await Zotero.Promise.delay(50);
|
|
|
|
|
// Open section
|
|
|
|
|
libraryAttachmentsBox.querySelector('collapsible-section > .head').click();
|
|
|
|
|
await Zotero.Promise.delay(50);
|
|
|
|
|
|
|
|
|
|
// Select reader tab
|
|
|
|
|
Zotero_Tabs.select(tabID);
|
|
|
|
|
|
|
|
|
|
// Make sure the preview status is not changed in reader
|
|
|
|
|
assert.isFalse(isPreviewDisplayed(attachmentsBox));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This test is essential to ensure the proper functioning of the sync/async rendering,
|
|
|
|
|
* scrolling handler, and pinning mechanism of ItemDetails.
|
|
|
|
|
* AttachmentsBox serves as a good example since it involves both sync and async rendering.
|
|
|
|
|
* If this test fails, it is not recommended to add timeouts as a quick fix.
|
|
|
|
|
*/
|
|
|
|
|
it("should keep attachments pane status after changing selection", async function () {
|
|
|
|
|
let itemDetails = ZoteroPane.itemPane._itemDetails;
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
let preview = attachmentsBox._preview;
|
|
|
|
|
|
|
|
|
|
// Pin the pane to avoid always scrolling to the section
|
|
|
|
|
itemDetails.pinnedPane = paneID;
|
|
|
|
|
|
|
|
|
|
// item with attachment (1 annotation)
|
|
|
|
|
let item1 = new Zotero.Item('book');
|
|
|
|
|
await item1.saveTx();
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
let attachment1 = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item1.id
|
|
|
|
|
});
|
|
|
|
|
let annotation = await createAnnotation('highlight', attachment1);
|
|
|
|
|
|
|
|
|
|
await itemDetails._renderPromise;
|
|
|
|
|
await waitForPreviewBoxReader(attachmentsBox, attachment1.id);
|
|
|
|
|
|
|
|
|
|
assert.isFalse(attachmentsBox.hidden);
|
|
|
|
|
let readerAnnotation
|
|
|
|
|
= preview._reader._internalReader._annotationManager._annotations.find(
|
|
|
|
|
a => a.libraryID === annotation.libraryID && a.id === annotation.key
|
|
|
|
|
);
|
|
|
|
|
assert.exists(readerAnnotation);
|
|
|
|
|
assert.equal(attachmentsBox.querySelectorAll("attachment-row").length, 1);
|
|
|
|
|
let attachmentRow = attachmentsBox.querySelector(`attachment-row[attachment-id="${attachment1.id}"]`);
|
|
|
|
|
assert.isFalse(attachmentRow._annotationButton.hidden);
|
|
|
|
|
// 1 annotation
|
|
|
|
|
assert.equal(attachmentRow._annotationButton.querySelector('.label').textContent, "1");
|
|
|
|
|
|
|
|
|
|
// item with attachment (no annotation)
|
|
|
|
|
let item2 = new Zotero.Item('book');
|
|
|
|
|
await item2.saveTx();
|
|
|
|
|
file = getTestDataDirectory();
|
|
|
|
|
file.append('wonderland_short.pdf');
|
|
|
|
|
let attachment2 = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item2.id
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Select item with attachment (no annotation)
|
|
|
|
|
await itemDetails._renderPromise;
|
|
|
|
|
await waitForPreviewBoxReader(attachmentsBox, attachment2.id);
|
|
|
|
|
|
|
|
|
|
assert.isFalse(attachmentsBox.hidden);
|
|
|
|
|
readerAnnotation
|
|
|
|
|
= preview._reader._internalReader._annotationManager._annotations.find(
|
|
|
|
|
a => a.libraryID === annotation.libraryID && a.id === annotation.key
|
|
|
|
|
);
|
|
|
|
|
assert.notExists(readerAnnotation);
|
|
|
|
|
assert.equal(attachmentsBox.querySelectorAll("attachment-row").length, 1);
|
|
|
|
|
attachmentRow = attachmentsBox.querySelector(`attachment-row[attachment-id="${attachment2.id}"]`);
|
|
|
|
|
assert.isTrue(attachmentRow._annotationButton.hidden);
|
|
|
|
|
// 0 annotation
|
|
|
|
|
assert.equal(attachmentRow._annotationButton.querySelector('.label').textContent, "0");
|
|
|
|
|
|
|
|
|
|
let item3 = new Zotero.Item('book');
|
|
|
|
|
await item3.saveTx();
|
|
|
|
|
|
|
|
|
|
// Select item without attachment
|
|
|
|
|
await itemDetails._renderPromise;
|
|
|
|
|
|
|
|
|
|
assert.isFalse(attachmentsBox.hidden);
|
|
|
|
|
assert.equal(attachmentsBox.querySelectorAll("attachment-row").length, 0);
|
|
|
|
|
|
|
|
|
|
// Again, select item with attachment (1 annotation)
|
|
|
|
|
await ZoteroPane.selectItem(item1.id);
|
|
|
|
|
await itemDetails._renderPromise;
|
|
|
|
|
await waitForPreviewBoxReader(attachmentsBox, attachment1.id);
|
|
|
|
|
|
|
|
|
|
assert.isFalse(attachmentsBox.hidden);
|
|
|
|
|
readerAnnotation
|
|
|
|
|
= preview._reader._internalReader._annotationManager._annotations.find(
|
|
|
|
|
a => a.libraryID === annotation.libraryID && a.id === annotation.key
|
|
|
|
|
);
|
|
|
|
|
assert.exists(readerAnnotation);
|
|
|
|
|
assert.equal(attachmentsBox.querySelectorAll("attachment-row").length, 1);
|
|
|
|
|
attachmentRow = attachmentsBox.querySelector(`attachment-row[attachment-id="${attachment1.id}"]`);
|
|
|
|
|
assert.isFalse(attachmentRow._annotationButton.hidden);
|
|
|
|
|
// 1 annotation
|
|
|
|
|
assert.equal(attachmentRow._annotationButton.querySelector('.label').textContent, "1");
|
|
|
|
|
|
|
|
|
|
// Unpin
|
|
|
|
|
itemDetails.pinnedPane = "";
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should open attachment on clicking attachment row", async function () {
|
|
|
|
|
let itemDetails = ZoteroPane.itemPane._itemDetails;
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
let attachment = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await ZoteroPane.selectItem(item.id);
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
await waitForPreviewBoxRender(attachmentsBox);
|
|
|
|
|
|
|
|
|
|
let attachmentRow = attachmentsBox.querySelector(`attachment-row[attachment-id="${attachment.id}"]`);
|
|
|
|
|
attachmentRow._attachmentButton.click();
|
|
|
|
|
await Zotero.Promise.delay(100);
|
|
|
|
|
let reader = await Zotero.Reader.getByTabID(Zotero_Tabs.selectedID);
|
|
|
|
|
// Should open attachment
|
|
|
|
|
assert.equal(reader.itemID, attachment.id);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should select attachment on clicking annotation button of attachment row", async function () {
|
|
|
|
|
let itemDetails = ZoteroPane.itemPane._itemDetails;
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
let attachment = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
let _annotation = await createAnnotation('highlight', attachment);
|
|
|
|
|
|
|
|
|
|
await ZoteroPane.selectItem(item.id);
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
await waitForPreviewBoxRender(attachmentsBox);
|
|
|
|
|
|
|
|
|
|
let attachmentRow = attachmentsBox.querySelector(`attachment-row[attachment-id="${attachment.id}"]`);
|
|
|
|
|
attachmentRow._annotationButton.click();
|
|
|
|
|
await Zotero.Promise.delay(100);
|
|
|
|
|
// Should select attachment
|
|
|
|
|
assert.equal(ZoteroPane.getSelectedItems(true)[0], attachment.id);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should open attachment on double-clicking attachments pane preview", async function () {
|
|
|
|
|
let itemDetails = ZoteroPane.itemPane._itemDetails;
|
|
|
|
|
let attachmentsBox = itemDetails.getPane(paneID);
|
|
|
|
|
let preview = attachmentsBox._preview;
|
|
|
|
|
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
let attachment = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await ZoteroPane.selectItem(item.id);
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
await waitForPreviewBoxRender(attachmentsBox);
|
|
|
|
|
|
|
|
|
|
let event = new MouseEvent('dblclick', {
|
|
|
|
|
bubbles: true,
|
|
|
|
|
cancelable: true,
|
|
|
|
|
view: window
|
|
|
|
|
});
|
|
|
|
|
preview.dispatchEvent(event);
|
|
|
|
|
await Zotero.Promise.delay(100);
|
|
|
|
|
let reader = await Zotero.Reader.getByTabID(Zotero_Tabs.selectedID);
|
|
|
|
|
// Should open attachment
|
|
|
|
|
assert.equal(reader.itemID, attachment.id);
|
|
|
|
|
});
|
|
|
|
|
});
|
2015-05-19 21:05:58 +00:00
|
|
|
|
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
describe("Notes pane", function () {
|
|
|
|
|
it("should refresh on child note change", function* () {
|
|
|
|
|
var item;
|
|
|
|
|
var note1;
|
|
|
|
|
var note2;
|
2020-07-05 10:20:01 +00:00
|
|
|
|
yield Zotero.DB.executeTransaction(async function () {
|
2017-03-01 06:35:15 +00:00
|
|
|
|
item = createUnsavedDataObject('item');
|
2020-07-05 10:20:01 +00:00
|
|
|
|
await item.save();
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
note1 = new Zotero.Item('note');
|
|
|
|
|
note1.parentID = item.id;
|
|
|
|
|
note1.setNote('A');
|
2020-07-05 10:20:01 +00:00
|
|
|
|
await note1.save();
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
note2 = new Zotero.Item('note');
|
|
|
|
|
note2.parentID = item.id;
|
|
|
|
|
note2.setNote('B');
|
2020-07-05 10:20:01 +00:00
|
|
|
|
await note2.save();
|
2017-03-01 06:35:15 +00:00
|
|
|
|
});
|
|
|
|
|
|
2024-01-16 19:37:29 +00:00
|
|
|
|
var body = doc.querySelector('#zotero-editpane-notes .body');
|
2017-03-01 06:35:15 +00:00
|
|
|
|
// Wait for note list to update
|
|
|
|
|
do {
|
|
|
|
|
yield Zotero.Promise.delay(1);
|
|
|
|
|
}
|
2024-01-16 19:37:29 +00:00
|
|
|
|
while (body.querySelectorAll('.row .label').length !== 2);
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
// Update note text
|
|
|
|
|
note2.setNote('C');
|
|
|
|
|
yield note2.saveTx();
|
|
|
|
|
|
|
|
|
|
// Wait for note list to update
|
|
|
|
|
do {
|
|
|
|
|
yield Zotero.Promise.delay(1);
|
|
|
|
|
}
|
2024-01-16 19:37:29 +00:00
|
|
|
|
while ([...body.querySelectorAll('.row .label')].every(label => label.textContent != 'C'));
|
2017-03-01 06:35:15 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should refresh on child note trash", function* () {
|
|
|
|
|
var item;
|
|
|
|
|
var note1;
|
|
|
|
|
var note2;
|
2020-07-05 10:20:01 +00:00
|
|
|
|
yield Zotero.DB.executeTransaction(async function () {
|
2017-03-01 06:35:15 +00:00
|
|
|
|
item = createUnsavedDataObject('item');
|
2020-07-05 10:20:01 +00:00
|
|
|
|
await item.save();
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
note1 = new Zotero.Item('note');
|
|
|
|
|
note1.parentID = item.id;
|
|
|
|
|
note1.setNote('A');
|
2020-07-05 10:20:01 +00:00
|
|
|
|
await note1.save();
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
note2 = new Zotero.Item('note');
|
|
|
|
|
note2.parentID = item.id;
|
|
|
|
|
note2.setNote('B');
|
2020-07-05 10:20:01 +00:00
|
|
|
|
await note2.save();
|
2017-03-01 06:35:15 +00:00
|
|
|
|
});
|
2024-01-16 19:37:29 +00:00
|
|
|
|
|
|
|
|
|
var body = doc.querySelector('#zotero-editpane-notes .body');
|
2017-03-01 06:35:15 +00:00
|
|
|
|
// Wait for note list to update
|
|
|
|
|
do {
|
|
|
|
|
yield Zotero.Promise.delay(1);
|
|
|
|
|
}
|
2024-01-16 19:37:29 +00:00
|
|
|
|
while (body.querySelectorAll('.row .label').length !== 2);
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
// Click "-" in first note
|
|
|
|
|
var promise = waitForDialog();
|
2024-01-16 19:37:29 +00:00
|
|
|
|
body.querySelector(".zotero-clicky-minus").click();
|
2017-03-01 06:35:15 +00:00
|
|
|
|
yield promise;
|
|
|
|
|
|
|
|
|
|
// Wait for note list to update
|
|
|
|
|
do {
|
|
|
|
|
yield Zotero.Promise.delay(1);
|
|
|
|
|
}
|
2024-01-16 19:37:29 +00:00
|
|
|
|
while (body.querySelectorAll('.row .label').length !== 1);
|
2017-03-01 06:35:15 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should refresh on child note delete", function* () {
|
|
|
|
|
var item;
|
|
|
|
|
var note1;
|
|
|
|
|
var note2;
|
2020-07-05 10:20:01 +00:00
|
|
|
|
yield Zotero.DB.executeTransaction(async function () {
|
2017-03-01 06:35:15 +00:00
|
|
|
|
item = createUnsavedDataObject('item');
|
2020-07-05 10:20:01 +00:00
|
|
|
|
await item.save();
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
note1 = new Zotero.Item('note');
|
|
|
|
|
note1.parentID = item.id;
|
|
|
|
|
note1.setNote('A');
|
2020-07-05 10:20:01 +00:00
|
|
|
|
await note1.save();
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
note2 = new Zotero.Item('note');
|
|
|
|
|
note2.parentID = item.id;
|
|
|
|
|
note2.setNote('B');
|
2020-07-05 10:20:01 +00:00
|
|
|
|
await note2.save();
|
2017-03-01 06:35:15 +00:00
|
|
|
|
});
|
|
|
|
|
|
2024-01-16 19:37:29 +00:00
|
|
|
|
var body = doc.querySelector('#zotero-editpane-notes .body');
|
2017-03-01 06:35:15 +00:00
|
|
|
|
// Wait for note list to update
|
|
|
|
|
do {
|
|
|
|
|
yield Zotero.Promise.delay(1);
|
|
|
|
|
}
|
2024-01-16 19:37:29 +00:00
|
|
|
|
while (body.querySelectorAll('.row .label').length !== 2);
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
yield note2.eraseTx();
|
|
|
|
|
|
|
|
|
|
// Wait for note list to update
|
|
|
|
|
do {
|
|
|
|
|
yield Zotero.Promise.delay(1);
|
|
|
|
|
}
|
2024-01-16 19:37:29 +00:00
|
|
|
|
while (body.querySelectorAll('.row .label').length !== 1);
|
2017-03-01 06:35:15 +00:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2015-08-07 19:36:46 +00:00
|
|
|
|
describe("Attachment pane", function () {
|
2024-04-22 01:15:22 +00:00
|
|
|
|
let paneID = "attachment-info";
|
|
|
|
|
|
|
|
|
|
beforeEach(function () {
|
|
|
|
|
Zotero.Prefs.set("panes.attachment-info.open", true);
|
|
|
|
|
Zotero.Prefs.set("showAttachmentPreview", true);
|
|
|
|
|
Zotero_Tabs.select("zotero-pane");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
afterEach(function () {
|
|
|
|
|
Zotero_Tabs.select("zotero-pane");
|
|
|
|
|
});
|
|
|
|
|
|
2024-01-18 04:44:29 +00:00
|
|
|
|
it("should refresh on file rename", async function () {
|
|
|
|
|
let file = getTestDataDirectory();
|
2015-08-07 19:36:46 +00:00
|
|
|
|
file.append('test.png');
|
2024-01-18 04:44:29 +00:00
|
|
|
|
let item = await Zotero.Attachments.importFromFile({
|
2015-08-07 19:36:46 +00:00
|
|
|
|
file: file
|
|
|
|
|
});
|
2024-01-18 04:44:29 +00:00
|
|
|
|
let newName = 'test2.png';
|
|
|
|
|
|
|
|
|
|
let itemBox = doc.getElementById('zotero-attachment-box');
|
|
|
|
|
let label = itemBox._id('fileName');
|
|
|
|
|
let promise = waitForDOMAttributes(label, 'value', (newValue) => {
|
|
|
|
|
return newValue === newName;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await item.renameAttachmentFile(newName);
|
2015-08-07 19:36:46 +00:00
|
|
|
|
|
2024-01-18 04:44:29 +00:00
|
|
|
|
await promise;
|
2015-08-07 19:36:46 +00:00
|
|
|
|
assert.equal(label.value, newName);
|
2024-01-18 04:44:29 +00:00
|
|
|
|
});
|
2021-05-31 07:25:23 +00:00
|
|
|
|
|
|
|
|
|
it("should update on attachment title change", async function () {
|
2024-01-18 04:44:29 +00:00
|
|
|
|
let file = getTestDataDirectory();
|
2021-05-31 07:25:23 +00:00
|
|
|
|
file.append('test.png');
|
2024-01-18 04:44:29 +00:00
|
|
|
|
let item = await Zotero.Attachments.importFromFile({ file });
|
|
|
|
|
let newTitle = 'New Title';
|
|
|
|
|
|
|
|
|
|
let paneHeader = doc.getElementById('zotero-item-pane-header');
|
|
|
|
|
let label = paneHeader.titleField;
|
|
|
|
|
let promise = waitForDOMAttributes(label, 'value', (newValue) => {
|
|
|
|
|
return newValue === newTitle;
|
|
|
|
|
});
|
|
|
|
|
|
2021-05-31 07:25:23 +00:00
|
|
|
|
item.setField('title', newTitle);
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
|
2024-01-18 04:44:29 +00:00
|
|
|
|
await promise;
|
|
|
|
|
assert.equal(label.value, newTitle);
|
|
|
|
|
});
|
2024-04-22 01:15:22 +00:00
|
|
|
|
|
|
|
|
|
it("should show attachment pane in library for attachment item", async function () {
|
|
|
|
|
// Regular item: hide
|
|
|
|
|
let itemDetails = ZoteroPane.itemPane._itemDetails;
|
|
|
|
|
let box = itemDetails.getPane(paneID);
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
await ZoteroPane.selectItem(item.id);
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
assert.isTrue(box.hidden);
|
|
|
|
|
|
|
|
|
|
// Child attachment: show
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
let attachment = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
await ZoteroPane.selectItem(attachment.id);
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
await waitForPreviewBoxReader(box, attachment.id);
|
|
|
|
|
assert.isFalse(box.hidden);
|
|
|
|
|
await Zotero.Promise.delay(100);
|
|
|
|
|
assert.isTrue(isPreviewDisplayed(box));
|
|
|
|
|
|
|
|
|
|
// Standalone attachment: show
|
|
|
|
|
let attachment1 = await importFileAttachment('test.pdf');
|
|
|
|
|
await ZoteroPane.selectItem(attachment1.id);
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
await waitForPreviewBoxReader(box, attachment1.id);
|
|
|
|
|
assert.isFalse(box.hidden);
|
|
|
|
|
await Zotero.Promise.delay(100);
|
|
|
|
|
assert.isTrue(isPreviewDisplayed(box));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should show attachment pane without preview in reader for standalone attachment item", async function () {
|
|
|
|
|
// Attachment item with parent item: hide
|
|
|
|
|
let item = new Zotero.Item('book');
|
|
|
|
|
let file = getTestDataDirectory();
|
|
|
|
|
file.append('test.pdf');
|
|
|
|
|
await item.saveTx();
|
|
|
|
|
let attachment = await Zotero.Attachments.importFromFile({
|
|
|
|
|
file,
|
|
|
|
|
parentItemID: item.id
|
|
|
|
|
});
|
|
|
|
|
await ZoteroPane.viewItems([attachment]);
|
|
|
|
|
let tabID = Zotero_Tabs.selectedID;
|
|
|
|
|
let itemDetails = ZoteroContextPane.context._getItemContext(tabID);
|
|
|
|
|
let box = itemDetails.getPane(paneID);
|
|
|
|
|
assert.isTrue(box.hidden);
|
|
|
|
|
|
|
|
|
|
// Standalone attachment item: show
|
|
|
|
|
attachment = await importFileAttachment('test.pdf');
|
|
|
|
|
await ZoteroPane.viewItems([attachment]);
|
|
|
|
|
tabID = Zotero_Tabs.selectedID;
|
|
|
|
|
itemDetails = ZoteroContextPane.context._getItemContext(tabID);
|
|
|
|
|
box = itemDetails.getPane(paneID);
|
|
|
|
|
assert.isFalse(box.hidden);
|
|
|
|
|
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
// No preview
|
|
|
|
|
assert.isFalse(isPreviewDisplayed(box));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should only show attachment note container when exists", async function () {
|
|
|
|
|
let itemDetails = ZoteroPane.itemPane._itemDetails;
|
|
|
|
|
let box = itemDetails.getPane(paneID);
|
|
|
|
|
let noteContainer = box._id("note-container");
|
|
|
|
|
let noteEditor = box._id('attachment-note-editor');
|
|
|
|
|
|
|
|
|
|
// Hide note container by default
|
|
|
|
|
let attachment = await importFileAttachment('test.pdf');
|
|
|
|
|
await ZoteroPane.selectItem(attachment.id);
|
|
|
|
|
await itemDetails._renderPromise;
|
|
|
|
|
await waitForScrollToPane(itemDetails, paneID);
|
|
|
|
|
await waitForPreviewBoxRender(box);
|
|
|
|
|
assert.isTrue(noteContainer.hidden);
|
|
|
|
|
|
|
|
|
|
// Add attachment note
|
|
|
|
|
let itemModifyPromise = waitForItemEvent("modify");
|
|
|
|
|
attachment.setNote("<h1>TEST</h1>");
|
|
|
|
|
await attachment.saveTx();
|
|
|
|
|
await itemModifyPromise;
|
|
|
|
|
await waitForPreviewBoxRender(box);
|
|
|
|
|
// Should show note container
|
|
|
|
|
assert.isFalse(noteContainer.hidden);
|
|
|
|
|
// Should be readonly
|
|
|
|
|
assert.equal(noteEditor.mode, "view");
|
|
|
|
|
});
|
2024-01-18 04:44:29 +00:00
|
|
|
|
});
|
2015-08-07 19:36:46 +00:00
|
|
|
|
|
2017-03-01 06:35:15 +00:00
|
|
|
|
|
|
|
|
|
describe("Note editor", function () {
|
2015-05-19 21:05:58 +00:00
|
|
|
|
it("should refresh on note update", function* () {
|
|
|
|
|
var item = new Zotero.Item('note');
|
|
|
|
|
var id = yield item.saveTx();
|
|
|
|
|
|
2017-08-30 22:22:00 +00:00
|
|
|
|
var noteEditor = doc.getElementById('zotero-note-editor');
|
|
|
|
|
|
2015-05-19 21:05:58 +00:00
|
|
|
|
// Wait for the editor
|
2017-08-30 22:22:00 +00:00
|
|
|
|
yield new Zotero.Promise((resolve, reject) => {
|
2021-01-13 12:01:44 +00:00
|
|
|
|
noteEditor.onInit(() => resolve());
|
|
|
|
|
});
|
|
|
|
|
assert.equal(noteEditor._editorInstance._iframeWindow.wrappedJSObject.getDataSync(), null);
|
2015-05-19 21:05:58 +00:00
|
|
|
|
item.setNote('<p>Test</p>');
|
|
|
|
|
yield item.saveTx();
|
|
|
|
|
|
2021-01-13 12:01:44 +00:00
|
|
|
|
// Wait for asynchronous editor update
|
|
|
|
|
do {
|
|
|
|
|
yield Zotero.Promise.delay(10);
|
2022-07-25 15:04:00 +00:00
|
|
|
|
} while (
|
|
|
|
|
!/<div data-schema-version=".*"><p>Test<\/p><\/div>/.test(
|
|
|
|
|
noteEditor._editorInstance._iframeWindow.wrappedJSObject.getDataSync().html.replace(/\n/g, '')
|
|
|
|
|
)
|
|
|
|
|
);
|
2021-01-13 12:01:44 +00:00
|
|
|
|
});
|
|
|
|
|
});
|
2016-03-25 04:49:14 +00:00
|
|
|
|
|
|
|
|
|
describe("Feed buttons", function() {
|
|
|
|
|
describe("Mark as Read/Unread", function() {
|
2017-11-03 08:47:04 +00:00
|
|
|
|
it("should update label when state of an item changes", function* () {
|
2016-03-25 04:49:14 +00:00
|
|
|
|
let feed = yield createFeed();
|
|
|
|
|
yield selectLibrary(win, feed.libraryID);
|
2017-11-03 08:47:04 +00:00
|
|
|
|
yield waitForItemsLoad(win);
|
|
|
|
|
|
|
|
|
|
var stub = sinon.stub(win.ZoteroPane, 'startItemReadTimeout');
|
|
|
|
|
var item = yield createDataObject('feedItem', { libraryID: feed.libraryID });
|
|
|
|
|
// Skip timed mark-as-read
|
|
|
|
|
assert.ok(stub.called);
|
|
|
|
|
stub.restore();
|
|
|
|
|
item.isRead = true;
|
|
|
|
|
yield item.saveTx();
|
|
|
|
|
|
2016-03-25 04:49:14 +00:00
|
|
|
|
let button = doc.getElementById('zotero-feed-item-toggleRead-button');
|
|
|
|
|
|
2024-01-30 10:43:16 +00:00
|
|
|
|
assert.equal(button.label, Zotero.getString('pane.item.markAsUnread'));
|
2016-03-25 04:49:14 +00:00
|
|
|
|
yield item.toggleRead(false);
|
2024-01-30 10:43:16 +00:00
|
|
|
|
// Button is re-created
|
|
|
|
|
button = doc.getElementById('zotero-feed-item-toggleRead-button');
|
|
|
|
|
assert.equal(button.label, Zotero.getString('pane.item.markAsRead'));
|
2016-03-25 04:49:14 +00:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
2020-06-06 21:16:09 +00:00
|
|
|
|
|
|
|
|
|
describe("Duplicates Merge pane", function () {
|
|
|
|
|
// Same as test in itemsTest, but via UI, which makes a copy via toJSON()/fromJSON()
|
|
|
|
|
it("should transfer merge-tracking relations when merging two pairs into one item", async function () {
|
|
|
|
|
var item1 = await createDataObject('item', { title: 'A' });
|
|
|
|
|
var item2 = await createDataObject('item', { title: 'B' });
|
|
|
|
|
var item3 = await createDataObject('item', { title: 'C' });
|
|
|
|
|
var item4 = await createDataObject('item', { title: 'D' });
|
|
|
|
|
|
|
|
|
|
var uris = [item2, item3, item4].map(item => Zotero.URI.getItemURI(item));
|
|
|
|
|
|
|
|
|
|
var p;
|
|
|
|
|
|
|
|
|
|
var zp = win.ZoteroPane;
|
|
|
|
|
await zp.selectItems([item1.id, item2.id]);
|
|
|
|
|
zp.mergeSelectedItems();
|
|
|
|
|
p = waitForItemEvent('modify');
|
|
|
|
|
doc.getElementById('zotero-duplicates-merge-button').click();
|
|
|
|
|
await p;
|
|
|
|
|
|
|
|
|
|
assert.sameMembers(
|
|
|
|
|
item1.getRelations()[Zotero.Relations.replacedItemPredicate],
|
|
|
|
|
[uris[0]]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await zp.selectItems([item3.id, item4.id]);
|
|
|
|
|
zp.mergeSelectedItems();
|
|
|
|
|
p = waitForItemEvent('modify');
|
|
|
|
|
doc.getElementById('zotero-duplicates-merge-button').click();
|
|
|
|
|
await p;
|
|
|
|
|
|
|
|
|
|
assert.sameMembers(
|
|
|
|
|
item3.getRelations()[Zotero.Relations.replacedItemPredicate],
|
|
|
|
|
[uris[2]]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await zp.selectItems([item1.id, item3.id]);
|
|
|
|
|
zp.mergeSelectedItems();
|
|
|
|
|
p = waitForItemEvent('modify');
|
|
|
|
|
doc.getElementById('zotero-duplicates-merge-button').click();
|
|
|
|
|
await p;
|
|
|
|
|
|
|
|
|
|
// Remaining item should include all other URIs
|
|
|
|
|
assert.sameMembers(
|
|
|
|
|
item1.getRelations()[Zotero.Relations.replacedItemPredicate],
|
|
|
|
|
uris
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
});
|
2024-04-22 01:15:22 +00:00
|
|
|
|
});
|