Experiment with the new UI

This commit is contained in:
Martynas Bagdonas 2020-10-05 10:00:17 +03:00 committed by Dan Stillman
parent 52f3945aa4
commit 8709ddd657
13 changed files with 692 additions and 191 deletions

View file

@ -82,6 +82,10 @@
this._editorInstance.saveSync();
}
}
this.getCurrentInstance = () => {
return this._editorInstance;
}
this.initEditor = async (state) => {
if (this._editorInstance) {
@ -94,7 +98,8 @@
iframeWindow: document.getAnonymousElementByAttribute(this, 'anonid', 'editor-view').contentWindow,
popup: document.getAnonymousElementByAttribute(this, 'anonid', 'editor-menu'),
onNavigate: this._navigateHandler,
readOnly: !this.editable
readOnly: !this.editable,
placeholder: this.placeholder
});
}
@ -220,10 +225,10 @@
this.initEditor();
var parentKey = this._item.parentKey;
if (parentKey) {
this.parentItem = Zotero.Items.getByLibraryAndKey(this._item.libraryID, parentKey);
}
// var parentKey = this._item.parentKey;
// if (parentKey) {
// this.parentItem = Zotero.Items.getByLibraryAndKey(this._item.libraryID, parentKey);
// }
this._id('links-box').item = this._item;
})();

View file

@ -32,6 +32,7 @@ var ZoteroItemPane = new function() {
var _selectedNoteID;
var _translationTarget;
var _noteIDs;
var _recentlyPinned = [];
this.onLoad = function () {
if (!Zotero) {
@ -55,7 +56,15 @@ var ZoteroItemPane = new function() {
};
_relatedBox = document.getElementById('zotero-editpane-related');
this._unregisterID = Zotero.Notifier.registerObserver(this, ['item'], 'itemPane');
this._unregisterID = Zotero.Notifier.registerObserver(this, ['item', 'tab'], 'itemPane');
document.getElementById('temp-toggle-1').addEventListener('click', () => {
this.togglePane();
});
document.getElementById('temp-toggle-2').addEventListener('click', () => {
this.togglePane();
});
this.initPinnedView();
}
@ -213,15 +222,28 @@ 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(type == 'item') {
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);
}
}
if (refresh) {
yield this.viewItem(_lastItem, null, 1);
}
else if (type == 'tab') {
if (action == 'add') {
this.addPDFTabContext(ids[0], extraData.itemID);
}
else if (action == 'close') {
this.removeTabContext(ids[0]);
}
else if (action == 'select') {
this.selectTabContext(ids[0], extraData.type);
}
}
});
@ -435,6 +457,369 @@ var ZoteroItemPane = new function() {
elem.setAttribute('tooltiptext', tooltip);
};
this.getActiveNote = function() {
let mainDeck = document.getElementById('zotero-item-pane-main-deck');
if (mainDeck.selectedIndex == 0) {
let contextualDeck = document.getElementById('zotero-item-pane-contextual-deck');
if (contextualDeck.selectedIndex > 0) {
let child = contextualDeck.children[contextualDeck.selectedIndex];
if (child.querySelector('deck').selectedIndex == 1) {
return child.querySelector('zoteronoteeditor');
}
}
}
else {
let pinnedDeck = document.getElementById('zotero-item-pane-pin-deck2');
if (pinnedDeck.selectedIndex == 1) {
return pinnedDeck.querySelector('zoteronoteeditor');
}
}
return null;
}
window.addEventListener('mousedown', () => {
Zotero.debug('active note')
Zotero.debug(this.getActiveNote())
});
this.pinNote = function(itemID) {
_recentlyPinned.unshift(itemID);
_recentlyPinned = _recentlyPinned.slice(0, 10);
this._setPinnedNote(itemID);
this._updatePinnedList();
}
this.togglePane = function(forceItem) {
let mainDeck = document.getElementById('zotero-item-pane-main-deck');
let value;
if (forceItem !== undefined) {
value = forceItem ? 0 : 1;
}
else {
value = mainDeck.selectedIndex == 0 ? 1 : 0;
}
document.getElementById('temp-toggle-1').firstChild.remove();
document.getElementById('temp-toggle-2').firstChild.remove();
if (value == 0) {
document.getElementById('temp-toggle-1').append('(Slider)__________');
document.getElementById('temp-toggle-2').append('(Slider)__________');
}
else {
document.getElementById('temp-toggle-1').append('__________(Slider)');
document.getElementById('temp-toggle-2').append('__________(Slider)');
}
mainDeck.selectedIndex = value;
}
this.initPinnedView = async function () {
let container = document.getElementById('zotero-item-pane-pin-deck');
let bar = document.createElement('hbox');
container.appendChild(bar);
let inner = document.createElement('deck');
inner.id = 'zotero-item-pane-pin-deck2';
inner.style.backgroundColor = 'white';
inner.setAttribute('flex', 1);
container.appendChild(inner);
let returnButton = document.createElement('toolbarbutton');
returnButton.className = 'zotero-tb-button';
returnButton.id = 'zotero-tb-return';
returnButton.style.listStyleImage = "url('chrome://zotero/skin/citation-delete.png')"
returnButton.addEventListener('click', () => {
inner.setAttribute('selectedIndex', 0);
});
bar.append(returnButton, 'Pinned note');
bar.style.overflowX = 'hidden';
bar.style.textOverflow = 'ellipsis';
bar.style.fontWeight = 'bold';
let list = document.createElement('vbox');
list.setAttribute('flex', 1);
list.className = 'zotero-box';
let note = document.createElement('zoteronoteeditor');
note.id = 'zotero-item-pane-pinned-note';
note.setAttribute('flex', 1);
inner.appendChild(list);
inner.appendChild(note);
inner.setAttribute('selectedIndex', 0);
let head = document.createElement('hbox');
head.setAttribute('align', 'center');
let label = document.createElement('label');
let button = document.createElement('button');
button.setAttribute('label', 'Add');
button.addEventListener('click', async () => {
inner.setAttribute('selectedIndex', 1);
let item = new Zotero.Item('note');
item.libraryID = parentItem.libraryID;
item.parentKey = parentItem.key;
note.mode = 'edit';
note.item = item;
note.parentItem = null;
});
head.append(label, button);
let grid = document.createElement('grid');
grid.setAttribute('flex', 1);
grid.style.overflowY = 'scroll';
let columns = document.createElement('columns');
let column1 = document.createElement('column');
column1.setAttribute('flex', 1);
let column2 = document.createElement('column');
columns.append(column1, column2);
grid.append(columns);
let rows = document.createElement('rows');
rows.setAttribute('flex', 1);
rows.id = 'zotero-item-pane-pinned-list';
grid.append(rows);
list.append(head, grid);
this._updatePinnedList();
}
this._updatePinnedList = async function() {
let rows = document.getElementById('zotero-item-pane-pinned-list');
while (rows.hasChildNodes()) {
rows.removeChild(rows.firstChild);
}
await Zotero.Schema.schemaUpdatePromise;
var s = new Zotero.Search();
s.addCondition('libraryID', 'is', 1);
s.addCondition('itemType', 'is', 'note');
s.addCondition('noChildren', 'true');
let notes = await s.search();
notes = Zotero.Items.get(notes);
notes.sort((a, b) => {
a = a.getField('dateModified');
b = b.getField('dateModified');
return b.localeCompare(a);
});
var row = document.createElement('row');
row.style.fontWeight = 'bold';
row.appendChild(document.createTextNode('Recently pinned notes'));
rows.append(row);
this._appendNoteRows(Zotero.Items.get(_recentlyPinned), rows, false, (id) => {
this._setPinnedNote(id);
});
row = document.createElement('row');
row.style.fontWeight = 'bold';
row.appendChild(document.createTextNode('Recently edited standalone notes'));
rows.append(row);
this._appendNoteRows(notes, rows, false, (id) => {
this._setPinnedNote(id);
});
}
this._setPinnedNote = function (itemID) {
let pinnedDeck = document.getElementById('zotero-item-pane-pin-deck2');
pinnedDeck.setAttribute('selectedIndex', 1);
let pinnedNote = document.getElementById('zotero-item-pane-pinned-note');
pinnedNote.mode = 'edit';
pinnedNote.item = Zotero.Items.get(itemID);
pinnedNote.parentItem = null;
this.togglePane(false);
}
this._appendNoteRows = function (notes, list, editable, onClick, onDelete) {
for (var i = 0; i < notes.length; i++) {
let note = notes[i];
let id = notes[i].id;
var icon = document.createElement('image');
icon.className = 'zotero-box-icon';
icon.setAttribute('src', `chrome://zotero/skin/treeitem-note${Zotero.hiDPISuffix}.png`);
var label = document.createElement('label');
label.className = 'zotero-box-label';
var title = note.getNoteTitle();
title = title ? title : Zotero.getString('pane.item.notes.untitled');
label.setAttribute('value', title);
label.setAttribute('flex', '1'); //so that the long names will flex smaller
label.setAttribute('crop', 'end');
var box = document.createElement('box');
box.setAttribute('class', 'zotero-clicky');
box.addEventListener('click', () => {
onClick(id);
});
box.appendChild(icon);
box.appendChild(label);
if (editable) {
var removeButton = document.createElement('label');
removeButton.setAttribute('value', '-');
removeButton.setAttribute('class', 'zotero-clicky zotero-clicky-minus');
removeButton.addEventListener('click', function () {
onDelete(id)
});
}
var row = document.createElement('row');
row.appendChild(box);
if (editable) {
row.appendChild(removeButton);
}
list.appendChild(row);
}
}
this.addPDFTabContext = function(tabID, itemID) {
let contextualDeck = document.getElementById('zotero-item-pane-contextual-deck');
let container = document.createElement('vbox');
container.id = tabID + '-context';
let bar = document.createElement('hbox');
container.appendChild(bar);
let inner = document.createElement('deck');
inner.style.backgroundColor = 'white';
inner.setAttribute('flex', 1);
container.appendChild(inner);
contextualDeck.appendChild(container);
let item = Zotero.Items.get(itemID);
if (!item.parentID) {
inner.append("The PDF doesn't have a parent");
return;
}
let parentItem = Zotero.Items.get(item.parentID);
let returnButton = document.createElement('toolbarbutton');
returnButton.className = 'zotero-tb-button';
returnButton.id = 'zotero-tb-return';
returnButton.style.listStyleImage = "url('chrome://zotero/skin/citation-delete.png')"
returnButton.addEventListener('click', () => {
inner.setAttribute('selectedIndex', 0);
});
bar.append(returnButton, parentItem.getField('title'));
bar.style.overflowX = 'hidden';
bar.style.textOverflow = 'ellipsis';
bar.style.fontWeight = 'bold';
let list = document.createElement('vbox');
list.setAttribute('flex', 1);
list.className = 'zotero-box';
let note = document.createElement('zoteronoteeditor');
note.setAttribute('flex', 1);
inner.appendChild(list);
inner.appendChild(note);
inner.setAttribute('selectedIndex', 0);
note.placeholder = 'Drag annotations and write item-specific notes';
let head = document.createElement('hbox');
head.setAttribute('align', 'center');
let label = document.createElement('label');
let button = document.createElement('button');
button.setAttribute('label', 'Add');
button.addEventListener('click', async () => {
inner.setAttribute('selectedIndex', 1);
let item = new Zotero.Item('note');
item.libraryID = parentItem.libraryID;
item.parentKey = parentItem.key;
await item.saveTx();
note.mode = 'edit';
note.item = item;
note.parentItem = null;
_updateList();
});
head.append(label, button);
let grid = document.createElement('grid');
grid.setAttribute('flex', 1);
let columns = document.createElement('columns');
let column1 = document.createElement('column');
column1.setAttribute('flex', 1);
let column2 = document.createElement('column');
columns.append(column1, column2);
grid.append(columns);
let rows = document.createElement('rows');
rows.setAttribute('flex', 1);
grid.append(rows);
list.append(head, grid);
let parentNotes = parentItem.getNotes();
if (parentNotes.length == 0) {
inner.setAttribute('selectedIndex', 1);
let item = new Zotero.Item('note');
item.libraryID = parentItem.libraryID;
item.parentKey = parentItem.key;
note.mode = 'edit';
note.item = item;
note.parentItem = null;
}
else if (parentNotes.length == 1) {
inner.setAttribute('selectedIndex', 1);
note.mode = 'edit';
note.item = Zotero.Items.get(parentNotes[0]);
note.parentItem = null;
}
let _updateList = () => {
while (rows.hasChildNodes()) {
rows.removeChild(rows.firstChild);
}
let parentNotes = Zotero.Items.get(parentItem.getNotes());
this._appendNoteRows(parentNotes, rows, true, (id) => {
inner.setAttribute('selectedIndex', 1);
note.mode = 'edit';
note.item = Zotero.Items.get(id);
note.parentItem = null;
}, (id) => {
ZoteroItemPane.removeNote(id);
});
}
_updateList();
}
this.removeTabContext = function(tabID) {
document.getElementById(tabID + '-context').remove();
};
this.selectTabContext = function(tabID, type) {
let contextualDeck = document.getElementById('zotero-item-pane-contextual-deck');
contextualDeck.selectedIndex = Array.from(contextualDeck.children).findIndex(x => x.id == tabID + '-context');
let toolbar = document.getElementById('zotero-pane-horizontal-space');
let extendedToolbar = document.getElementById('zotero-item-pane-padding-top');
let itemPane = document.getElementById('zotero-item-pane');
if (type == 'library') {
toolbar.hidden = false;
extendedToolbar.hidden = true;
itemPane.hidden = false;
}
else {
toolbar.hidden = true;
extendedToolbar.hidden = false;
}
};
function _updateNoteCount() {
var c = _notesList.childNodes.length;

View file

@ -35,115 +35,125 @@
<script src="itemPane.js"></script>
<vbox id="zotero-item-pane" zotero-persist="width height">
<!-- My Publications -->
<hbox id="zotero-item-pane-top-buttons-my-publications" class="zotero-item-pane-top-buttons" hidden="true">
<button id="zotero-item-collection-show-hide"/>
</hbox>
<!-- Trash -->
<hbox id="zotero-item-pane-top-buttons-trash" class="zotero-item-pane-top-buttons" hidden="true">
<button id="zotero-item-restore-button" label="&zotero.items.menu.restoreToLibrary;"
oncommand="ZoteroPane_Local.restoreSelectedItems()"/>
<button id="zotero-item-delete-button" label="&zotero.item.deletePermanently;"
oncommand="ZoteroPane_Local.deleteSelectedItems()"/>
</hbox>
<!-- Feed -->
<hbox id="zotero-item-pane-top-buttons-feed" class="zotero-item-pane-top-buttons" hidden="true">
<button id="zotero-feed-item-toggleRead-button"
oncommand="ZoteroPane_Local.toggleSelectedItemsRead();"/>
<button id="zotero-feed-item-addTo-button" type="menu-button"
oncommand="ZoteroItemPane.translateSelectedItems()">
<menupopup id="zotero-item-addTo-menu" onpopupshowing="ZoteroItemPane.buildTranslateSelectContextMenu(event);"/>
</button>
</hbox>
<!-- Commons -->
<button id="zotero-item-show-original" label="Show Original"
oncommand="ZoteroPane_Local.showOriginalItem()" hidden="true"/>
<deck id="zotero-item-pane-content" selectedIndex="0" flex="1">
<!-- Center label (for zero or multiple item selection) -->
<groupbox id="zotero-item-pane-groupbox" pack="center" align="center">
<vbox id="zotero-item-pane-message-box"/>
</groupbox>
<!-- Regular item -->
<tabbox id="zotero-view-tabbox" flex="1" onselect="if (!ZoteroPane_Local.collectionsView.selection || event.originalTarget.localName != 'tabpanels') { return; }; ZoteroItemPane.viewItem(ZoteroPane_Local.getSelectedItems()[0], ZoteroPane_Local.collectionsView.editable ? 'edit' : 'view', this.selectedIndex)">
<tabs id="zotero-editpane-tabs">
<tab id="zotero-editpane-info-tab" label="&zotero.tabs.info.label;"/>
<tab id="zotero-editpane-notes-tab" label="&zotero.tabs.notes.label;"/>
<tab id="zotero-editpane-tags-tab" label="&zotero.tabs.tags.label;"/>
<tab id="zotero-editpane-related-tab" label="&zotero.tabs.related.label;"/>
</tabs>
<tabpanels id="zotero-view-item" flex="1">
<tabpanel>
<zoteroitembox id="zotero-editpane-item-box" flex="1"/>
</tabpanel>
<tabpanel flex="1" orient="vertical">
<vbox flex="1" id="zotero-editpane-notes" class="zotero-box">
<hbox align="center">
<label id="zotero-editpane-notes-label"/>
<button id="zotero-editpane-notes-add" label="&zotero.item.add;" oncommand="ZoteroItemPane.addNote(event.shiftKey);"/>
</hbox>
<grid flex="1">
<columns>
<column flex="1"/>
<column/>
</columns>
<rows id="zotero-editpane-dynamic-notes" flex="1"/>
</grid>
</vbox>
</tabpanel>
<tabpanel id="tags-pane" orient="vertical" context="tags-context-menu">
<html:div id="tags-box-container"></html:div>
</tabpanel>
<tabpanel>
<relatedbox id="zotero-editpane-related" flex="1"/>
</tabpanel>
</tabpanels>
</tabbox>
<!-- Note item -->
<groupbox id="zotero-view-note" flex="1">
<!--
'onerror' handler crashes the app on a save error to prevent typing in notes
while they're not being saved
-->
<zoteronoteeditor id="zotero-note-editor" flex="1" notitle="1"
previousfocus="zotero-items-tree"
onerror="return;ZoteroPane.displayErrorMessage(); /*this.mode = 'view'*/"/>
<button id="zotero-view-note-button"
label="&zotero.notes.separate;"
oncommand="ZoteroItemPane.openNoteWindow()"/>
</groupbox>
<!-- Attachment item -->
<groupbox>
<zoteroattachmentbox id="zotero-attachment-box" flex="1"/>
</groupbox>
<!-- Duplicate merging -->
<vbox id="zotero-duplicates-merge-pane" flex="1">
<groupbox>
<button id="zotero-duplicates-merge-button" oncommand="Zotero_Duplicates_Pane.merge()"/>
</groupbox>
<groupbox id="zotero-duplicates-merge-version-select">
<description>&zotero.duplicatesMerge.versionSelect;</description>
<hbox>
<listbox id="zotero-duplicates-merge-original-date" onselect="Zotero_Duplicates_Pane.setMaster(this.selectedIndex)" rows="0"/>
<hbox id="zotero-item-pane-padding-top" height="32" hidden="true" align="right"><button id="temp-toggle-2">(Slider)_______</button></hbox>
<deck id="zotero-item-pane-main-deck" flex="1" selectedIndex="0">
<deck id="zotero-item-pane-contextual-deck" selectedIndex="0">
<vbox id="zotero-pane-context">
<!-- My Publications -->
<hbox id="zotero-item-pane-top-buttons-my-publications" class="zotero-item-pane-top-buttons" hidden="true">
<button id="zotero-item-collection-show-hide"/>
</hbox>
</groupbox>
<groupbox flex="1">
<description id="zotero-duplicates-merge-field-select">&zotero.duplicatesMerge.fieldSelect;</description>
<zoteroitembox id="zotero-duplicates-merge-item-box" flex="1"/>
</groupbox>
</vbox>
<!-- Trash -->
<hbox id="zotero-item-pane-top-buttons-trash" class="zotero-item-pane-top-buttons" hidden="true">
<button id="zotero-item-restore-button" label="&zotero.items.menu.restoreToLibrary;"
oncommand="ZoteroPane_Local.restoreSelectedItems()"/>
<button id="zotero-item-delete-button" label="&zotero.item.deletePermanently;"
oncommand="ZoteroPane_Local.deleteSelectedItems()"/>
</hbox>
<!-- Feed -->
<hbox id="zotero-item-pane-top-buttons-feed" class="zotero-item-pane-top-buttons" hidden="true">
<button id="zotero-feed-item-toggleRead-button"
oncommand="ZoteroPane_Local.toggleSelectedItemsRead();"/>
<button id="zotero-feed-item-addTo-button" type="menu-button"
oncommand="ZoteroItemPane.translateSelectedItems()">
<menupopup id="zotero-item-addTo-menu" onpopupshowing="ZoteroItemPane.buildTranslateSelectContextMenu(event);"/>
</button>
</hbox>
<!-- Commons -->
<button id="zotero-item-show-original" label="Show Original"
oncommand="ZoteroPane_Local.showOriginalItem()" hidden="true"/>
<deck id="zotero-item-pane-content" selectedIndex="0" flex="1">
<!-- Center label (for zero or multiple item selection) -->
<groupbox id="zotero-item-pane-groupbox" pack="center" align="center">
<vbox id="zotero-item-pane-message-box"/>
</groupbox>
<!-- Regular item -->
<tabbox id="zotero-view-tabbox" flex="1" onselect="if (!ZoteroPane_Local.collectionsView.selection || event.originalTarget.localName != 'tabpanels') { return; }; ZoteroItemPane.viewItem(ZoteroPane_Local.getSelectedItems()[0], ZoteroPane_Local.collectionsView.editable ? 'edit' : 'view', this.selectedIndex)">
<tabs id="zotero-editpane-tabs">
<tab id="zotero-editpane-info-tab" label="&zotero.tabs.info.label;"/>
<tab id="zotero-editpane-notes-tab" label="&zotero.tabs.notes.label;"/>
<tab id="zotero-editpane-tags-tab" label="&zotero.tabs.tags.label;"/>
<tab id="zotero-editpane-related-tab" label="&zotero.tabs.related.label;"/>
</tabs>
<tabpanels id="zotero-view-item" flex="1">
<tabpanel>
<zoteroitembox id="zotero-editpane-item-box" flex="1"/>
</tabpanel>
<tabpanel flex="1" orient="vertical">
<vbox flex="1" id="zotero-editpane-notes" class="zotero-box">
<hbox align="center">
<label id="zotero-editpane-notes-label"/>
<button id="zotero-editpane-notes-add" label="&zotero.item.add;" oncommand="ZoteroItemPane.addNote(event.shiftKey);"/>
</hbox>
<grid flex="1">
<columns>
<column flex="1"/>
<column/>
</columns>
<rows id="zotero-editpane-dynamic-notes" flex="1"/>
</grid>
</vbox>
</tabpanel>
<tabpanel id="tags-pane" orient="vertical" context="tags-context-menu">
<html:div id="tags-box-container"></html:div>
</tabpanel>
<tabpanel>
<relatedbox id="zotero-editpane-related" flex="1"/>
</tabpanel>
</tabpanels>
</tabbox>
<!-- Note item -->
<groupbox id="zotero-view-note" flex="1">
<!--
'onerror' handler crashes the app on a save error to prevent typing in notes
while they're not being saved
-->
<zoteronoteeditor id="zotero-note-editor" flex="1" notitle="1"
previousfocus="zotero-items-tree"
onerror="return;ZoteroPane.displayErrorMessage(); /*this.mode = 'view'*/"/>
<button id="zotero-view-note-button"
label="&zotero.notes.separate;"
oncommand="ZoteroItemPane.openNoteWindow()"/>
</groupbox>
<!-- Attachment item -->
<groupbox>
<zoteroattachmentbox id="zotero-attachment-box" flex="1"/>
</groupbox>
<!-- Duplicate merging -->
<vbox id="zotero-duplicates-merge-pane" flex="1">
<groupbox>
<button id="zotero-duplicates-merge-button" oncommand="Zotero_Duplicates_Pane.merge()"/>
</groupbox>
<groupbox id="zotero-duplicates-merge-version-select">
<description>&zotero.duplicatesMerge.versionSelect;</description>
<hbox>
<listbox id="zotero-duplicates-merge-original-date" onselect="Zotero_Duplicates_Pane.setMaster(this.selectedIndex)" rows="0"/>
</hbox>
</groupbox>
<groupbox flex="1">
<description id="zotero-duplicates-merge-field-select">&zotero.duplicatesMerge.fieldSelect;</description>
<zoteroitembox id="zotero-duplicates-merge-item-box" flex="1"/>
</groupbox>
</vbox>
</deck>
</vbox>
</deck>
<vbox id="zotero-item-pane-pin-deck"></vbox>
</deck>
</vbox>
</overlay>

View file

@ -92,7 +92,7 @@ var Zotero_Tabs = new function () {
* @param {Function} onClose
* @return {{ id: string, container: XULElement}} id - tab id, container - a new tab container created in the deck
*/
this.add = function ({ type, title, index, select, onClose }) {
this.add = function ({ type, title, index, select, onClose, notifierData }) {
if (typeof type != 'string') {
throw new Error(`'type' should be a string (was ${typeof type})`);
}
@ -116,6 +116,7 @@ var Zotero_Tabs = new function () {
if (select) {
this.select(id);
}
Zotero.Notifier.trigger('add', 'tab', id, notifierData);
return { id, container };
};
@ -156,6 +157,7 @@ var Zotero_Tabs = new function () {
if (tab.onClose) {
tab.onClose();
}
Zotero.Notifier.trigger('close', 'tab', tab.id);
this._update();
};
@ -197,9 +199,7 @@ var Zotero_Tabs = new function () {
this._selectedID = id;
this.deck.selectedIndex = Array.from(this.deck.children).findIndex(x => x.id == id);
this._update();
if (this.onTabSelect) {
this.onTabSelect(tab.type);
}
Zotero.Notifier.trigger('select', 'tab', tab.id, { type: tab.type });
};
/**

View file

@ -95,10 +95,10 @@ Zotero.Notes = new function() {
}
Zotero.DB.requireTransaction();
// `"uri":"http://zotero.org/users/${fromUserID}/items/"`
let from = `%22uri%22%3A%22http%3A%2F%2Fzotero.org%2Fusers%2F${fromUserID}%2Fitems%2F`;
// `"uri":"http://zotero.org/users/${toUserId}/items/"`
let to = `%22uri%22%3A%22http%3A%2F%2Fzotero.org%2Fusers%2F${toUserID}%2Fitems%2F`;
// `"http://zotero.org/users/${fromUserID}/items/`
let from = `%22http%3A%2F%2Fzotero.org%2Fusers%2F${fromUserID}%2Fitems%2F`;
// `"http://zotero.org/users/${toUserId}/items/`
let to = `%22http%3A%2F%2Fzotero.org%2Fusers%2F${toUserID}%2Fitems%2F`;
let sql = `UPDATE itemNotes SET note=REPLACE(note, '${from}', '${to}')`;
await Zotero.DB.queryAsync(sql);

View file

@ -63,6 +63,7 @@ class EditorInstance {
action: 'init',
value: this._state || this._item.note,
readOnly: this._readOnly,
placeholder: options.placeholder,
dir: Zotero.dir,
font: this._getFont(),
// TODO: We should avoid hitting `data-schema-version` in note text
@ -98,7 +99,7 @@ class EditorInstance {
async updateCitationsForURIs(uris) {
let subscriptions = this._subscriptions
.filter(s => s.data.citation && s.data.citation.citationItems
.some(citationItem => uris.includes(citationItem.uri)));
.some(citationItem => uris.some(uri => citationItem.uris.includes(uri))));
for (let subscription of subscriptions) {
await this._feedSubscription(subscription);
}
@ -113,6 +114,13 @@ class EditorInstance {
this._save(noteData);
}
}
async insertAnnotations(annotations) {
let list = await this._annotationsToInsertionList(annotations);
if (list.length) {
this._postMessage({ action: 'insertAnnotationsAndCitations', list, pos: -1 });
}
}
_postMessage(message) {
this._iframeWindow.postMessage({ instanceId: this.instanceID, message }, '*');
@ -132,6 +140,36 @@ class EditorInstance {
this._postMessage({ action: 'updateFont', font: this._getFont() });
}
async _annotationsToInsertionList(annotations) {
let list = [];
for (let annotation of annotations) {
let attachmentItem = await Zotero.Items.getAsync(annotation.itemId);
if (!attachmentItem) {
continue;
}
let item = attachmentItem.parentID && await Zotero.Items.getAsync(attachmentItem.parentID) || attachmentItem;
if (item !== attachmentItem) {
annotation.parentURI = Zotero.URI.getItemURI(item);
}
annotation.uri = Zotero.URI.getItemURI(attachmentItem);
let citationItem = {
uris: [Zotero.URI.getItemURI(item)],
itemData: Zotero.Cite.System.prototype.retrieveItem(item),
locator: annotation.pageLabel
};
annotation.citationItem = citationItem;
let citation = {
citationItems: [citationItem],
properties: {}
};
list.push({ annotation, citation });
}
return list;
}
_messageHandler = async (e) => {
if (e.data.instanceId !== this.instanceID) {
return;
@ -148,11 +186,12 @@ class EditorInstance {
if (!item) {
continue;
}
list.push({
citation: {
citationItems: [{
uri: Zotero.URI.getItemURI(item),
backupText: this._getBackupStr(item)
uris: [Zotero.URI.getItemURI(item)],
itemData: Zotero.Cite.System.prototype.retrieveItem(item),
}],
properties: {}
}
@ -161,23 +200,7 @@ class EditorInstance {
}
else if (type === 'zotero/annotation') {
let annotations = JSON.parse(data);
for (let annotation of annotations) {
let attachmentItem = await Zotero.Items.getAsync(annotation.itemId);
if (!attachmentItem) {
continue;
}
let citationItem = attachmentItem.parentID && await Zotero.Items.getAsync(attachmentItem.parentID) || attachmentItem;
annotation.uri = Zotero.URI.getItemURI(attachmentItem);
let citation = {
citationItems: [{
uri: Zotero.URI.getItemURI(citationItem),
backupText: this._getBackupStr(citationItem),
locator: annotation.pageLabel
}],
properties: {}
};
list.push({ annotation, citation });
}
list = await this._annotationsToInsertionList(annotations);
}
if (list.length) {
this._postMessage({ action: 'insertAnnotationsAndCitations', list, pos });
@ -194,6 +217,26 @@ class EditorInstance {
}
return;
}
case 'openCitation': {
let { citation } = message;
let items = [];
for (let citationItem of citation.citationItems) {
let item = await this._getItemFromURIs(citationItem.uris);
if (item) {
items.push(item);
}
}
let zp = Zotero.getActiveZoteroPane();
if (zp && items.length) {
zp.selectItems(items.map(item => item.id));
let win = Zotero.getMainWindow();
if (win) {
win.focus();
win.Zotero_Tabs.select('zotero-pane');
}
}
return;
}
case 'openUrl': {
let { url } = message;
let zp = Zotero.getActiveZoteroPane();
@ -245,7 +288,7 @@ class EditorInstance {
citation = JSON.parse(JSON.stringify(citation));
let availableCitationItems = [];
for (let citationItem of citation.citationItems) {
let item = await Zotero.URI.getURIItem(citationItem.uri);
let item = await this._getItemFromURIs(citationItem.uris);
if (item) {
availableCitationItems.push({ ...citationItem, id: item.id });
}
@ -444,6 +487,31 @@ class EditorInstance {
}
}
async _getItemFromURIs(uris) {
for (let uri of uris) {
// Try getting URI directly
try {
let item = await Zotero.URI.getURIItem(uri);
if (item) {
// Ignore items in the trash
if (!item.deleted) {
return item;
}
}
}
catch (e) {
}
// Try merged item mapping
var replacer = await Zotero.Relations.getByPredicateAndObject(
'item', Zotero.Relations.replacedItemPredicate, uri
);
if (replacer.length && !replacer[0].deleted) {
return replacer[0];
}
}
}
/**
* Builds the string to go inside a bubble
*/
@ -483,15 +551,19 @@ class EditorInstance {
async _getFormattedCitation(citation) {
let formattedItems = [];
for (let citationItem of citation.citationItems) {
let item = await Zotero.URI.getURIItem(citationItem.uri);
if (item && !item.deleted) {
let item = await this._getItemFromURIs(citationItem.uris);
if (!item && citationItem.itemData) {
item = new Zotero.Item();
Zotero.Utilities.itemFromCSLJSON(item, citationItem.itemData);
}
if (item) {
formattedItems.push(this._buildBubbleString(citationItem, this._getBackupStr(item)));
}
else {
let formattedItem = this._buildBubbleString(citationItem, citationItem.backupText);
formattedItem = `<span style="color: red;">${formattedItem}</span>`;
formattedItems.push(formattedItem);
}
// else {
// let formattedItem = this._buildBubbleString(citationItem, citationItem.backupText);
// formattedItem = `<span style="color: red;">${formattedItem}</span>`;
// formattedItems.push(formattedItem);
// }
}
return formattedItems.join(';');
}
@ -595,10 +667,10 @@ class EditorInstance {
}
for (let citationItem of citation.citationItems) {
let itm = await Zotero.Items.getAsync(parseInt(citationItem.id));
let item = await Zotero.Items.getAsync(parseInt(citationItem.id));
delete citationItem.id;
citationItem.uri = Zotero.URI.getItemURI(itm);
citationItem.backupText = that._getBackupStr(itm);
citationItem.uris = [Zotero.URI.getItemURI(item)];
citationItem.itemData = Zotero.Cite.System.prototype.retrieveItem(item);
}
if (progressCallback || !citationData.citationItems.length) {

View file

@ -30,7 +30,7 @@ Zotero.Notifier = new function(){
var _types = [
'collection', 'search', 'share', 'share-items', 'item', 'file',
'collection-item', 'item-tag', 'tag', 'setting', 'group', 'trash',
'bucket', 'relation', 'feed', 'feedItem', 'sync', 'api-key'
'bucket', 'relation', 'feed', 'feedItem', 'sync', 'api-key', 'tab'
];
var _transactionID = false;
var _queue = {};

View file

@ -34,9 +34,9 @@ class ReaderInstance {
this._nextHistory = [];
}
this._itemID = item.id;
this.updateTitle();
let path = await item.getFilePathAsync();
let buf = await OS.File.read(path, {});
this.updateTitle();
buf = new Uint8Array(buf).buffer;
// TODO: Remove when fixed
item._loaded.childItems = true;
@ -176,18 +176,21 @@ class ReaderInstance {
popup.addEventListener('popuphidden', function () {
popup.remove();
});
// Add to note
let menuitem = this._window.document.createElement('menuitem');
menuitem.setAttribute('label', 'Delete');
menuitem.setAttribute('label', 'Add to Note');
menuitem.addEventListener('command', () => {
let data = {
action: 'popupCmd',
cmd: 'deleteAnnotation',
cmd: 'addToNote',
id: annotationId
};
this._postMessage(data);
});
popup.appendChild(menuitem);
// Separator
popup.appendChild(this._window.document.createElement('menuseparator'));
// Colors
for (let color of colors) {
menuitem = this._window.document.createElement('menuitem');
menuitem.setAttribute('label', color[0]);
@ -204,6 +207,20 @@ class ReaderInstance {
});
popup.appendChild(menuitem);
}
// Separator
popup.appendChild(this._window.document.createElement('menuseparator'));
// Delete
menuitem = this._window.document.createElement('menuitem');
menuitem.setAttribute('label', 'Delete');
menuitem.addEventListener('command', () => {
let data = {
action: 'popupCmd',
cmd: 'deleteAnnotation',
id: annotationId
};
this._postMessage(data);
});
popup.appendChild(menuitem);
popup.openPopupAtScreen(x, y, true);
}
@ -362,6 +379,11 @@ class ReaderInstance {
Zotero.debug('Dismiss PDF annotations');
return;
}
case 'addToNote': {
let { annotations } = message;
this._addToNote(annotations);
return;
}
case 'save': {
Zotero.debug('Exporting PDF');
let zp = Zotero.getActiveZoteroPane();
@ -437,7 +459,7 @@ class ReaderInstance {
}
class ReaderTab extends ReaderInstance {
constructor() {
constructor(itemID) {
super();
this._window = Services.wm.getMostRecentWindow('navigator:browser');
let { id, container } = this._window.Zotero_Tabs.add({
@ -447,6 +469,9 @@ class ReaderTab extends ReaderInstance {
onClose: () => {
this.tabID = null;
this.close();
},
notifierData: {
itemID
}
});
this.tabID = id;
@ -500,6 +525,18 @@ class ReaderTab extends ReaderInstance {
_setTitleValue(title) {
this._window.Zotero_Tabs.rename(this.tabID, title);
}
_addToNote(annotations) {
let noteEditor = this._window.ZoteroItemPane.getActiveNote();
if (!noteEditor) {
return;
}
let editorInstance = noteEditor.getCurrentInstance();
if (editorInstance) {
editorInstance.focus();
editorInstance.insertAnnotations(annotations);
}
}
}
@ -570,16 +607,7 @@ class ReaderWindow extends ReaderInstance {
this._window.close();
}
updateTitle() {
let item = Zotero.Items.get(this._itemID);
let title = item.getField('title');
let parentItemID = item.parentItemID;
if (parentItemID) {
let parentItem = Zotero.Items.get(parentItemID);
if (parentItem) {
title = parentItem.getField('title');
}
}
_setTitleValue(title) {
this._window.document.title = title;
}
@ -733,7 +761,7 @@ class Reader {
});
}
else {
reader = new ReaderTab();
reader = new ReaderTab(itemID);
if (!(await reader.open({ itemID, location }))) {
return;
}

View file

@ -132,9 +132,9 @@ var ZoteroPane = new function()
// continue loading pane
_loadPane();
Zotero_Tabs.onTabSelect = (type) => {
Zotero_Tabs.onTabSelect = (id, type) => {
let toolbar = document.getElementById('zotero-pane-horizontal-space');
let extendedToolbar = document.getElementById('zotero-reader-toolbar-extension');
let extendedToolbar = document.getElementById('zotero-item-pane-padding-top');
let itemPane = document.getElementById('zotero-item-pane');
if (type == 'library') {
toolbar.hidden = false;
@ -150,7 +150,7 @@ var ZoteroPane = new function()
itemPane.hidden = false;
}
else {
itemPane.hidden = true;
itemPane.hidden = true;
}
}
}
@ -1421,6 +1421,8 @@ var ZoteroPane = new function()
}
_lastSelectedItems = ids;
ZoteroItemPane.togglePane(true);
var tabs = document.getElementById('zotero-view-tabbox');
// save note when switching from a note
@ -4072,7 +4074,8 @@ var ZoteroPane = new function()
if (!this.collectionsView.editable) {
continue;
}
document.getElementById('zotero-view-note-button').doCommand();
ZoteroItemPane.pinNote(item.id);
// document.getElementById('zotero-view-note-button').doCommand();
}
else if (item.isAttachment()) {
yield this.viewAttachment(item.id, event);
@ -5216,7 +5219,7 @@ var ZoteroPane = new function()
// Allow item pane to shrink to available height in stacked mode, but don't expand to be too
// wide when there's no persisted width in non-stacked mode
//itemPane.setAttribute("flex", stackedLayout ? 1 : 0);
itemPane.setAttribute("flex", stackedLayout ? 1 : 0);
this.handleTagSelectorResize();
}

View file

@ -214,6 +214,7 @@
<div xmlns="http://www.w3.org/1999/xhtml" class="sync-button-tooltip-messages"/>
</tooltip>
</toolbarbutton>
<button id="temp-toggle-1">(Slider)_______</button>
</hbox>
</toolbar>
@ -576,12 +577,9 @@
oncommand="ZoteroPane.updateToolbarPosition(); ZoteroPane.updateTagsBoxSize()">
<grippy id="zotero-items-grippy"/>
</splitter>
<vbox>
<hbox id="zotero-reader-toolbar-extension" height="32" hidden="true"></hbox>
<!-- itemPane.xul -->
<vbox id="zotero-item-pane" flex="1"/>
</vbox>
<!-- itemPane.xul -->
<vbox id="zotero-item-pane" flex="1"/>
</hbox>
</vbox>

@ -1 +1 @@
Subproject commit acd34e852d38768c8f31e59aa7238d4d934081eb
Subproject commit 3d949e7c83a19af8afdd1de0fdb3f95dde4f4dea

@ -1 +1 @@
Subproject commit 9067fc6a9245019b0a4670f8a2b5d81f9f36ad0f
Subproject commit 886e714d3344534b66370010e855ea857f460627

@ -1 +1 @@
Subproject commit 3e8ec222463b2eb05c4fecd4c43b8b629311e583
Subproject commit 156459aaf4dbba9dc91b10a4e8ecb1142e56484b