From 3830aa11252562dd42e5722241cb5fb805193bfa Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Wed, 15 Feb 2017 13:15:30 -0500 Subject: [PATCH] Mark trashed items as unsynced and update parents (including note list) Regression from 3a0e0cb0886 --- chrome/content/zotero/xpcom/data/item.js | 1 + chrome/content/zotero/xpcom/data/items.js | 12 +++++- test/tests/itemPaneTest.js | 49 +++++++++++++++++++++++ test/tests/itemTest.js | 2 + test/tests/itemsTest.js | 27 +++++++++++-- 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 index 8ab56825e1..2543fc3e76 100644 --- 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 index 3e57e79ae1..94b6831dd6 100644 --- 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 index 1528e8668e..491174f0d3 100644 --- a/test/tests/itemPaneTest.js +++ b/test/tests/itemPaneTest.js @@ -151,6 +151,55 @@ describe("Item pane", function () { assert.equal(noteBox.noteField.value, '

Test

'); }) + + 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 index bc9c1293c0..063ae69fd7 100644 --- 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 index d558fdfa9f..2c2ecb3178 100644 --- 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); }); });