Improve the new UI:
- Revert `notesList` to standalone notes mode only - Fix splitter styling on Windows - Fix `contextPane` performance fixes - Add a customizable throttle function to `Zotero.Utilities` - Fix reader tab selection issues - Improve error handling in the new editor - Update pdf-reader and zotero-note-editor submodules - Fix contextPane child notes list - Properly notify editor about new images - Fix note title and body snippet extraction - Persist right-hand pane state when switching tab - Hopefully fix two panes visible at the same time
This commit is contained in:
parent
c6a196b999
commit
51f760fe1a
12 changed files with 211 additions and 141 deletions
|
@ -61,7 +61,9 @@
|
||||||
|
|
||||||
#zotero-collections-splitter:not([state=collapsed]),
|
#zotero-collections-splitter:not([state=collapsed]),
|
||||||
#zotero-items-splitter:not([state=collapsed]),
|
#zotero-items-splitter:not([state=collapsed]),
|
||||||
#zotero-tags-splitter:not([state=collapsed]) {
|
#zotero-tags-splitter:not([state=collapsed]),
|
||||||
|
#zotero-context-splitter:not([state=collapsed]),
|
||||||
|
#zotero-context-splitter-stacked:not([state=collapsed]) {
|
||||||
border: 0;
|
border: 0;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -70,9 +72,15 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#zotero-context-splitter:not([state=collapsed]),
|
||||||
|
#zotero-context-splitter-stacked:not([state=collapsed]) {
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
#zotero-collections-splitter:not([state=collapsed]),
|
#zotero-collections-splitter:not([state=collapsed]),
|
||||||
#zotero-items-splitter:not([state=collapsed]):not([orient=vertical]),
|
#zotero-items-splitter:not([state=collapsed]):not([orient=vertical]),
|
||||||
#zotero-tags-splitter:not([state=collapsed]) {
|
#zotero-tags-splitter:not([state=collapsed]),
|
||||||
|
#zotero-context-splitter:not([state=collapsed]) {
|
||||||
border-inline-end: 1px solid var(--theme-border-color);
|
border-inline-end: 1px solid var(--theme-border-color);
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
|
@ -80,7 +88,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#zotero-tags-splitter:not([state=collapsed]),
|
#zotero-tags-splitter:not([state=collapsed]),
|
||||||
#zotero-items-splitter:not([state=collapsed])[orient=vertical] {
|
#zotero-items-splitter:not([state=collapsed])[orient=vertical],
|
||||||
|
#zotero-context-splitter-stacked:not([state=collapsed]) {
|
||||||
border-block-end: 1px solid var(--theme-border-color);
|
border-block-end: 1px solid var(--theme-border-color);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
height: 3px;
|
height: 3px;
|
||||||
|
@ -89,13 +98,16 @@
|
||||||
|
|
||||||
#zotero-collections-splitter > grippy,
|
#zotero-collections-splitter > grippy,
|
||||||
#zotero-items-splitter > grippy,
|
#zotero-items-splitter > grippy,
|
||||||
#zotero-tags-splitter > grippy {
|
#zotero-tags-splitter > grippy,
|
||||||
|
#zotero-context-splitter > grippy {
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#zotero-collections-splitter:not([state=collapsed]) > grippy,
|
#zotero-collections-splitter:not([state=collapsed]) > grippy,
|
||||||
#zotero-items-splitter:not([state=collapsed]) > grippy,
|
#zotero-items-splitter:not([state=collapsed]) > grippy,
|
||||||
#zotero-tags-splitter:not([state=collapsed]) > grippy {
|
#zotero-tags-splitter:not([state=collapsed]) > grippy,
|
||||||
|
#zotero-context-splitter:not([state=collapsed]) > grippy,
|
||||||
|
#zotero-context-splitter-stacked:not([state=collapsed]) > grippy {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,18 +109,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.notify = async (event, type, ids, extraData) => {
|
this.notify = async (event, type, ids, extraData) => {
|
||||||
// Update citations
|
|
||||||
let uris = [];
|
|
||||||
let items = await Zotero.Items.getAsync(ids);
|
|
||||||
for (let item of items) {
|
|
||||||
let uri = Zotero.URI.getItemURI(item);
|
|
||||||
if (uri) {
|
|
||||||
uris.push(uri)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._editorInstance) {
|
if (this._editorInstance) {
|
||||||
await this._editorInstance.updateCitationsForURIs(uris);
|
await this._editorInstance.notify(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.item) return;
|
if (!this.item) return;
|
||||||
|
@ -252,15 +242,14 @@
|
||||||
<property name="linksOnTop">
|
<property name="linksOnTop">
|
||||||
<setter>
|
<setter>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
return;
|
// if (val) {
|
||||||
if (val) {
|
// var container = this._id('links-container');
|
||||||
var container = this._id('links-container');
|
// var parent = container.parentNode;
|
||||||
var parent = container.parentNode;
|
// var sib = container.nextSibling;
|
||||||
var sib = container.nextSibling;
|
// while (parent.firstChild !== container) {
|
||||||
while (parent.firstChild !== container) {
|
// parent.insertBefore(parent.removeChild(parent.firstChild), sib);
|
||||||
parent.insertBefore(parent.removeChild(parent.firstChild), sib);
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
]]>
|
]]>
|
||||||
</setter>
|
</setter>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
@ -25,18 +25,14 @@
|
||||||
|
|
||||||
import React, { forwardRef, useImperativeHandle, useState } from 'react';
|
import React, { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
|
|
||||||
const NoteRow = ({ parentTitle, parentImageSrc, title, body, date, onClick }) => {
|
const NoteRow = ({ title, body, date, onClick }) => {
|
||||||
return (
|
return (
|
||||||
<div className="note-row" onClick={onClick}>
|
<div className="note-row" onClick={onClick}>
|
||||||
<div className="inner">
|
<div className="inner">
|
||||||
{parentTitle !== null && <div className="first-line">
|
<div className="first-line">
|
||||||
<div className="icon"><img src={parentImageSrc}/></div>
|
|
||||||
<div className="title">{parentTitle}</div>
|
|
||||||
</div>}
|
|
||||||
<div className="second-line">
|
|
||||||
<div className="title">{title}</div>
|
<div className="title">{title}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="third-line">
|
<div className="second-line">
|
||||||
<div className="date">{date}</div>
|
<div className="date">{date}</div>
|
||||||
<div className="body">{body}</div>
|
<div className="body">{body}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -82,43 +82,66 @@ var ZoteroContextPane = new function () {
|
||||||
|
|
||||||
_init();
|
_init();
|
||||||
|
|
||||||
this._unregisterID = Zotero.Notifier.registerObserver(this, ['item', 'tab'], 'contextPane');
|
this._notifierID = Zotero.Notifier.registerObserver(this, ['item', 'tab'], 'contextPane');
|
||||||
window.addEventListener('resize', _update);
|
window.addEventListener('resize', _update);
|
||||||
_itemToggle.addEventListener('click', () => {
|
_itemToggle.addEventListener('click', _toggleItemButton);
|
||||||
_togglePane(0);
|
_notesToggle.addEventListener('click', _toggleNotesButton);
|
||||||
});
|
|
||||||
_notesToggle.addEventListener('click', () => {
|
|
||||||
_togglePane(1);
|
|
||||||
});
|
|
||||||
Zotero.Reader.onChangeSidebarWidth = _updatePaneWidth;
|
Zotero.Reader.onChangeSidebarWidth = _updatePaneWidth;
|
||||||
Zotero.Reader.onChangeSidebarOpen = _updatePaneWidth;
|
Zotero.Reader.onChangeSidebarOpen = _updatePaneWidth;
|
||||||
|
|
||||||
const observer = new MutationObserver(() => {
|
this._mutationObserver = new MutationObserver(() => {
|
||||||
_updateToolbarWidth();
|
_updateToolbarWidth();
|
||||||
// Sometimes XUL is late to reflow
|
// Sometimes XUL is late to reflow
|
||||||
setTimeout(_updateToolbarWidth, 100);
|
setTimeout(_updateToolbarWidth, 100);
|
||||||
});
|
});
|
||||||
observer.observe(_tabToolbarContainer, { attributes: true, childList: true, subtree: true });
|
this._mutationObserver.observe(_tabToolbarContainer, { attributes: true, childList: true, subtree: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onUnload = function () {
|
this.onUnload = function () {
|
||||||
Zotero.Notifier.unregisterObserver(this._unregisterID);
|
_itemToggle.removeEventListener('click', _toggleItemButton);
|
||||||
|
_notesToggle.removeEventListener('click', _toggleNotesButton);
|
||||||
|
window.removeEventListener('resize', _update);
|
||||||
|
Zotero.Notifier.unregisterObserver(this._notifierID);
|
||||||
|
this._mutationObserver.disconnect();
|
||||||
|
Zotero.Reader.onChangeSidebarWidth = () => {};
|
||||||
|
Zotero.Reader.onChangeSidebarOpen = () => {};
|
||||||
|
_contextPaneInner.innerHTML = '';
|
||||||
|
_itemContexts = [];
|
||||||
|
_notesContexts = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
this.notify = Zotero.Promise.coroutine(function* (action, type, ids, extraData) {
|
this.notify = Zotero.Promise.coroutine(function* (action, type, ids, extraData) {
|
||||||
if (type == 'item') {
|
if (type == 'item') {
|
||||||
// TODO: Filter library and seriously thing about the performance of this part
|
// Update, remove or re-create item panes
|
||||||
for (let context of _itemContexts) {
|
for (let context of _itemContexts.slice()) {
|
||||||
let item = Zotero.Items.get(context.itemID);
|
let item = Zotero.Items.get(context.itemID);
|
||||||
if (item && item.parentID != context.parentID) {
|
if (!item) {
|
||||||
|
_removeItemContext(context.tabID);
|
||||||
|
}
|
||||||
|
else if (item.parentID != context.parentID) {
|
||||||
_removeItemContext(context.tabID);
|
_removeItemContext(context.tabID);
|
||||||
_addItemContext(context.tabID, context.itemID);
|
_addItemContext(context.tabID, context.itemID);
|
||||||
}
|
}
|
||||||
context.update();
|
else {
|
||||||
|
context.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update notes lists for affected libraries
|
||||||
|
let libraryIDs = [];
|
||||||
|
for (let id of ids) {
|
||||||
|
let item = Zotero.Items.get(id);
|
||||||
|
if (item && item.isNote()) {
|
||||||
|
libraryIDs.push(item.libraryID);
|
||||||
|
}
|
||||||
|
else if (action == 'delete') {
|
||||||
|
libraryIDs.push(extraData[id].libraryID);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (let context of _notesContexts) {
|
for (let context of _notesContexts) {
|
||||||
context.updateNotesList();
|
if (libraryIDs.includes(context.libraryID)) {
|
||||||
|
context.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type == 'tab') {
|
else if (type == 'tab') {
|
||||||
|
@ -157,11 +180,19 @@ var ZoteroContextPane = new function () {
|
||||||
if (context) {
|
if (context) {
|
||||||
_selectNotesContext(context.libraryID);
|
_selectNotesContext(context.libraryID);
|
||||||
}
|
}
|
||||||
_selectItemContext(ids[0], extraData[ids[0]].type);
|
_selectItemContext(ids[0]);
|
||||||
_update();
|
_update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function _toggleItemButton() {
|
||||||
|
_togglePane(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _toggleNotesButton() {
|
||||||
|
_togglePane(1);
|
||||||
|
}
|
||||||
|
|
||||||
function _removeNote(id) {
|
function _removeNote(id) {
|
||||||
var ps = Components.classes['@mozilla.org/embedcomp/prompt-service;1']
|
var ps = Components.classes['@mozilla.org/embedcomp/prompt-service;1']
|
||||||
|
@ -183,11 +214,13 @@ var ZoteroContextPane = new function () {
|
||||||
if (splitter.getAttribute('state') != 'collapsed') {
|
if (splitter.getAttribute('state') != 'collapsed') {
|
||||||
if (_panesDeck.selectedIndex == 0) {
|
if (_panesDeck.selectedIndex == 0) {
|
||||||
let child = _itemPaneDeck.selectedPanel;
|
let child = _itemPaneDeck.selectedPanel;
|
||||||
var tabPanels = child.querySelector('tabpanels');
|
if (child) {
|
||||||
if (tabPanels && tabPanels.selectedIndex == 1) {
|
var tabPanels = child.querySelector('tabpanels');
|
||||||
var notesDeck = child.querySelector('.notes-deck');
|
if (tabPanels && tabPanels.selectedIndex == 1) {
|
||||||
if (notesDeck.selectedIndex == 1) {
|
var notesDeck = child.querySelector('.notes-deck');
|
||||||
return child.querySelector('zoteronoteeditor');
|
if (notesDeck.selectedIndex == 1) {
|
||||||
|
return child.querySelector('zoteronoteeditor');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,29 +319,18 @@ var ZoteroContextPane = new function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function _togglePane(paneIndex) {
|
function _togglePane(paneIndex) {
|
||||||
var splitter;
|
var splitter = Zotero.Prefs.get('layout') == 'stacked'
|
||||||
var stacked = Zotero.Prefs.get('layout') == 'stacked';
|
? _contextPaneSplitterStacked : _contextPaneSplitter;
|
||||||
if (stacked) {
|
|
||||||
splitter = _contextPaneSplitterStacked;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
splitter = _contextPaneSplitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
var isOpen = splitter.getAttribute('state') != 'collapsed';
|
var isOpen = splitter.getAttribute('state') != 'collapsed';
|
||||||
var hide = false;
|
var hide = false;
|
||||||
|
|
||||||
var currentPane = _panesDeck.selectedIndex;
|
var currentPane = _panesDeck.selectedIndex;
|
||||||
|
|
||||||
if (isOpen && currentPane == paneIndex) {
|
if (isOpen && currentPane == paneIndex) {
|
||||||
hide = true;
|
hide = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_panesDeck.setAttribute('selectedIndex', paneIndex);
|
_panesDeck.setAttribute('selectedIndex', paneIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
var context = _itemContexts.find(x => x.tabID == Zotero_Tabs.selectedID);
|
|
||||||
context.selectedIndex = paneIndex;
|
|
||||||
|
|
||||||
splitter.setAttribute('state', hide ? 'collapsed' : 'open');
|
splitter.setAttribute('state', hide ? 'collapsed' : 'open');
|
||||||
_update();
|
_update();
|
||||||
|
@ -371,7 +393,7 @@ var ZoteroContextPane = new function () {
|
||||||
|
|
||||||
var label = document.createElement('label');
|
var label = document.createElement('label');
|
||||||
var button = document.createElement('button');
|
var button = document.createElement('button');
|
||||||
button.setAttribute('label', Zotero.Intl.strings['zotero.item.add']);
|
button.setAttribute('label', Zotero.Intl.strings['zotero.toolbar.newNote']);
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
contextNode.setAttribute('selectedIndex', 1);
|
contextNode.setAttribute('selectedIndex', 1);
|
||||||
var item = new Zotero.Item('note');
|
var item = new Zotero.Item('note');
|
||||||
|
@ -394,7 +416,7 @@ var ZoteroContextPane = new function () {
|
||||||
input.setAttribute('type', 'search');
|
input.setAttribute('type', 'search');
|
||||||
input.setAttribute('timeout', '250');
|
input.setAttribute('timeout', '250');
|
||||||
input.addEventListener('command', () => {
|
input.addEventListener('command', () => {
|
||||||
updateNotesList();
|
_updateNotesList();
|
||||||
});
|
});
|
||||||
vbox2.append(input);
|
vbox2.append(input);
|
||||||
|
|
||||||
|
@ -411,20 +433,20 @@ var ZoteroContextPane = new function () {
|
||||||
|
|
||||||
var notesListRef = React.createRef();
|
var notesListRef = React.createRef();
|
||||||
|
|
||||||
var updateNotesList = async (reset) => {
|
async function _updateNotesList(reset) {
|
||||||
if (reset) {
|
if (reset) {
|
||||||
input.value = '';
|
input.value = '';
|
||||||
contextNode.setAttribute('selectedIndex', 0);
|
contextNode.setAttribute('selectedIndex', 0);
|
||||||
}
|
}
|
||||||
var text = input.value;
|
var query = input.value;
|
||||||
|
|
||||||
await Zotero.Schema.schemaUpdatePromise;
|
await Zotero.Schema.schemaUpdatePromise;
|
||||||
var s = new Zotero.Search();
|
var s = new Zotero.Search();
|
||||||
s.addCondition('libraryID', 'is', libraryID);
|
s.addCondition('libraryID', 'is', libraryID);
|
||||||
s.addCondition('itemType', 'is', 'note');
|
s.addCondition('itemType', 'is', 'note');
|
||||||
s.addCondition('noChildren', 'false');
|
s.addCondition('noChildren', 'true');
|
||||||
if (text) {
|
if (query) {
|
||||||
s.addCondition('note', 'contains', text, true);
|
s.addCondition('note', 'contains', query, true);
|
||||||
}
|
}
|
||||||
var notes = await s.search();
|
var notes = await s.search();
|
||||||
notes = Zotero.Items.get(notes);
|
notes = Zotero.Items.get(notes);
|
||||||
|
@ -435,20 +457,15 @@ var ZoteroContextPane = new function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
notesListRef.current.setNotes(notes.map(note => {
|
notesListRef.current.setNotes(notes.map(note => {
|
||||||
var text2 = note.note.slice(0, 500);
|
var text = note.note;
|
||||||
text2 = text2.trim();
|
text = Zotero.Utilities.unescapeHTML(text);
|
||||||
// TODO: Fix a potential performance issuse
|
text = text.trim();
|
||||||
text2 = Zotero.Utilities.unescapeHTML(text2);
|
text = text.slice(0, 500);
|
||||||
var parts = text2.split('\n').map(x => x.trim()).filter(x => x.length);
|
var parts = text.split('\n').map(x => x.trim()).filter(x => x.length);
|
||||||
var parent = null;
|
var title = parts[0] && parts[0].slice(0, Zotero.Notes.MAX_TITLE_LENGTH);
|
||||||
if (note.parentID) {
|
|
||||||
parent = Zotero.Items.get(note.parentID);
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
id: note.id,
|
id: note.id,
|
||||||
parentTitle: parent && parent.getDisplayTitle(),
|
title: title || Zotero.getString('pane.item.notes.untitled'),
|
||||||
parentImageSrc: parent && parent.getImageSrc(),
|
|
||||||
title: parts[0] || Zotero.getString('pane.item.notes.untitled'),
|
|
||||||
body: parts[1] || '',
|
body: parts[1] || '',
|
||||||
date: (new Date(note.dateModified).toLocaleDateString(Zotero.locale))
|
date: (new Date(note.dateModified).toLocaleDateString(Zotero.locale))
|
||||||
};
|
};
|
||||||
|
@ -468,14 +485,14 @@ var ZoteroContextPane = new function () {
|
||||||
/>,
|
/>,
|
||||||
listInner,
|
listInner,
|
||||||
() => {
|
() => {
|
||||||
updateNotesList();
|
_updateNotesList();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
var context = {
|
var context = {
|
||||||
libraryID,
|
libraryID,
|
||||||
node: contextNode,
|
node: contextNode,
|
||||||
updateNotesList,
|
update: Zotero.Utilities.throttle(_updateNotesList, 1000, { leading: false }),
|
||||||
editor
|
editor
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -503,7 +520,7 @@ var ZoteroContextPane = new function () {
|
||||||
_notesContexts = _notesContexts.filter(x => x.libraryID != libraryID);
|
_notesContexts = _notesContexts.filter(x => x.libraryID != libraryID);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _libraryEditable(libraryID) {
|
function _isLibraryEditable(libraryID) {
|
||||||
var type = Zotero.Libraries.get(libraryID).libraryType;
|
var type = Zotero.Libraries.get(libraryID).libraryType;
|
||||||
if (type == 'group') {
|
if (type == 'group') {
|
||||||
var groupID = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
|
var groupID = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
|
||||||
|
@ -514,7 +531,7 @@ var ZoteroContextPane = new function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function _setPinnedNote(libraryID, itemID) {
|
function _setPinnedNote(libraryID, itemID) {
|
||||||
var editable = _libraryEditable(libraryID);
|
var editable = _isLibraryEditable(libraryID);
|
||||||
var context = _getNotesContext(libraryID);
|
var context = _getNotesContext(libraryID);
|
||||||
if (context) {
|
if (context) {
|
||||||
let { editor, node } = context;
|
let { editor, node } = context;
|
||||||
|
@ -530,7 +547,7 @@ var ZoteroContextPane = new function () {
|
||||||
function _appendNoteRows(notes, list, editable, onClick, onDelete) {
|
function _appendNoteRows(notes, list, editable, onClick, onDelete) {
|
||||||
for (var i = 0; i < notes.length; i++) {
|
for (var i = 0; i < notes.length; i++) {
|
||||||
var note = notes[i];
|
var note = notes[i];
|
||||||
var id = notes[i].id;
|
let id = notes[i].id;
|
||||||
|
|
||||||
var icon = document.createElement('image');
|
var icon = document.createElement('image');
|
||||||
icon.className = 'zotero-box-icon';
|
icon.className = 'zotero-box-icon';
|
||||||
|
@ -551,7 +568,9 @@ var ZoteroContextPane = new function () {
|
||||||
});
|
});
|
||||||
box.appendChild(icon);
|
box.appendChild(icon);
|
||||||
box.appendChild(label);
|
box.appendChild(label);
|
||||||
|
|
||||||
|
var row = document.createElement('row');
|
||||||
|
row.appendChild(box);
|
||||||
if (editable) {
|
if (editable) {
|
||||||
var removeButton = document.createElement('label');
|
var removeButton = document.createElement('label');
|
||||||
removeButton.setAttribute('value', '-');
|
removeButton.setAttribute('value', '-');
|
||||||
|
@ -559,11 +578,6 @@ var ZoteroContextPane = new function () {
|
||||||
removeButton.addEventListener('click', function () {
|
removeButton.addEventListener('click', function () {
|
||||||
onDelete(id);
|
onDelete(id);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
var row = document.createElement('row');
|
|
||||||
row.appendChild(box);
|
|
||||||
if (editable) {
|
|
||||||
row.appendChild(removeButton);
|
row.appendChild(removeButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,34 +590,32 @@ var ZoteroContextPane = new function () {
|
||||||
_itemContexts = _itemContexts.filter(x => x.tabID != tabID);
|
_itemContexts = _itemContexts.filter(x => x.tabID != tabID);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _selectItemContext(tabID, type) {
|
function _selectItemContext(tabID) {
|
||||||
let selectedIndex = Array.from(_itemPaneDeck.children).findIndex(x => x.id == tabID + '-context');
|
let selectedIndex = Array.from(_itemPaneDeck.children).findIndex(x => x.id == tabID + '-context');
|
||||||
if (selectedIndex != -1) {
|
if (selectedIndex != -1) {
|
||||||
_itemPaneDeck.setAttribute('selectedIndex', selectedIndex);
|
_itemPaneDeck.setAttribute('selectedIndex', selectedIndex);
|
||||||
var context = _itemContexts.find(x => x.tabID == tabID);
|
|
||||||
if (context && Zotero_Tabs.selectedIndex > 0) {
|
|
||||||
_panesDeck.setAttribute('selectedIndex', context.selectedIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _addItemContext(tabID, itemID) {
|
function _addItemContext(tabID, itemID) {
|
||||||
|
var item = Zotero.Items.get(itemID);
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var libraryID = item.libraryID;
|
||||||
|
var editable = _isLibraryEditable(libraryID);
|
||||||
|
var parentID = item.parentID;
|
||||||
|
|
||||||
var container = document.createElement('vbox');
|
var container = document.createElement('vbox');
|
||||||
container.id = tabID + '-context';
|
container.id = tabID + '-context';
|
||||||
container.className = 'zotero-item-pane-content';
|
container.className = 'zotero-item-pane-content';
|
||||||
_itemPaneDeck.appendChild(container);
|
_itemPaneDeck.appendChild(container);
|
||||||
|
|
||||||
var item = Zotero.Items.get(itemID);
|
|
||||||
var libraryID = item.libraryID;
|
|
||||||
var editable = _libraryEditable(libraryID);
|
|
||||||
var parentID = item.parentID;
|
|
||||||
|
|
||||||
var context = {
|
var context = {
|
||||||
tabID,
|
tabID,
|
||||||
itemID,
|
itemID,
|
||||||
parentID,
|
parentID,
|
||||||
libraryID,
|
libraryID,
|
||||||
selectedIndex: 0,
|
|
||||||
update: () => {}
|
update: () => {}
|
||||||
};
|
};
|
||||||
_itemContexts.push(context);
|
_itemContexts.push(context);
|
||||||
|
@ -619,7 +631,6 @@ var ZoteroContextPane = new function () {
|
||||||
container.append(vbox);
|
container.append(vbox);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parentItem = Zotero.Items.get(item.parentID);
|
var parentItem = Zotero.Items.get(item.parentID);
|
||||||
|
|
||||||
// tabbox
|
// tabbox
|
||||||
|
@ -685,7 +696,6 @@ var ZoteroContextPane = new function () {
|
||||||
hbox.setAttribute('align', 'center');
|
hbox.setAttribute('align', 'center');
|
||||||
var label = document.createElement('label');
|
var label = document.createElement('label');
|
||||||
var button = document.createElement('button');
|
var button = document.createElement('button');
|
||||||
// TODO: Should not depend on the current ZoteroPane state
|
|
||||||
button.hidden = !editable;
|
button.hidden = !editable;
|
||||||
button.setAttribute('label', Zotero.Intl.strings['zotero.item.add']);
|
button.setAttribute('label', Zotero.Intl.strings['zotero.item.add']);
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
|
@ -763,6 +773,10 @@ var ZoteroContextPane = new function () {
|
||||||
|
|
||||||
function _renderNotesPanel() {
|
function _renderNotesPanel() {
|
||||||
rows.innerHTML = '';
|
rows.innerHTML = '';
|
||||||
|
var parentItem = Zotero.Items.get(parentID);
|
||||||
|
if (!parentItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var parentNotes = Zotero.Items.get(parentItem.getNotes());
|
var parentNotes = Zotero.Items.get(parentItem.getNotes());
|
||||||
_appendNoteRows(parentNotes, rows, editable, (id) => {
|
_appendNoteRows(parentNotes, rows, editable, (id) => {
|
||||||
deck.setAttribute('selectedIndex', 1);
|
deck.setAttribute('selectedIndex', 1);
|
||||||
|
@ -782,7 +796,7 @@ var ZoteroContextPane = new function () {
|
||||||
label.value = Zotero.getString(str, [c]);
|
label.value = Zotero.getString(str, [c]);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.update = _renderNotesPanel;
|
context.update = Zotero.Utilities.throttle(_renderNotesPanel, 500);
|
||||||
_renderNotesPanel();
|
_renderNotesPanel();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -113,7 +113,7 @@ var Zotero_Tabs = new function () {
|
||||||
index = index || this._tabs.length;
|
index = index || this._tabs.length;
|
||||||
this._tabs.splice(index, 0, tab);
|
this._tabs.splice(index, 0, tab);
|
||||||
this._update();
|
this._update();
|
||||||
Zotero.Notifier.trigger('add', 'tab', [id], { [id]: notifierData });
|
Zotero.Notifier.trigger('add', 'tab', [id], { [id]: notifierData }, true);
|
||||||
if (select) {
|
if (select) {
|
||||||
this.select(id);
|
this.select(id);
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ var Zotero_Tabs = new function () {
|
||||||
if (tab.onClose) {
|
if (tab.onClose) {
|
||||||
tab.onClose();
|
tab.onClose();
|
||||||
}
|
}
|
||||||
Zotero.Notifier.trigger('close', 'tab', [tab.id]);
|
Zotero.Notifier.trigger('close', 'tab', [tab.id], true);
|
||||||
this._update();
|
this._update();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ var Zotero_Tabs = new function () {
|
||||||
this._selectedID = id;
|
this._selectedID = id;
|
||||||
this.deck.selectedIndex = Array.from(this.deck.children).findIndex(x => x.id == id);
|
this.deck.selectedIndex = Array.from(this.deck.children).findIndex(x => x.id == id);
|
||||||
this._update();
|
this._update();
|
||||||
Zotero.Notifier.trigger('select', 'tab', [tab.id], { [tab.id]: { type: tab.type } });
|
Zotero.Notifier.trigger('select', 'tab', [tab.id], { [tab.id]: { type: tab.type } }, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -101,11 +101,28 @@ class EditorInstance {
|
||||||
async updateCitationsForURIs(uris) {
|
async updateCitationsForURIs(uris) {
|
||||||
let subscriptions = this._subscriptions
|
let subscriptions = this._subscriptions
|
||||||
.filter(s => s.data.citation && s.data.citation.citationItems
|
.filter(s => s.data.citation && s.data.citation.citationItems
|
||||||
.some(citationItem => uris.some(uri => citationItem.uris.includes(uri))));
|
.some(citationItem => citationItem.uris && uris.some(uri => citationItem.uris.includes(uri))));
|
||||||
for (let subscription of subscriptions) {
|
for (let subscription of subscriptions) {
|
||||||
await this._feedSubscription(subscription);
|
await this._feedSubscription(subscription);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async notify(ids) {
|
||||||
|
let items = await Zotero.Items.getAsync(ids);
|
||||||
|
|
||||||
|
// Update attachments
|
||||||
|
let keys = items.map(item => item.key);
|
||||||
|
this._subscriptions
|
||||||
|
.filter(s => keys.includes(s.data.attachmentKey))
|
||||||
|
.forEach(s => this._feedSubscription(s));
|
||||||
|
|
||||||
|
// Update citations
|
||||||
|
let uris = items.map(x => Zotero.URI.getItemURI(x)).filter(x => x);
|
||||||
|
this._subscriptions
|
||||||
|
.filter(s => s.data.citation && s.data.citation.citationItems
|
||||||
|
.some(citationItem => citationItem.uris && uris.some(uri => citationItem.uris.includes(uri))))
|
||||||
|
.forEach(s => this._feedSubscription(s));
|
||||||
|
}
|
||||||
|
|
||||||
saveSync() {
|
saveSync() {
|
||||||
if (!this._readOnly && !this._disableSaving && this._iframeWindow) {
|
if (!this._readOnly && !this._disableSaving && this._iframeWindow) {
|
||||||
|
@ -600,6 +617,9 @@ class EditorInstance {
|
||||||
async _getFormattedCitationParts(citation) {
|
async _getFormattedCitationParts(citation) {
|
||||||
let formattedItems = [];
|
let formattedItems = [];
|
||||||
for (let citationItem of citation.citationItems) {
|
for (let citationItem of citation.citationItems) {
|
||||||
|
if (!Array.isArray(citationItem.uris)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let item = await this._getItemFromURIs(citationItem.uris);
|
let item = await this._getItemFromURIs(citationItem.uris);
|
||||||
if (!item && citationItem.itemData) {
|
if (!item && citationItem.itemData) {
|
||||||
item = new Zotero.Item();
|
item = new Zotero.Item();
|
||||||
|
|
|
@ -755,6 +755,10 @@ class Reader {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reader) {
|
if (reader) {
|
||||||
|
if (reader instanceof ReaderTab) {
|
||||||
|
reader._window.Zotero_Tabs.select(reader.tabID);
|
||||||
|
}
|
||||||
|
|
||||||
if (location) {
|
if (location) {
|
||||||
reader.navigate(location);
|
reader.navigate(location);
|
||||||
}
|
}
|
||||||
|
@ -806,9 +810,6 @@ class Reader {
|
||||||
if (reader instanceof ReaderWindow) {
|
if (reader instanceof ReaderWindow) {
|
||||||
reader._window.focus();
|
reader._window.focus();
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
reader._window.Zotero_Tabs.select(reader.tabID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async triggerAnnotationsImportCheck(itemID) {
|
async triggerAnnotationsImportCheck(itemID) {
|
||||||
|
|
|
@ -49,6 +49,62 @@ Zotero.Utilities = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a new, throttled version of the
|
||||||
|
* passed function, that, when invoked repeatedly,
|
||||||
|
* will only actually call the original function at most
|
||||||
|
* once per every wait milliseconds
|
||||||
|
*
|
||||||
|
* By default, throttle will execute the function as soon
|
||||||
|
* as you call it for the first time, and, if you call it
|
||||||
|
* again any number of times during the wait period, as soon
|
||||||
|
* as that period is over. If you'd like to disable the
|
||||||
|
* leading-edge call, pass {leading: false}, and if you'd
|
||||||
|
* like to disable the execution on the trailing-edge,
|
||||||
|
* pass {trailing: false}. See
|
||||||
|
* https://underscorejs.org/#throttle
|
||||||
|
* https://github.com/jashkenas/underscore/blob/master/underscore.js
|
||||||
|
* (c) 2009-2018 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||||
|
* Underscore may be freely distributed under the MIT license.
|
||||||
|
*
|
||||||
|
* @param {Function} func Function to throttle
|
||||||
|
* @param {Integer} wait Wait period in milliseconds
|
||||||
|
* @param {Boolean} [options.leading] Call at the beginning of the wait period
|
||||||
|
* @param {Boolean} [options.trailing] Call at the end of the wait period
|
||||||
|
*/
|
||||||
|
throttle: function (func, wait, options) {
|
||||||
|
var context, args, result;
|
||||||
|
var timeout = null;
|
||||||
|
var previous = 0;
|
||||||
|
if (!options) options = {};
|
||||||
|
var later = function () {
|
||||||
|
previous = options.leading === false ? 0 : Date.now();
|
||||||
|
timeout = null;
|
||||||
|
result = func.apply(context, args);
|
||||||
|
if (!timeout) context = args = null;
|
||||||
|
};
|
||||||
|
return function () {
|
||||||
|
var now = Date.now();
|
||||||
|
if (!previous && options.leading === false) previous = now;
|
||||||
|
var remaining = wait - (now - previous);
|
||||||
|
context = this;
|
||||||
|
args = arguments;
|
||||||
|
if (remaining <= 0 || remaining > wait) {
|
||||||
|
if (timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = null;
|
||||||
|
}
|
||||||
|
previous = now;
|
||||||
|
result = func.apply(context, args);
|
||||||
|
if (!timeout) context = args = null;
|
||||||
|
}
|
||||||
|
else if (!timeout && options.trailing !== false) {
|
||||||
|
timeout = setTimeout(later, remaining);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixes author name capitalization.
|
* Fixes author name capitalization.
|
||||||
* Currently for all uppercase names only
|
* Currently for all uppercase names only
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#zotero-context-pane {
|
#zotero-context-pane {
|
||||||
min-width: 300px;
|
min-width: 360px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#zotero-context-pane.stacked {
|
#zotero-context-pane.stacked {
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
background: linear-gradient(to top, #aeaeae 0, #aeaeae 1px, #d3d3d3 1px, #e3e3e3 100%);
|
background: linear-gradient(to top, #a9a9a9 0, #a9a9a9 1px, #f6f6f6 1px, #f6f6f6 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
#zotero-tab-toolbar-container #zotero-tb-locate,
|
#zotero-tab-toolbar-container #zotero-tb-locate,
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
opacity: 0.99;
|
opacity: 0.99;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-inline-start: -5px;
|
margin-inline-start: -5px;
|
||||||
background: linear-gradient(to top, #aeaeae 0, #aeaeae 1px, #d3d3d3 1px, #e3e3e3 100%);
|
background: linear-gradient(to top, #a9a9a9 0, #a9a9a9 1px, #f6f6f6 1px, #f6f6f6 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.zotero-context-notes-list {
|
.zotero-context-notes-list {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit be1fa9a77fb9090a1aad9a9cd40b8ebb22ee4281
|
Subproject commit 7595b7d83720941812a531b9a547deac626b24bc
|
|
@ -31,24 +31,6 @@
|
||||||
.first-line {
|
.first-line {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
.icon {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
flex-grow: 1;
|
|
||||||
width: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.second-line {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
width: 0;
|
width: 0;
|
||||||
|
@ -59,7 +41,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.third-line {
|
.second-line {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit a271598218fa8f52cd6d571d5c1b28e913803409
|
Subproject commit db2bfc6cbb724dbb1a22bafc324357a1bd61c3b1
|
Loading…
Reference in a new issue