Mark trashed items as unsynced and update parents (including note list)
Regression from 3a0e0cb088
This commit is contained in:
parent
41538ebca6
commit
3830aa1125
5 changed files with 86 additions and 5 deletions
|
@ -1775,6 +1775,7 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
||||||
// Update child item counts and contents
|
// Update child item counts and contents
|
||||||
if (reloadParentChildItems) {
|
if (reloadParentChildItems) {
|
||||||
for (let parentItemID in reloadParentChildItems) {
|
for (let parentItemID in reloadParentChildItems) {
|
||||||
|
// Keep in sync with Zotero.Items.trash()
|
||||||
let parentItem = yield this.ObjectsClass.getAsync(parentItemID);
|
let parentItem = yield this.ObjectsClass.getAsync(parentItemID);
|
||||||
yield parentItem.reload(['primaryData', 'childItems'], true);
|
yield parentItem.reload(['primaryData', 'childItems'], true);
|
||||||
parentItem.clearBestAttachmentState();
|
parentItem.clearBestAttachmentState();
|
||||||
|
|
|
@ -852,12 +852,17 @@ Zotero.Items = function() {
|
||||||
libraryIDs.add(item.libraryID);
|
libraryIDs.add(item.libraryID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var parentItemIDs = new Set();
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
item.setDeleted(true);
|
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.Utilities.Internal.forEachChunkAsync(ids, 250, Zotero.Promise.coroutine(function* (chunk) {
|
||||||
yield Zotero.DB.queryAsync(
|
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(", ")})`
|
+ `WHERE itemID IN (${chunk.map(id => parseInt(id)).join(", ")})`
|
||||||
);
|
);
|
||||||
yield Zotero.DB.queryAsync(
|
yield Zotero.DB.queryAsync(
|
||||||
|
@ -866,6 +871,11 @@ Zotero.Items = function() {
|
||||||
);
|
);
|
||||||
}.bind(this)));
|
}.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);
|
Zotero.Notifier.queue('trash', 'item', ids);
|
||||||
Array.from(libraryIDs).forEach(libraryID => {
|
Array.from(libraryIDs).forEach(libraryID => {
|
||||||
Zotero.Notifier.queue('refresh', 'trash', libraryID);
|
Zotero.Notifier.queue('refresh', 'trash', libraryID);
|
||||||
|
|
|
@ -151,6 +151,55 @@ describe("Item pane", function () {
|
||||||
|
|
||||||
assert.equal(noteBox.noteField.value, '<p>Test</p>');
|
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() {
|
describe("Feed buttons", function() {
|
||||||
|
|
|
@ -301,6 +301,8 @@ describe("Zotero.Item", function () {
|
||||||
it("should be set to true after save", function* () {
|
it("should be set to true after save", function* () {
|
||||||
var item = yield createDataObject('item');
|
var item = yield createDataObject('item');
|
||||||
item.deleted = true;
|
item.deleted = true;
|
||||||
|
// Sanity check for itemsTest#trash()
|
||||||
|
assert.isTrue(item._changed.deleted);
|
||||||
yield item.saveTx();
|
yield item.saveTx();
|
||||||
assert.ok(item.deleted);
|
assert.ok(item.deleted);
|
||||||
})
|
})
|
||||||
|
|
|
@ -92,19 +92,38 @@ describe("Zotero.Items", function () {
|
||||||
it("should send items to the trash", function* () {
|
it("should send items to the trash", function* () {
|
||||||
var items = [];
|
var items = [];
|
||||||
items.push(
|
items.push(
|
||||||
(yield createDataObject('item')),
|
(yield createDataObject('item', { synced: true })),
|
||||||
(yield createDataObject('item')),
|
(yield createDataObject('item', { synced: true })),
|
||||||
(yield createDataObject('item'))
|
(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);
|
var ids = items.map(item => item.id);
|
||||||
yield Zotero.Items.trashTx(ids);
|
yield Zotero.Items.trashTx(ids);
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
assert.isTrue(item.deleted);
|
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(
|
assert.equal((yield Zotero.DB.valueQueryAsync(
|
||||||
`SELECT COUNT(*) FROM deletedItems WHERE itemID IN (${ids})`
|
`SELECT COUNT(*) FROM deletedItems WHERE itemID IN (${ids})`
|
||||||
)), 3);
|
)), 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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue