commit 3830aa11252562dd42e5722241cb5fb805193bfa
parent 41538ebca6233eaadc2892da1fed437011909ffc
Author: Dan Stillman <dstillman@zotero.org>
Date: Wed, 15 Feb 2017 13:15:30 -0500
Mark trashed items as unsynced and update parents (including note list)
Regression from 3a0e0cb0886
Diffstat:
5 files changed, 86 insertions(+), 5 deletions(-)
diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js
@@ -1775,6 +1775,7 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
// Update child item counts and contents
if (reloadParentChildItems) {
for (let parentItemID in reloadParentChildItems) {
+ // Keep in sync with Zotero.Items.trash()
let parentItem = yield this.ObjectsClass.getAsync(parentItemID);
yield parentItem.reload(['primaryData', 'childItems'], true);
parentItem.clearBestAttachmentState();
diff --git a/chrome/content/zotero/xpcom/data/items.js b/chrome/content/zotero/xpcom/data/items.js
@@ -852,12 +852,17 @@ Zotero.Items = function() {
libraryIDs.add(item.libraryID);
}
+ var parentItemIDs = new Set();
items.forEach(item => {
item.setDeleted(true);
+ item.synced = false;
+ if (item.parentItemID) {
+ parentItemIDs.add(item.parentItemID);
+ }
});
yield Zotero.Utilities.Internal.forEachChunkAsync(ids, 250, Zotero.Promise.coroutine(function* (chunk) {
yield Zotero.DB.queryAsync(
- "UPDATE items SET synced=1, clientDateModified=CURRENT_TIMESTAMP "
+ "UPDATE items SET synced=0, clientDateModified=CURRENT_TIMESTAMP "
+ `WHERE itemID IN (${chunk.map(id => parseInt(id)).join(", ")})`
);
yield Zotero.DB.queryAsync(
@@ -866,6 +871,11 @@ Zotero.Items = function() {
);
}.bind(this)));
+ // Keep in sync with Zotero.Item::saveData()
+ for (let parentItemID of parentItemIDs) {
+ let parentItem = yield Zotero.Items.getAsync(parentItemID);
+ yield parentItem.reload(['primaryData', 'childItems'], true);
+ }
Zotero.Notifier.queue('trash', 'item', ids);
Array.from(libraryIDs).forEach(libraryID => {
Zotero.Notifier.queue('refresh', 'trash', libraryID);
diff --git a/test/tests/itemPaneTest.js b/test/tests/itemPaneTest.js
@@ -151,6 +151,55 @@ describe("Item pane", function () {
assert.equal(noteBox.noteField.value, '<p>Test</p>');
})
+
+ it("should refresh on note trash", function* () {
+ var item = yield createDataObject('item');
+
+ var note = new Zotero.Item('note');
+ note.parentItemID = item.id;
+ yield note.saveTx();
+ yield itemsView.selectItem(note.id);
+
+ // Wait for the note editor, just to be polite
+ var noteBox = doc.getElementById('zotero-note-editor');
+ var val = false;
+ do {
+ try {
+ val = noteBox.noteField.value;
+ }
+ catch (e) {}
+ yield Zotero.Promise.delay(1);
+ }
+ while (val === false)
+
+ // Select parent and make sure there's 1 note
+ yield itemsView.selectItem(item.id);
+ var tabs = doc.getElementById('zotero-editpane-tabs');
+ var infoTab = doc.getElementById('zotero-editpane-info-tab');
+ var notesTab = doc.getElementById('zotero-editpane-notes-tab');
+ var notesList = doc.getElementById('zotero-editpane-dynamic-notes');
+ tabs.selectedItem = notesTab;
+ // Wait for note list to update
+ do {
+ yield Zotero.Promise.delay(1);
+ }
+ while (notesList.childNodes.length !== 1);
+ tabs.selectedItem = infoTab;
+
+ // Select child and trash it
+ yield itemsView.selectItem(note.id);
+ yield Zotero.Items.trashTx([note.id]);
+
+ // Select parent and select notes pane
+ yield itemsView.selectItem(item.id);
+ tabs.selectedItem = notesTab;
+ // Wait for note list to update
+ var len = false;
+ do {
+ yield Zotero.Promise.delay(1);
+ }
+ while (notesList.childNodes.length !== 0);
+ })
})
describe("Feed buttons", function() {
diff --git a/test/tests/itemTest.js b/test/tests/itemTest.js
@@ -301,6 +301,8 @@ describe("Zotero.Item", function () {
it("should be set to true after save", function* () {
var item = yield createDataObject('item');
item.deleted = true;
+ // Sanity check for itemsTest#trash()
+ assert.isTrue(item._changed.deleted);
yield item.saveTx();
assert.ok(item.deleted);
})
diff --git a/test/tests/itemsTest.js b/test/tests/itemsTest.js
@@ -92,19 +92,38 @@ describe("Zotero.Items", function () {
it("should send items to the trash", function* () {
var items = [];
items.push(
- (yield createDataObject('item')),
- (yield createDataObject('item')),
- (yield createDataObject('item'))
+ (yield createDataObject('item', { synced: true })),
+ (yield createDataObject('item', { synced: true })),
+ (yield createDataObject('item', { synced: true }))
);
+ items.forEach(item => {
+ // Sanity-checked as true in itemTest#deleted
+ assert.isUndefined(item._changed.deleted);
+ });
var ids = items.map(item => item.id);
yield Zotero.Items.trashTx(ids);
items.forEach(item => {
assert.isTrue(item.deleted);
- assert.isFalse(item.hasChanged());
+ // Item should be saved (can't use hasChanged() because that includes .synced)
+ assert.isUndefined(item._changed.deleted);
+ assert.isFalse(item.synced);
});
assert.equal((yield Zotero.DB.valueQueryAsync(
`SELECT COUNT(*) FROM deletedItems WHERE itemID IN (${ids})`
)), 3);
+ for (let item of items) {
+ assert.equal((yield Zotero.DB.valueQueryAsync(
+ `SELECT synced FROM items WHERE itemID=${item.id}`
+ )), 0);
+ }
+ });
+
+ it("should update parent item when trashing child item", function* () {
+ var item = yield createDataObject('item');
+ var note = yield createDataObject('item', { itemType: 'note', parentID: item.id });
+ assert.lengthOf(item.getNotes(), 1);
+ yield Zotero.Items.trashTx([note.id]);
+ assert.lengthOf(item.getNotes(), 0);
});
});