diff --git a/chrome/content/zotero/itemPane.js b/chrome/content/zotero/itemPane.js index eb7a599b5f..b1f01bafe7 100644 --- a/chrome/content/zotero/itemPane.js +++ b/chrome/content/zotero/itemPane.js @@ -26,6 +26,7 @@ var ZoteroItemPane = new function() { var _lastItem, _itemBox, _notesLabel, _notesButton, _notesList, _tagsBox, _relatedBox; var _translationTarget; + var _noteIDs; this.onLoad = function () { if (!Zotero) { @@ -45,9 +46,16 @@ var ZoteroItemPane = new function() { _notesList = document.getElementById('zotero-editpane-dynamic-notes'); _tagsBox = document.getElementById('zotero-editpane-tags'); _relatedBox = document.getElementById('zotero-editpane-related'); + + this._unregisterID = Zotero.Notifier.registerObserver(this, ['item'], 'itemPane'); } + this.onUnload = function () { + Zotero.Notifier.unregisterObserver(this._unregisterID); + }, + + /* * Load a top-level item */ @@ -125,6 +133,7 @@ var ZoteroItemPane = new function() { _notesList.removeChild(_notesList.firstChild); } + _noteIDs = new Set(); let notes = yield Zotero.Items.getAsync(item.getNotes()); if (notes.length) { for (var i = 0; i < notes.length; i++) { @@ -163,6 +172,7 @@ var ZoteroItemPane = new function() { } _notesList.appendChild(row); + _noteIDs.add(id); } } @@ -185,6 +195,21 @@ var ZoteroItemPane = new function() { }); + this.notify = Zotero.Promise.coroutine(function* (action, type, ids, extraData) { + var viewBox = document.getElementById('zotero-view-item'); + // If notes pane is selected, refresh it if any of the notes change or are deleted + if (viewBox.selectedIndex == 1 && (action == 'modify' || action == 'delete')) { + let refresh = false; + if (ids.some(id => _noteIDs.has(id))) { + refresh = true; + } + if (refresh) { + yield this.viewItem(_lastItem, null, 1); + } + } + }); + + this.blurOpenField = Zotero.Promise.coroutine(function* () { var tabBox = document.getElementById('zotero-view-tabbox'); switch (tabBox.selectedIndex) { @@ -346,3 +371,4 @@ var ZoteroItemPane = new function() { } addEventListener("load", function(e) { ZoteroItemPane.onLoad(e); }, false); +addEventListener("unload", function(e) { ZoteroItemPane.onUnload(e); }, false); diff --git a/chrome/content/zotero/xpcom/data/items.js b/chrome/content/zotero/xpcom/data/items.js index e70f463e95..2c1b48dd0c 100644 --- a/chrome/content/zotero/xpcom/data/items.js +++ b/chrome/content/zotero/xpcom/data/items.js @@ -876,6 +876,7 @@ Zotero.Items = function() { let parentItem = yield Zotero.Items.getAsync(parentItemID); yield parentItem.reload(['primaryData', 'childItems'], true); } + Zotero.Notifier.queue('modify', 'item', ids); 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 491174f0d3..f9e6534bd6 100644 --- a/test/tests/itemPaneTest.js +++ b/test/tests/itemPaneTest.js @@ -112,6 +112,129 @@ describe("Item pane", function () { }); }) + + describe("Notes pane", function () { + it("should refresh on child note change", function* () { + var item; + var note1; + var note2; + yield Zotero.DB.executeTransaction(function* () { + item = createUnsavedDataObject('item'); + yield item.save(); + + note1 = new Zotero.Item('note'); + note1.parentID = item.id; + note1.setNote('A'); + yield note1.save(); + + note2 = new Zotero.Item('note'); + note2.parentID = item.id; + note2.setNote('B'); + yield note2.save(); + }); + + var tabs = doc.getElementById('zotero-editpane-tabs'); + var notesTab = doc.getElementById('zotero-editpane-notes-tab'); + var noteRows = doc.getElementById('zotero-editpane-dynamic-notes'); + tabs.selectedItem = notesTab; + // Wait for note list to update + do { + yield Zotero.Promise.delay(1); + } + while (noteRows.childNodes.length !== 2); + + // Update note text + note2.setNote('C'); + yield note2.saveTx(); + + // Wait for note list to update + do { + yield Zotero.Promise.delay(1); + } + while (Array.from(noteRows.querySelectorAll('label.zotero-box-label')).every(label => label.value != 'C')); + }); + + it("should refresh on child note trash", function* () { + var item; + var note1; + var note2; + yield Zotero.DB.executeTransaction(function* () { + item = createUnsavedDataObject('item'); + yield item.save(); + + note1 = new Zotero.Item('note'); + note1.parentID = item.id; + note1.setNote('A'); + yield note1.save(); + + note2 = new Zotero.Item('note'); + note2.parentID = item.id; + note2.setNote('B'); + yield note2.save(); + }); + + var tabs = doc.getElementById('zotero-editpane-tabs'); + var notesTab = doc.getElementById('zotero-editpane-notes-tab'); + var noteRows = doc.getElementById('zotero-editpane-dynamic-notes'); + tabs.selectedItem = notesTab; + // Wait for note list to update + do { + yield Zotero.Promise.delay(1); + } + while (noteRows.childNodes.length !== 2); + + // Click "-" in first note + var promise = waitForDialog(); + noteRows.childNodes[0].lastChild.click(); + yield promise; + + // Wait for note list to update + do { + yield Zotero.Promise.delay(1); + } + while (noteRows.childNodes.length !== 1); + }); + + it("should refresh on child note delete", function* () { + var item; + var note1; + var note2; + yield Zotero.DB.executeTransaction(function* () { + item = createUnsavedDataObject('item'); + yield item.save(); + + note1 = new Zotero.Item('note'); + note1.parentID = item.id; + note1.setNote('A'); + yield note1.save(); + + note2 = new Zotero.Item('note'); + note2.parentID = item.id; + note2.setNote('B'); + yield note2.save(); + }); + + var tabs = doc.getElementById('zotero-editpane-tabs'); + var notesTab = doc.getElementById('zotero-editpane-notes-tab'); + var noteRows = doc.getElementById('zotero-editpane-dynamic-notes'); + tabs.selectedItem = notesTab; + // Wait for note list to update + do { + yield Zotero.Promise.delay(1); + } + while (noteRows.childNodes.length !== 2); + + yield note2.eraseTx(); + + // Wait for note list to update + do { + yield Zotero.Promise.delay(1); + } + while (noteRows.childNodes.length !== 1); + }); + }); + + describe("Attachment pane", function () { it("should refresh on file rename", function* () { var file = getTestDataDirectory(); @@ -128,7 +251,8 @@ describe("Item pane", function () { }) }) - describe("Note pane", function () { + + describe("Note editor", function () { it("should refresh on note update", function* () { var item = new Zotero.Item('note'); var id = yield item.saveTx(); @@ -151,55 +275,6 @@ 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() {