Don't show note in right-hand pane when editing in separate window

- When a child note is opened in a separate window, the parent window is
  selected. (This used to work but was broken in 5.0.)
- When a top-level note is opened (via double-click), the right-hand pane
  changes to show "Editing in separate window".
- If a note that's currently open in a separate window is clicked on,
  the right-hand pane shows "Editing in a separate window".
- If a note window is closed and the item is selected, the note editor
  reappears in the right-hand pane after the note is saved.

This will avoid unnecessary UI updates and data loss bugs from the two
notes getting out of sync (and is just generally cleaner).

Also:

- General cleanup of note display code
This commit is contained in:
Dan Stillman 2017-12-11 02:23:15 -05:00
parent b2c9a42103
commit dcfaa5521e
6 changed files with 126 additions and 83 deletions

View file

@ -222,6 +222,58 @@ var ZoteroItemPane = new function() {
}); });
this.onNoteSelected = function (item, editable) {
// If an external note window is open for this item, don't show the editor
if (ZoteroPane.findNoteWindow(item.id)) {
this.showNoteWindowMessage();
return;
}
var noteEditor = document.getElementById('zotero-note-editor');
noteEditor.mode = editable ? 'edit' : 'view';
noteEditor.parent = null;
noteEditor.item = item;
// If loading new or different note, disable undo while we repopulate the text field
// so Undo doesn't end up clearing the field. This also ensures that Undo doesn't
// undo content from another note into the current one.
var clearUndo = noteEditor.item ? noteEditor.item.id != item.id : false;
if (clearUndo) {
noteEditor.clearUndo();
}
document.getElementById('zotero-view-note-button').hidden = !editable;
document.getElementById('zotero-item-pane-content').selectedIndex = 2;
};
this.showNoteWindowMessage = function () {
ZoteroPane.setItemPaneMessage(Zotero.getString('pane.item.notes.editingInWindow'));
};
/**
* Select the parent item and open the note editor
*/
this.openNoteWindow = async function () {
var noteEditor = document.getElementById('zotero-note-editor');
var item = noteEditor.item;
// We don't want to show the note in two places, since it causes unnecessary UI updates
// and can result in weird bugs where note content gets lost.
//
// If this is a child note, select the parent
if (item.parentID) {
await ZoteroPane.selectItem(item.parentID);
}
// Otherwise, hide note and replace with a message that we're editing externally
else {
this.showNoteWindowMessage();
}
ZoteroPane.openNoteWindow(item.id);
};
this.addNote = function (popup) { this.addNote = function (popup) {
ZoteroPane_Local.newNote(popup, _lastItem.key); ZoteroPane_Local.newNote(popup, _lastItem.key);
} }

View file

@ -114,7 +114,9 @@
<zoteronoteeditor id="zotero-note-editor" flex="1" notitle="1" <zoteronoteeditor id="zotero-note-editor" flex="1" notitle="1"
previousfocus="zotero-items-tree" previousfocus="zotero-items-tree"
onerror="ZoteroPane.displayErrorMessage(); this.mode = 'view'"/> onerror="ZoteroPane.displayErrorMessage(); this.mode = 'view'"/>
<button id="zotero-view-note-button" label="&zotero.notes.separate;" oncommand="ZoteroPane_Local.openNoteWindow(this.getAttribute('noteID')); if(this.hasAttribute('sourceID')) ZoteroPane_Local.selectItem(this.getAttribute('sourceID'));"/> <button id="zotero-view-note-button"
label="&zotero.notes.separate;"
oncommand="ZoteroItemPane.openNoteWindow()"/>
</groupbox> </groupbox>
<!-- Attachment item --> <!-- Attachment item -->

View file

@ -26,7 +26,7 @@
var noteEditor; var noteEditor;
var notifierUnregisterID; var notifierUnregisterID;
function onLoad() { async function onLoad() {
noteEditor = document.getElementById('zotero-note-editor'); noteEditor = document.getElementById('zotero-note-editor');
noteEditor.mode = 'edit'; noteEditor.mode = 'edit';
noteEditor.focus(); noteEditor.focus();
@ -37,42 +37,41 @@ function onLoad() {
if (window.arguments) { if (window.arguments) {
var io = window.arguments[0]; var io = window.arguments[0];
} }
var itemID = parseInt(io.itemID); var itemID = parseInt(io.itemID);
var collectionID = parseInt(io.collectionID); var collectionID = parseInt(io.collectionID);
var parentItemKey = io.parentItemKey; var parentItemKey = io.parentItemKey;
return Zotero.spawn(function* () { if (itemID) {
if (itemID) { var ref = await Zotero.Items.getAsync(itemID);
var ref = yield Zotero.Items.getAsync(itemID);
var clearUndo = noteEditor.item ? noteEditor.item.id != ref.id : false;
var clearUndo = noteEditor.item ? noteEditor.item.id != ref.id : false;
noteEditor.item = ref;
noteEditor.item = ref;
// If loading new or different note, disable undo while we repopulate the text field
// If loading new or different note, disable undo while we repopulate the text field // so Undo doesn't end up clearing the field. This also ensures that Undo doesn't
// so Undo doesn't end up clearing the field. This also ensures that Undo doesn't // undo content from another note into the current one.
// undo content from another note into the current one. if (clearUndo) {
if (clearUndo) { noteEditor.clearUndo();
noteEditor.clearUndo();
}
document.title = ref.getNoteTitle();
}
else {
if (parentItemKey) {
var ref = Zotero.Items.getByLibraryAndKey(parentItemKey);
noteEditor.parentItem = ref;
}
else {
if (collectionID && collectionID != '' && collectionID != 'undefined') {
noteEditor.collection = Zotero.Collections.get(collectionID);
}
}
noteEditor.refresh();
} }
notifierUnregisterID = Zotero.Notifier.registerObserver(NotifyCallback, 'item'); document.title = ref.getNoteTitle();
}); }
else {
if (parentItemKey) {
var ref = Zotero.Items.getByLibraryAndKey(parentItemKey);
noteEditor.parentItem = ref;
}
else {
if (collectionID && collectionID != '' && collectionID != 'undefined') {
noteEditor.collection = Zotero.Collections.get(collectionID);
}
}
noteEditor.refresh();
}
notifierUnregisterID = Zotero.Notifier.registerObserver(NotifyCallback, 'item', 'noteWindow');
} }
// If there's an error saving a note, close the window and crash the app // If there's an error saving a note, close the window and crash the app
@ -86,12 +85,13 @@ function onError() {
window.close(); window.close();
} }
function onUnload()
{ function onUnload() {
if(noteEditor && noteEditor.value)
noteEditor.save();
Zotero.Notifier.unregisterObserver(notifierUnregisterID); Zotero.Notifier.unregisterObserver(notifierUnregisterID);
if (noteEditor.item) {
window.opener.ZoteroPane.onNoteWindowClosed(noteEditor.item.id, noteEditor.value);
}
} }
var NotifyCallback = { var NotifyCallback = {

View file

@ -15,7 +15,6 @@
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="include.js"/> <script src="include.js"/>
<script src="itemPane.js"/>
<script src="note.js"/> <script src="note.js"/>
<keyset> <keyset>

View file

@ -53,7 +53,6 @@ var ZoteroPane = new function()
this.setItemsPaneMessage = setItemsPaneMessage; this.setItemsPaneMessage = setItemsPaneMessage;
this.clearItemsPaneMessage = clearItemsPaneMessage; this.clearItemsPaneMessage = clearItemsPaneMessage;
this.contextPopupShowing = contextPopupShowing; this.contextPopupShowing = contextPopupShowing;
this.openNoteWindow = openNoteWindow;
this.viewSelectedAttachment = viewSelectedAttachment; this.viewSelectedAttachment = viewSelectedAttachment;
this.reportErrors = reportErrors; this.reportErrors = reportErrors;
this.displayErrorMessage = displayErrorMessage; this.displayErrorMessage = displayErrorMessage;
@ -1479,37 +1478,7 @@ var ZoteroPane = new function()
var item = selectedItems[0]; var item = selectedItems[0];
if (item.isNote()) { if (item.isNote()) {
var noteEditor = document.getElementById('zotero-note-editor'); ZoteroItemPane.onNoteSelected(item, this.collectionsView.editable);
noteEditor.mode = this.collectionsView.editable ? 'edit' : 'view';
var clearUndo = noteEditor.item ? noteEditor.item.id != item.id : false;
noteEditor.parent = null;
noteEditor.item = item;
// If loading new or different note, disable undo while we repopulate the text field
// so Undo doesn't end up clearing the field. This also ensures that Undo doesn't
// undo content from another note into the current one.
if (clearUndo) {
noteEditor.clearUndo();
}
var viewButton = document.getElementById('zotero-view-note-button');
if (this.collectionsView.editable) {
viewButton.hidden = false;
viewButton.setAttribute('noteID', item.id);
if (!item.isTopLevelItem()) {
viewButton.setAttribute('parentItemID', item.parentItemID);
}
else {
viewButton.removeAttribute('parentItemID');
}
}
else {
viewButton.hidden = true;
}
document.getElementById('zotero-item-pane-content').selectedIndex = 2;
} }
else if (item.isAttachment()) { else if (item.isAttachment()) {
@ -3640,8 +3609,7 @@ var ZoteroPane = new function()
function openNoteWindow(itemID, col, parentKey) this.openNoteWindow = function (itemID, col, parentKey) {
{
if (!this.canEdit()) { if (!this.canEdit()) {
this.displayCannotEditLibraryMessage(); this.displayCannotEditLibraryMessage();
return; return;
@ -3650,22 +3618,17 @@ var ZoteroPane = new function()
var name = null; var name = null;
if (itemID) { if (itemID) {
let w = this.findNoteWindow(itemID);
if (w) {
w.focus();
return;
}
// Create a name for this window so we can focus it later // Create a name for this window so we can focus it later
// //
// Collection is only used on new notes, so we don't need to // Collection is only used on new notes, so we don't need to
// include it in the name // include it in the name
name = 'zotero-note-' + itemID; name = 'zotero-note-' + itemID;
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var e = wm.getEnumerator('zotero:note');
while (e.hasMoreElements()) {
var w = e.getNext();
if (w.name == name) {
w.focus();
return;
}
}
} }
var io = { itemID: itemID, collectionID: col, parentItemKey: parentKey }; var io = { itemID: itemID, collectionID: col, parentItemKey: parentKey };
@ -3673,6 +3636,32 @@ var ZoteroPane = new function()
} }
this.findNoteWindow = function (itemID) {
var name = 'zotero-note-' + itemID;
var wm = Services.wm;
var e = wm.getEnumerator('zotero:note');
while (e.hasMoreElements()) {
var w = e.getNext();
if (w.name == name) {
return w;
}
}
};
this.onNoteWindowClosed = async function (itemID, noteText) {
var item = Zotero.Items.get(itemID);
item.setNote(noteText);
await item.saveTx();
// If note is still selected, show the editor again when the note window closes
var selectedItems = this.getSelectedItems(true);
if (selectedItems.length == 1 && itemID == selectedItems[0]) {
ZoteroItemPane.onNoteSelected(item, this.collectionsView.editable);
}
};
this.addAttachmentFromURI = Zotero.Promise.method(function (link, itemID) { this.addAttachmentFromURI = Zotero.Promise.method(function (link, itemID) {
if (!this.canEdit()) { if (!this.canEdit()) {
this.displayCannotEditLibraryMessage(); this.displayCannotEditLibraryMessage();

View file

@ -339,6 +339,7 @@ pane.item.notes.delete.confirm = Are you sure you want to delete this note?
pane.item.notes.count.zero = %S notes: pane.item.notes.count.zero = %S notes:
pane.item.notes.count.singular = %S note: pane.item.notes.count.singular = %S note:
pane.item.notes.count.plural = %S notes: pane.item.notes.count.plural = %S notes:
pane.item.notes.editingInWindow = Editing in separate window
pane.item.attachments.rename.title = New title: pane.item.attachments.rename.title = New title:
pane.item.attachments.rename.renameAssociatedFile = Rename associated file pane.item.attachments.rename.renameAssociatedFile = Rename associated file
pane.item.attachments.rename.error = An error occurred while renaming the file. pane.item.attachments.rename.error = An error occurred while renaming the file.