Improve the new UI:
- Rollback all redundant changes made in the last few months - Introduce `contextPane` - Show child notes in the notes pane - Fix splitter styling - Various bug fixes - Fix contextPane switching and states persistence - Persist reader sidebar open/close state - Fix bottom pane placeholder updating concurrency issues - Fix toolbar placeholder width updating - Display titles for split button - Fix toolbar position when switching tabs - Add PDF tab loading cover - Improve notes and citations insertion - Clean up and refactor code - Fixes and cleanups to PDF reader
6
.gitmodules
vendored
|
@ -31,13 +31,13 @@
|
|||
url = https://github.com/gildas-lormeau/SingleFile.git
|
||||
[submodule "pdf-reader"]
|
||||
path = pdf-reader
|
||||
url = https://github.com/zotero/pdf-reader.git
|
||||
url = ssh://git@github.com/zotero/pdf-reader.git
|
||||
branch = master
|
||||
[submodule "pdf-worker"]
|
||||
path = pdf-worker
|
||||
url = https://github.com/zotero/pdf-worker.git
|
||||
url = ssh://git@github.com/zotero/pdf-worker.git
|
||||
branch = master
|
||||
[submodule "zotero-note-editor"]
|
||||
path = zotero-note-editor
|
||||
url = https://github.com/zotero/zotero-note-editor.git
|
||||
url = ssh://git@github.com/zotero/zotero-note-editor.git
|
||||
branch = master
|
||||
|
|
|
@ -129,7 +129,7 @@ input {
|
|||
|
||||
.zotero-editpane-tabs {
|
||||
-moz-appearance: none;
|
||||
/*background: -moz-linear-gradient(top, #ededed, #cccccc);*/
|
||||
background: -moz-linear-gradient(top, #ededed, #cccccc);
|
||||
border-style: solid;
|
||||
border-width: 0 0 1px 0;
|
||||
border-color: #bdbdbd;
|
||||
|
@ -217,7 +217,8 @@ input {
|
|||
}
|
||||
|
||||
#zotero-collections-splitter:not([state=collapsed]),
|
||||
#zotero-items-splitter:not([state=collapsed])[orient=horizontal]
|
||||
#zotero-items-splitter:not([state=collapsed])[orient=horizontal],
|
||||
#zotero-context-splitter:not([state=collapsed])[orient=horizontal]
|
||||
{
|
||||
-moz-appearance: none;
|
||||
border-inline-start: 1px solid #bdbdbd;
|
||||
|
@ -228,7 +229,8 @@ input {
|
|||
background-image: none;
|
||||
}
|
||||
|
||||
#zotero-items-splitter[orient=vertical]
|
||||
#zotero-items-splitter[orient=vertical],
|
||||
#zotero-context-splitter-stacked
|
||||
{
|
||||
-moz-border-start: none !important;
|
||||
-moz-border-end: none !important;
|
||||
|
@ -239,17 +241,25 @@ input {
|
|||
}
|
||||
|
||||
#zotero-collections-splitter:not([state=collapsed]) > grippy,
|
||||
#zotero-items-splitter:not([state=collapsed]) > grippy
|
||||
#zotero-items-splitter:not([state=collapsed]) > grippy,
|
||||
#zotero-context-splitter:not([state=collapsed]) > grippy,
|
||||
#zotero-context-splitter-stacked:not([state=collapsed]) > grippy
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#zotero-collections-splitter[state=collapsed], #zotero-items-splitter[state=collapsed] {
|
||||
#zotero-collections-splitter[state=collapsed],
|
||||
#zotero-items-splitter[state=collapsed],
|
||||
#zotero-context-splitter[state=collapsed],
|
||||
#zotero-context-splitter-stacked[state=collapsed]
|
||||
{
|
||||
border: 0 solid #d6d6d6 !important;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#zotero-collections-splitter[state=collapsed], #zotero-items-splitter[state=collapsed][orient=horizontal]
|
||||
#zotero-collections-splitter[state=collapsed],
|
||||
#zotero-items-splitter[state=collapsed][orient=horizontal],
|
||||
#zotero-context-splitter[state=collapsed][orient=horizontal]
|
||||
{
|
||||
background-image: url("chrome://zotero/skin/mac/vsplitter.png");
|
||||
background-repeat: repeat-y;
|
||||
|
@ -258,7 +268,8 @@ input {
|
|||
width: 8px !important;
|
||||
}
|
||||
|
||||
#zotero-items-splitter[state=collapsed][orient=vertical]
|
||||
#zotero-items-splitter[state=collapsed][orient=vertical],
|
||||
#zotero-context-splitter-stacked[state=collapsed][orient=vertical]
|
||||
{
|
||||
background-image: url("chrome://zotero/skin/mac/hsplitter.png");
|
||||
background-repeat: repeat-x;
|
||||
|
@ -271,11 +282,17 @@ input {
|
|||
border-right-width: 1px !important;
|
||||
}
|
||||
|
||||
#zotero-items-splitter[state=collapsed] {
|
||||
#zotero-items-splitter[state=collapsed],
|
||||
#zotero-context-splitter[state=collapsed],
|
||||
#zotero-context-splitter-stacked[state=collapsed]
|
||||
{
|
||||
border-left-width: 1px !important;
|
||||
}
|
||||
|
||||
#zotero-collections-splitter[state=collapsed] > grippy, #zotero-items-splitter[state=collapsed] > grippy
|
||||
#zotero-collections-splitter[state=collapsed] > grippy,
|
||||
#zotero-items-splitter[state=collapsed] > grippy,
|
||||
#zotero-context-splitter[state=collapsed] > grippy,
|
||||
#zotero-context-splitter-stacked[state=collapsed] > grippy
|
||||
{
|
||||
-moz-appearance: none;
|
||||
background: url(chrome://zotero/skin/mac/vgrippy.png) center/auto 8px no-repeat;
|
||||
|
@ -301,11 +318,20 @@ input {
|
|||
height: 8px;
|
||||
}
|
||||
|
||||
#zotero-tags-splitter > grippy:hover, #zotero-collections-splitter > grippy:hover, #zotero-items-splitter > grippy:hover
|
||||
#zotero-tags-splitter > grippy:hover,
|
||||
#zotero-collections-splitter > grippy:hover,
|
||||
#zotero-items-splitter > grippy:hover,
|
||||
#zotero-context-splitter > grippy:hover,
|
||||
#zotero-context-splitter-stacked > grippy:hover
|
||||
{
|
||||
background-color:transparent;
|
||||
}
|
||||
|
||||
#zotero-context-toolbar-extension {
|
||||
/* To cover #zotero-context-splitter 1px border */
|
||||
margin-inline-start: -1px;
|
||||
}
|
||||
|
||||
#zotero-items-tree
|
||||
{
|
||||
-moz-appearance: none;
|
||||
|
|
|
@ -76,3 +76,9 @@ tab {
|
|||
background-color: transparent;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
#zotero-context-splitter-stacked {
|
||||
-moz-appearance: none;
|
||||
background-color: #ececec;
|
||||
border-top: 1px solid hsla(0, 0%, 0%, 0.2);
|
||||
}
|
||||
|
|
|
@ -42,15 +42,19 @@
|
|||
<field name="displayTags">false</field>
|
||||
<field name="displayRelated">false</field>
|
||||
<field name="displayButton">false</field>
|
||||
|
||||
<field name="hideLinksContainer"/>
|
||||
|
||||
<field name="buttonCaption"/>
|
||||
<field name="parentClickHandler"/>
|
||||
<field name="keyDownHandler"/>
|
||||
<field name="commandHandler"/>
|
||||
<field name="clickHandler"/>
|
||||
<field name="navigateHandler"/>
|
||||
|
||||
<field name="returnHandler"/>
|
||||
|
||||
<constructor><![CDATA[
|
||||
this._destroyed = false;
|
||||
this._noteEditorID = Zotero.Utilities.randomString();
|
||||
this._iframe = document.getAnonymousElementByAttribute(this, 'anonid', 'editor-view');
|
||||
this._iframe.addEventListener('DOMContentLoaded', (e) => {
|
||||
|
@ -99,6 +103,7 @@
|
|||
popup: document.getAnonymousElementByAttribute(this, 'anonid', 'editor-menu'),
|
||||
onNavigate: this._navigateHandler,
|
||||
readOnly: !this.editable,
|
||||
onReturn: this._returnHandler,
|
||||
placeholder: this.placeholder
|
||||
});
|
||||
}
|
||||
|
@ -137,7 +142,7 @@
|
|||
this._lastHtmlValue = this.item.note;
|
||||
}
|
||||
|
||||
this._id('links-container').hidden = !(this.displayTags && this.displayRelated);
|
||||
this._id('links-container').hidden = !(this.displayTags && this.displayRelated) || this._hideLinksContainer;
|
||||
this._id('links-box').refresh();
|
||||
}
|
||||
|
||||
|
@ -179,12 +184,21 @@
|
|||
this._mode = val;
|
||||
document.getAnonymousNodes(this)[0].setAttribute('mode', val);
|
||||
this._id('links-box').mode = val;
|
||||
this._id('links-container').hidden = !(this.displayTags && this.displayRelated);
|
||||
this._id('links-container').hidden = !(this.displayTags && this.displayRelated) || this._hideLinksContainer;
|
||||
this._id('links-box').refresh();
|
||||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
||||
<field name="returnHandler"/>
|
||||
<property name="returnHandler" onget="return this._returnHandler;">
|
||||
<setter>
|
||||
<![CDATA[
|
||||
this._returnHandler = val;
|
||||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
||||
<field name="_parentItem"/>
|
||||
<property name="parentItem" onget="return this._parentItem;">
|
||||
<setter>
|
||||
|
@ -261,6 +275,15 @@
|
|||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
||||
<property name="hideLinksContainer">
|
||||
<setter>
|
||||
<![CDATA[
|
||||
this._hideLinksContainer = val;
|
||||
this._id('links-container').hidden = val;
|
||||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
||||
<field name="collection"/>
|
||||
|
||||
|
@ -271,6 +294,8 @@
|
|||
this._editorInstance.uninit();
|
||||
}
|
||||
this._destroyed = true;
|
||||
this._initialized = false;
|
||||
this._editorInstance = null;
|
||||
]]>
|
||||
</destructor>
|
||||
|
||||
|
@ -307,8 +332,8 @@
|
|||
</implementation>
|
||||
|
||||
<content>
|
||||
<xul:vbox xbl:inherits="flex">
|
||||
<xul:iframe tooltip="editor-tooltip" anonid="editor-view" flex="1" overflow="auto" style="width: 100%;margin-right: 5px;border: 0"
|
||||
<xul:vbox xbl:inherits="flex" style="display: flex;flex-direction: column;flex-grow: 1;">
|
||||
<xul:iframe tooltip="editor-tooltip" anonid="editor-view" flex="1" overflow="auto" style="width: 100%;margin-right: 5px;border: 0;width: 100%;margin-right: 5px;border: 0;flex-grow: 1;"
|
||||
frameBorder="0" src="resource://zotero/zotero-note-editor/editor.html" type="content"/>
|
||||
<xul:hbox id="links-container" hidden="true">
|
||||
<xul:linksbox id="links-box" flex="1" xbl:inherits="notitle"/>
|
||||
|
@ -512,7 +537,7 @@
|
|||
<xul:menupopup id="tagsPopup" ignorekeys="true"
|
||||
onpopupshown="if (!document.commandDispatcher.focusedElement || document.commandDispatcher.focusedElement.tagName=='xul:label'){ /* DEBUG: it would be nice to make this work -- if (this.firstChild.count==0){ this.firstChild.newTag(); } */ this.setAttribute('showing', 'true'); }"
|
||||
onpopuphidden="if (!document.commandDispatcher.focusedElement || document.commandDispatcher.focusedElement.tagName=='xul:label'){ this.setAttribute('showing', 'false'); }">
|
||||
<xul:tagsbox id="tags" flex="1" mode="edit"/>
|
||||
<xul:tagsbox id="tags" flex="1" mode="edit" style="display: flex"/>
|
||||
</xul:menupopup>
|
||||
</xul:popupset>
|
||||
</xul:vbox>
|
||||
|
|
|
@ -25,14 +25,18 @@
|
|||
|
||||
import React, { forwardRef, useImperativeHandle, useState } from 'react';
|
||||
|
||||
const NoteRow = ({ title, body, date, onClick }) => {
|
||||
const NoteRow = ({ parentTitle, parentImageSrc, title, body, date, onClick }) => {
|
||||
return (
|
||||
<div className="note-row" onClick={onClick}>
|
||||
<div className="inner">
|
||||
<div className="first-line">
|
||||
{parentTitle !== null && <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>
|
||||
<div className="second-line">
|
||||
<div className="third-line">
|
||||
<div className="date">{date}</div>
|
||||
<div className="body">{body}</div>
|
||||
</div>
|
||||
|
|
791
chrome/content/zotero/contextPane.js
Normal file
|
@ -0,0 +1,791 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2020 Corporation for Digital Scholarship
|
||||
Vienna, Virginia, USA
|
||||
https://digitalscholar.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
// TODO: Fix import/require related isues that might be
|
||||
// related with `require` not reusing the context
|
||||
var React = require('react');
|
||||
var ReactDOM = require('react-dom');
|
||||
var TagsBoxContainer = require('containers/tagsBoxContainer').default;
|
||||
var NotesList = require('components/itemPane/notesList').default;
|
||||
|
||||
var ZoteroContextPane = new function () {
|
||||
const HTML_NS = 'http://www.w3.org/1999/xhtml';
|
||||
|
||||
var _tabCover;
|
||||
var _contextPane;
|
||||
var _contextPaneInner;
|
||||
var _contextPaneSplitter;
|
||||
var _contextPaneSplitterStacked;
|
||||
var _itemToggle;
|
||||
var _notesToggle;
|
||||
var _panesDeck;
|
||||
var _itemPaneDeck;
|
||||
var _notesPaneDeck;
|
||||
|
||||
var _itemToolbar;
|
||||
var _splitButton;
|
||||
var _itemPaneToggle;
|
||||
var _notesPaneToggle;
|
||||
var _toolbar;
|
||||
var _tabToolbarContainer;
|
||||
|
||||
var _itemContexts = [];
|
||||
var _notesContexts = [];
|
||||
|
||||
// Using attribute instead of propery to set 'selectedIndex'
|
||||
// is more reliable
|
||||
|
||||
this.update = _update;
|
||||
this.getActiveEditor = _getActiveEditor;
|
||||
|
||||
this.onLoad = function () {
|
||||
if (!Zotero) {
|
||||
return;
|
||||
}
|
||||
|
||||
_tabCover = document.getElementById('zotero-tab-cover');
|
||||
_itemToggle = document.getElementById('zotero-tb-toggle-item-pane');
|
||||
_notesToggle = document.getElementById('zotero-tb-toggle-notes-pane');
|
||||
_contextPane = document.getElementById('zotero-context-pane');
|
||||
_contextPaneInner = document.getElementById('zotero-context-pane-inner');
|
||||
_contextPaneSplitter = document.getElementById('zotero-context-splitter');
|
||||
_contextPaneSplitterStacked = document.getElementById('zotero-context-splitter-stacked');
|
||||
|
||||
_itemToolbar = document.getElementById('zotero-item-toolbar');
|
||||
_splitButton = document.getElementById('zotero-tb-split');
|
||||
_itemPaneToggle = document.getElementById('zotero-tb-toggle-item-pane');
|
||||
_notesPaneToggle = document.getElementById('zotero-tb-toggle-notes-pane');
|
||||
_toolbar = document.getElementById('zotero-toolbar');
|
||||
_tabToolbarContainer = document.getElementById('zotero-tab-toolbar-container');
|
||||
|
||||
_init();
|
||||
|
||||
this._unregisterID = Zotero.Notifier.registerObserver(this, ['item', 'tab'], 'contextPane');
|
||||
window.addEventListener('resize', _update);
|
||||
_itemToggle.addEventListener('click', () => {
|
||||
_togglePane(0);
|
||||
});
|
||||
_notesToggle.addEventListener('click', () => {
|
||||
_togglePane(1);
|
||||
});
|
||||
Zotero.Reader.onChangeSidebarWidth = _updatePaneWidth;
|
||||
Zotero.Reader.onChangeSidebarOpen = _updatePaneWidth;
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
_updateToolbarWidth();
|
||||
// Sometimes XUL is late to reflow
|
||||
setTimeout(_updateToolbarWidth, 100);
|
||||
});
|
||||
observer.observe(_tabToolbarContainer, { attributes: true, childList: true, subtree: true });
|
||||
};
|
||||
|
||||
this.onUnload = function () {
|
||||
Zotero.Notifier.unregisterObserver(this._unregisterID);
|
||||
};
|
||||
|
||||
this.notify = Zotero.Promise.coroutine(function* (action, type, ids, extraData) {
|
||||
if (type == 'item') {
|
||||
// TODO: Filter library and seriously thing about the performance of this part
|
||||
for (let context of _itemContexts) {
|
||||
let item = Zotero.Items.get(context.itemID);
|
||||
if (item && item.parentID != context.parentID) {
|
||||
_removeItemContext(context.tabID);
|
||||
_addItemContext(context.tabID, context.itemID);
|
||||
}
|
||||
context.update();
|
||||
}
|
||||
|
||||
for (let context of _notesContexts) {
|
||||
context.updateNotesList();
|
||||
}
|
||||
}
|
||||
else if (type == 'tab') {
|
||||
if (action == 'add') {
|
||||
_addItemContext(ids[0], extraData[ids[0]].itemID);
|
||||
}
|
||||
else if (action == 'close') {
|
||||
_removeItemContext(ids[0]);
|
||||
}
|
||||
else if (action == 'select') {
|
||||
if (Zotero_Tabs.selectedIndex == 0) {
|
||||
_contextPaneSplitter.setAttribute('hidden', true);
|
||||
_contextPane.setAttribute('collapsed', true);
|
||||
_toolbar.append(_itemToolbar);
|
||||
_itemToolbar.classList.remove('tab-mode');
|
||||
_splitButton.classList.add('hidden');
|
||||
}
|
||||
else {
|
||||
var reader = Zotero.Reader.getByTabID(Zotero_Tabs.selectedID);
|
||||
if (reader) {
|
||||
_tabCover.hidden = false;
|
||||
(async () => {
|
||||
await reader._initPromise;
|
||||
_tabCover.hidden = true;
|
||||
})();
|
||||
}
|
||||
|
||||
_contextPaneSplitter.setAttribute('hidden', false);
|
||||
_contextPane.setAttribute('collapsed', !(_contextPaneSplitter.getAttribute('state') != 'collapsed'));
|
||||
_tabToolbarContainer.append(_itemToolbar);
|
||||
_itemToolbar.classList.add('tab-mode');
|
||||
_splitButton.classList.remove('hidden');
|
||||
}
|
||||
|
||||
var context = _itemContexts.find(x => x.tabID == ids[0]);
|
||||
if (context) {
|
||||
_selectNotesContext(context.libraryID);
|
||||
}
|
||||
_selectItemContext(ids[0], extraData[ids[0]].type);
|
||||
_update();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function _removeNote(id) {
|
||||
var ps = Components.classes['@mozilla.org/embedcomp/prompt-service;1']
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
if (ps.confirm(null, '', Zotero.getString('pane.item.notes.delete.confirm'))) {
|
||||
Zotero.Items.trashTx(id);
|
||||
}
|
||||
}
|
||||
|
||||
function _getActiveEditor() {
|
||||
var splitter;
|
||||
if (Zotero.Prefs.get('layout') == 'stacked') {
|
||||
splitter = _contextPaneSplitterStacked;
|
||||
}
|
||||
else {
|
||||
splitter = _contextPaneSplitter;
|
||||
}
|
||||
|
||||
if (splitter.getAttribute('state') != 'collapsed') {
|
||||
if (_panesDeck.selectedIndex == 0) {
|
||||
let child = _itemPaneDeck.selectedPanel;
|
||||
var tabPanels = child.querySelector('tabpanels');
|
||||
if (tabPanels && tabPanels.selectedIndex == 1) {
|
||||
var notesDeck = child.querySelector('.notes-deck');
|
||||
if (notesDeck.selectedIndex == 1) {
|
||||
return child.querySelector('zoteronoteeditor');
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var node = _notesPaneDeck.selectedPanel;
|
||||
if (node.selectedIndex == 1) {
|
||||
return node.querySelector('zoteronoteeditor');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _updateAddToNote() {
|
||||
var reader = Zotero.Reader.getByTabID(Zotero_Tabs.selectedID);
|
||||
if (reader) {
|
||||
var editor = _getActiveEditor();
|
||||
reader.enableAddToNote(!!editor);
|
||||
}
|
||||
}
|
||||
|
||||
function _updatePaneWidth() {
|
||||
var stacked = Zotero.Prefs.get('layout') == 'stacked';
|
||||
var width = Zotero.Reader.getSidebarWidth() + 'px';
|
||||
if (!Zotero.Reader.getSidebarOpen()) {
|
||||
width = 0;
|
||||
}
|
||||
_contextPane.style.left = stacked ? width : 'unset';
|
||||
}
|
||||
|
||||
function _updateToolbarWidth() {
|
||||
var stacked = Zotero.Prefs.get('layout') == 'stacked';
|
||||
var reader = Zotero.Reader.getByTabID(Zotero_Tabs.selectedID);
|
||||
if (reader) {
|
||||
if ((stacked || _contextPaneSplitter.getAttribute('state') == 'collapsed')) {
|
||||
reader.setToolbarPlaceholderWidth(_tabToolbarContainer.boxObject.width);
|
||||
}
|
||||
else {
|
||||
reader.setToolbarPlaceholderWidth(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _update() {
|
||||
if (Zotero_Tabs.selectedIndex == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var splitter;
|
||||
var stacked = Zotero.Prefs.get('layout') == 'stacked';
|
||||
if (stacked) {
|
||||
_contextPaneSplitterStacked.setAttribute('hidden', false);
|
||||
_contextPaneSplitter.setAttribute('state', 'open');
|
||||
_contextPaneSplitter.setAttribute('hidden', true);
|
||||
_contextPane.classList.add('stacked');
|
||||
_contextPane.classList.remove('standard');
|
||||
splitter = _contextPaneSplitterStacked;
|
||||
}
|
||||
else {
|
||||
_contextPaneSplitter.setAttribute('hidden', false);
|
||||
_contextPaneSplitterStacked.setAttribute('hidden', true);
|
||||
_contextPaneSplitterStacked.setAttribute('state', 'open');
|
||||
_contextPane.classList.add('standard');
|
||||
_contextPane.classList.remove('stacked');
|
||||
splitter = _contextPaneSplitter;
|
||||
}
|
||||
|
||||
var collapsed = splitter.getAttribute('state') == 'collapsed';
|
||||
|
||||
var selectedIndex = _panesDeck.selectedIndex;
|
||||
if (!collapsed && selectedIndex == 0) {
|
||||
_itemPaneToggle.classList.add('toggled');
|
||||
}
|
||||
else {
|
||||
_itemPaneToggle.classList.remove('toggled');
|
||||
}
|
||||
|
||||
if (!collapsed && selectedIndex == 1) {
|
||||
_notesPaneToggle.classList.add('toggled');
|
||||
}
|
||||
else {
|
||||
_notesPaneToggle.classList.remove('toggled');
|
||||
}
|
||||
|
||||
if (Zotero_Tabs.selectedIndex > 0) {
|
||||
var height = 0;
|
||||
if (Zotero.Prefs.get('layout') == 'stacked'
|
||||
&& _contextPane.getAttribute('collapsed') != 'true') {
|
||||
height = _contextPaneInner.boxObject.height;
|
||||
}
|
||||
Zotero.Reader.setBottomPlaceholderHeight(height);
|
||||
}
|
||||
|
||||
_updatePaneWidth();
|
||||
_updateToolbarWidth();
|
||||
_updateAddToNote();
|
||||
}
|
||||
|
||||
function _togglePane(paneIndex) {
|
||||
var splitter;
|
||||
var stacked = Zotero.Prefs.get('layout') == 'stacked';
|
||||
if (stacked) {
|
||||
splitter = _contextPaneSplitterStacked;
|
||||
}
|
||||
else {
|
||||
splitter = _contextPaneSplitter;
|
||||
}
|
||||
|
||||
var isOpen = splitter.getAttribute('state') != 'collapsed';
|
||||
var hide = false;
|
||||
|
||||
var currentPane = _panesDeck.selectedIndex;
|
||||
|
||||
if (isOpen && currentPane == paneIndex) {
|
||||
hide = true;
|
||||
}
|
||||
else {
|
||||
_panesDeck.setAttribute('selectedIndex', paneIndex);
|
||||
}
|
||||
|
||||
var context = _itemContexts.find(x => x.tabID == Zotero_Tabs.selectedID);
|
||||
context.selectedIndex = paneIndex;
|
||||
|
||||
splitter.setAttribute('state', hide ? 'collapsed' : 'open');
|
||||
_update();
|
||||
}
|
||||
|
||||
function _init() {
|
||||
// vbox
|
||||
var vbox = document.createElement('vbox');
|
||||
vbox.setAttribute('flex', '1');
|
||||
|
||||
_contextPaneInner.append(vbox);
|
||||
|
||||
// Toolbar extension
|
||||
var toolbarExtension = document.createElement('box');
|
||||
toolbarExtension.style.height = '32px';
|
||||
toolbarExtension.id = 'zotero-context-toolbar-extension';
|
||||
|
||||
_panesDeck = document.createElement('deck');
|
||||
_panesDeck.setAttribute('flex', 1);
|
||||
_panesDeck.setAttribute('selectedIndex', 0);
|
||||
|
||||
vbox.append(toolbarExtension, _panesDeck);
|
||||
|
||||
// Item pane deck
|
||||
_itemPaneDeck = document.createElement('deck');
|
||||
// Notes pane deck
|
||||
_notesPaneDeck = document.createElement('deck');
|
||||
_notesPaneDeck.style.backgroundColor = 'white';
|
||||
_notesPaneDeck.setAttribute('flex', 1);
|
||||
_notesPaneDeck.className = 'notes-pane-deck';
|
||||
|
||||
_panesDeck.append(_itemPaneDeck, _notesPaneDeck);
|
||||
}
|
||||
|
||||
function _addNotesContext(libraryID) {
|
||||
var list = document.createElement('vbox');
|
||||
list.setAttribute('flex', 1);
|
||||
list.className = 'zotero-context-notes-list';
|
||||
|
||||
var noteContainer = document.createElement('vbox');
|
||||
var editor = document.createElement('zoteronoteeditor');
|
||||
editor.className = 'zotero-context-pane-pinned-note';
|
||||
editor.setAttribute('flex', 1);
|
||||
noteContainer.appendChild(editor);
|
||||
|
||||
let contextNode = document.createElement('deck');
|
||||
contextNode.append(list, noteContainer);
|
||||
_notesPaneDeck.append(contextNode);
|
||||
|
||||
contextNode.className = 'context-node';
|
||||
contextNode.setAttribute('selectedIndex', 0);
|
||||
|
||||
editor.returnHandler = () => {
|
||||
contextNode.setAttribute('selectedIndex', 0);
|
||||
_updateAddToNote();
|
||||
};
|
||||
|
||||
var head = document.createElement('hbox');
|
||||
head.style.display = 'flex';
|
||||
|
||||
var label = document.createElement('label');
|
||||
var button = document.createElement('button');
|
||||
button.setAttribute('label', Zotero.Intl.strings['zotero.item.add']);
|
||||
button.addEventListener('click', () => {
|
||||
contextNode.setAttribute('selectedIndex', 1);
|
||||
var item = new Zotero.Item('note');
|
||||
item.libraryID = libraryID;
|
||||
// item.parentKey = parentItem.key;
|
||||
editor.mode = 'edit';
|
||||
editor.item = item;
|
||||
editor.parentItem = null;
|
||||
editor.focus();
|
||||
_updateAddToNote();
|
||||
});
|
||||
|
||||
|
||||
var vbox1 = document.createElement('vbox');
|
||||
vbox1.append(label, button);
|
||||
|
||||
var vbox2 = document.createElement('vbox');
|
||||
vbox2.style.flex = '1';
|
||||
var input = document.createElement('textbox');
|
||||
input.setAttribute('type', 'search');
|
||||
input.setAttribute('timeout', '250');
|
||||
input.addEventListener('command', () => {
|
||||
updateNotesList();
|
||||
});
|
||||
vbox2.append(input);
|
||||
|
||||
head.append(vbox2, vbox1);
|
||||
|
||||
var listBox = document.createElement('vbox');
|
||||
listBox.style.display = 'flex';
|
||||
listBox.setAttribute('flex', '1');
|
||||
var listInner = document.createElementNS(HTML_NS, 'div');
|
||||
listInner.className = 'notes-list-container';
|
||||
listBox.append(listInner);
|
||||
|
||||
list.append(head, listBox);
|
||||
|
||||
var notesListRef = React.createRef();
|
||||
|
||||
var updateNotesList = async (reset) => {
|
||||
if (reset) {
|
||||
input.value = '';
|
||||
contextNode.setAttribute('selectedIndex', 0);
|
||||
}
|
||||
var text = input.value;
|
||||
|
||||
await Zotero.Schema.schemaUpdatePromise;
|
||||
var s = new Zotero.Search();
|
||||
s.addCondition('libraryID', 'is', libraryID);
|
||||
s.addCondition('itemType', 'is', 'note');
|
||||
s.addCondition('noChildren', 'false');
|
||||
if (text) {
|
||||
s.addCondition('note', 'contains', text, true);
|
||||
}
|
||||
var 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);
|
||||
});
|
||||
|
||||
notesListRef.current.setNotes(notes.map(note => {
|
||||
var text2 = note.note.slice(0, 500);
|
||||
text2 = text2.trim();
|
||||
// TODO: Fix a potential performance issuse
|
||||
text2 = Zotero.Utilities.unescapeHTML(text2);
|
||||
var parts = text2.split('\n').map(x => x.trim()).filter(x => x.length);
|
||||
var parent = null;
|
||||
if (note.parentID) {
|
||||
parent = Zotero.Items.get(note.parentID);
|
||||
}
|
||||
return {
|
||||
id: note.id,
|
||||
parentTitle: parent && parent.getDisplayTitle(),
|
||||
parentImageSrc: parent && parent.getImageSrc(),
|
||||
title: parts[0] || Zotero.getString('pane.item.notes.untitled'),
|
||||
body: parts[1] || '',
|
||||
date: (new Date(note.dateModified).toLocaleDateString(Zotero.locale))
|
||||
};
|
||||
}));
|
||||
|
||||
var c = notes.length;
|
||||
var str = 'pane.item.notes.count.' + (c == 0 && 'zero' || c == 1 && 'singular' || 'plural');
|
||||
label.value = Zotero.getString(str, [c]);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<NotesList
|
||||
ref={notesListRef}
|
||||
onClick={(id) => {
|
||||
_setPinnedNote(libraryID, id);
|
||||
}}
|
||||
/>,
|
||||
listInner,
|
||||
() => {
|
||||
updateNotesList();
|
||||
}
|
||||
);
|
||||
|
||||
var context = {
|
||||
libraryID,
|
||||
node: contextNode,
|
||||
updateNotesList,
|
||||
editor
|
||||
};
|
||||
|
||||
_notesContexts.push(context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
function _getNotesContext(libraryID) {
|
||||
var context = _notesContexts.find(x => x.libraryID == libraryID);
|
||||
if (!context) {
|
||||
context = _addNotesContext(libraryID);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
function _selectNotesContext(libraryID) {
|
||||
let context = _getNotesContext(libraryID);
|
||||
_notesPaneDeck.setAttribute('selectedIndex', Array.from(_notesPaneDeck.children).findIndex(x => x == context.node));
|
||||
}
|
||||
|
||||
function _removeNotesContext(libraryID) {
|
||||
var context = _notesContexts.find(x => x.libraryID == libraryID);
|
||||
context.node.remove();
|
||||
_notesContexts = _notesContexts.filter(x => x.libraryID != libraryID);
|
||||
}
|
||||
|
||||
function _libraryEditable(libraryID) {
|
||||
var type = Zotero.Libraries.get(libraryID).libraryType;
|
||||
if (type == 'group') {
|
||||
var groupID = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
|
||||
var group = Zotero.Groups.get(groupID);
|
||||
return group.editable;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function _setPinnedNote(libraryID, itemID) {
|
||||
var editable = _libraryEditable(libraryID);
|
||||
var context = _getNotesContext(libraryID);
|
||||
if (context) {
|
||||
let { editor, node } = context;
|
||||
node.setAttribute('selectedIndex', 1);
|
||||
editor.mode = editable ? 'edit' : 'view';
|
||||
editor.item = Zotero.Items.get(itemID);
|
||||
editor.parentItem = null;
|
||||
editor.hideLinksContainer = true;
|
||||
_updateAddToNote();
|
||||
}
|
||||
}
|
||||
|
||||
function _appendNoteRows(notes, list, editable, onClick, onDelete) {
|
||||
for (var i = 0; i < notes.length; i++) {
|
||||
var note = notes[i];
|
||||
var 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);
|
||||
}
|
||||
}
|
||||
|
||||
function _removeItemContext(tabID) {
|
||||
document.getElementById(tabID + '-context').remove();
|
||||
_itemContexts = _itemContexts.filter(x => x.tabID != tabID);
|
||||
}
|
||||
|
||||
function _selectItemContext(tabID, type) {
|
||||
let selectedIndex = Array.from(_itemPaneDeck.children).findIndex(x => x.id == tabID + '-context');
|
||||
if (selectedIndex != -1) {
|
||||
_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) {
|
||||
var container = document.createElement('vbox');
|
||||
container.id = tabID + '-context';
|
||||
container.className = 'zotero-item-pane-content';
|
||||
_itemPaneDeck.appendChild(container);
|
||||
|
||||
var item = Zotero.Items.get(itemID);
|
||||
var libraryID = item.libraryID;
|
||||
var editable = _libraryEditable(libraryID);
|
||||
var parentID = item.parentID;
|
||||
|
||||
var context = {
|
||||
tabID,
|
||||
itemID,
|
||||
parentID,
|
||||
libraryID,
|
||||
selectedIndex: 0,
|
||||
update: () => {}
|
||||
};
|
||||
_itemContexts.push(context);
|
||||
|
||||
if (!parentID) {
|
||||
var vbox = document.createElement('vbox');
|
||||
vbox.setAttribute('flex', '1');
|
||||
vbox.setAttribute('align', 'center');
|
||||
vbox.setAttribute('pack', 'center');
|
||||
var description = document.createElement('description');
|
||||
vbox.append(description);
|
||||
description.append(Zotero.getString('pane.context.noParent'));
|
||||
container.append(vbox);
|
||||
return;
|
||||
}
|
||||
|
||||
var parentItem = Zotero.Items.get(item.parentID);
|
||||
|
||||
// tabbox
|
||||
var tabbox = document.createElement('tabbox');
|
||||
tabbox.setAttribute('flex', '1');
|
||||
tabbox.className = 'zotero-view-tabbox';
|
||||
|
||||
container.append(tabbox);
|
||||
|
||||
// tabs
|
||||
var tabs = document.createElement('tabs');
|
||||
tabs.className = 'zotero-editpane-tabs';
|
||||
// tabpanels
|
||||
var tabpanels = document.createElement('tabpanels');
|
||||
tabpanels.setAttribute('flex', '1');
|
||||
tabpanels.className = 'zotero-view-item';
|
||||
tabpanels.addEventListener('select', () => {
|
||||
_updateAddToNote();
|
||||
});
|
||||
|
||||
tabbox.append(tabs, tabpanels);
|
||||
|
||||
// Info tab
|
||||
var tabInfo = document.createElement('tab');
|
||||
tabInfo.setAttribute('label', Zotero.Intl.strings['zotero.tabs.info.label']);
|
||||
// Notes tab
|
||||
var tabNotes = document.createElement('tab');
|
||||
tabNotes.setAttribute('label', Zotero.Intl.strings['zotero.tabs.notes.label']);
|
||||
// Tags tab
|
||||
var tabTags = document.createElement('tab');
|
||||
tabTags.setAttribute('label', Zotero.Intl.strings['zotero.tabs.tags.label']);
|
||||
// Related tab
|
||||
var tabRelated = document.createElement('tab');
|
||||
tabRelated.setAttribute('label', Zotero.Intl.strings['zotero.tabs.related.label']);
|
||||
|
||||
tabs.append(tabInfo, tabNotes, tabTags, tabRelated);
|
||||
|
||||
// Info panel
|
||||
var panelInfo = document.createElement('tabpanel');
|
||||
panelInfo.setAttribute('flex', '1');
|
||||
panelInfo.className = 'zotero-editpane-item-box';
|
||||
var itemBox = document.createElement('zoteroitembox');
|
||||
itemBox.setAttribute('flex', '1');
|
||||
panelInfo.append(itemBox);
|
||||
// Notes panel
|
||||
var panelNotes = document.createElement('tabpanel');
|
||||
panelNotes.setAttribute('flex', '1');
|
||||
panelNotes.setAttribute('orient', 'vertical');
|
||||
var deck = document.createElement('deck');
|
||||
deck.className = 'notes-deck';
|
||||
deck.setAttribute('flex', '1');
|
||||
panelNotes.append(deck);
|
||||
var vbox2 = document.createElement('vbox');
|
||||
var note = document.createElement('zoteronoteeditor');
|
||||
note.setAttribute('flex', 1);
|
||||
vbox2.append(note);
|
||||
var vbox = document.createElement('vbox');
|
||||
vbox.setAttribute('flex', '1');
|
||||
vbox.setAttribute('class', 'zotero-box');
|
||||
vbox.style.overflowY = 'auto';
|
||||
panelNotes.append(vbox);
|
||||
var hbox = document.createElement('hbox');
|
||||
hbox.setAttribute('align', 'center');
|
||||
var label = document.createElement('label');
|
||||
var button = document.createElement('button');
|
||||
// TODO: Should not depend on the current ZoteroPane state
|
||||
button.hidden = !editable;
|
||||
button.setAttribute('label', Zotero.Intl.strings['zotero.item.add']);
|
||||
button.addEventListener('click', () => {
|
||||
deck.setAttribute('selectedIndex', 1);
|
||||
var item = new Zotero.Item('note');
|
||||
item.libraryID = parentItem.libraryID;
|
||||
item.parentID = parentItem.id;
|
||||
note.returnHandler = () => {
|
||||
deck.setAttribute('selectedIndex', 0);
|
||||
_updateAddToNote();
|
||||
};
|
||||
note.mode = editable ? 'edit' : 'view';
|
||||
note.item = item;
|
||||
note.focus();
|
||||
_updateAddToNote();
|
||||
});
|
||||
hbox.append(label, button);
|
||||
var grid = document.createElement('grid');
|
||||
grid.setAttribute('flex', 1);
|
||||
var columns = document.createElement('columns');
|
||||
var column = document.createElement('column');
|
||||
column.setAttribute('flex', 1);
|
||||
columns.append(column);
|
||||
var column = document.createElement('column');
|
||||
columns.append(column);
|
||||
grid.append(columns);
|
||||
var rows = document.createElement('rows');
|
||||
rows.setAttribute('flex', 1);
|
||||
grid.append(rows);
|
||||
vbox.append(hbox, grid);
|
||||
deck.append(vbox, vbox2);
|
||||
deck.setAttribute('selectedIndex', 0);
|
||||
// Tags panel
|
||||
var panelTags = document.createElement('tabpanel');
|
||||
panelTags.setAttribute('orient', 'vertical');
|
||||
panelTags.setAttribute('context', 'tags-context-menu');
|
||||
panelTags.className = 'tags-pane';
|
||||
panelTags.style.display = 'flex';
|
||||
var div = document.createElementNS(HTML_NS, 'div');
|
||||
div.className = 'tags-box-container';
|
||||
div.style.display = 'flex';
|
||||
div.style.flexGrow = '1';
|
||||
panelTags.append(div);
|
||||
var tagsBoxRef = React.createRef();
|
||||
ReactDOM.render(
|
||||
<TagsBoxContainer
|
||||
key={'tagsBox-' + parentItem.id}
|
||||
item={parentItem}
|
||||
editable={editable}
|
||||
ref={tagsBoxRef}
|
||||
/>,
|
||||
div
|
||||
);
|
||||
// Related panel
|
||||
var panelRelated = document.createElement('tabpanel');
|
||||
var relatedBox = document.createElement('relatedbox');
|
||||
relatedBox.setAttribute('flex', '1');
|
||||
relatedBox.className = 'zotero-editpane-related';
|
||||
panelRelated.addEventListener('click', (event) => {
|
||||
if (event.originalTarget.closest('.zotero-clicky')) {
|
||||
Zotero_Tabs.select('zotero-pane');
|
||||
}
|
||||
});
|
||||
panelRelated.append(relatedBox);
|
||||
|
||||
tabpanels.append(panelInfo, panelNotes, panelTags, panelRelated);
|
||||
tabbox.selectedIndex = 0;
|
||||
|
||||
|
||||
itemBox.mode = editable ? 'edit' : 'view';
|
||||
itemBox.item = parentItem;
|
||||
|
||||
relatedBox.mode = editable ? 'edit' : 'view';
|
||||
relatedBox.item = parentItem;
|
||||
|
||||
function _renderNotesPanel() {
|
||||
rows.innerHTML = '';
|
||||
var parentNotes = Zotero.Items.get(parentItem.getNotes());
|
||||
_appendNoteRows(parentNotes, rows, editable, (id) => {
|
||||
deck.setAttribute('selectedIndex', 1);
|
||||
note.returnHandler = () => {
|
||||
deck.setAttribute('selectedIndex', 0);
|
||||
_updateAddToNote();
|
||||
};
|
||||
note.mode = editable ? 'edit' : 'view';
|
||||
note.item = Zotero.Items.get(id);
|
||||
note.parentItem = null;
|
||||
_updateAddToNote();
|
||||
}, (id) => {
|
||||
_removeNote(id);
|
||||
});
|
||||
var c = parentNotes.length;
|
||||
var str = 'pane.item.notes.count.' + (c == 0 && 'zero' || c == 1 && 'singular' || 'plural');
|
||||
label.value = Zotero.getString(str, [c]);
|
||||
}
|
||||
|
||||
context.update = _renderNotesPanel;
|
||||
_renderNotesPanel();
|
||||
}
|
||||
};
|
||||
|
||||
addEventListener('load', function (e) { ZoteroContextPane.onLoad(e); }, false);
|
||||
addEventListener('unload', function (e) { ZoteroContextPane.onUnload(e); }, false);
|
|
@ -26,17 +26,12 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import TagsBoxContainer from 'containers/tagsBoxContainer';
|
||||
import NotesList from 'components/itemPane/notesList';
|
||||
|
||||
var ZoteroItemPane = new function() {
|
||||
const HTML_NS = 'http://www.w3.org/1999/xhtml';
|
||||
|
||||
var _lastItem, _itemBox, _notesLabel, _notesButton, _notesList, _tagsBox, _relatedBox;
|
||||
var _selectedNoteID;
|
||||
var _translationTarget;
|
||||
var _noteIDs;
|
||||
var _contextNoteUpdaters = [];
|
||||
let _pdfTabHidden = false;
|
||||
|
||||
this.onLoad = function () {
|
||||
if (!Zotero) {
|
||||
|
@ -60,15 +55,7 @@ var ZoteroItemPane = new function() {
|
|||
};
|
||||
_relatedBox = document.getElementById('zotero-editpane-related');
|
||||
|
||||
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.initStandaloneNotesView();
|
||||
this._unregisterID = Zotero.Notifier.registerObserver(this, ['item'], 'itemPane');
|
||||
}
|
||||
|
||||
|
||||
|
@ -115,8 +102,6 @@ var ZoteroItemPane = new function() {
|
|||
|
||||
_lastItem = item;
|
||||
|
||||
_updateTitle();
|
||||
|
||||
var viewBox = document.getElementById('zotero-view-item');
|
||||
viewBox.classList.remove('no-tabs');
|
||||
|
||||
|
@ -228,32 +213,15 @@ var ZoteroItemPane = new function() {
|
|||
|
||||
|
||||
this.notify = Zotero.Promise.coroutine(function* (action, type, ids, extraData) {
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
this.updateStandaloneNotesList();
|
||||
for (let updater of _contextNoteUpdaters) {
|
||||
updater.callback();
|
||||
}
|
||||
}
|
||||
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);
|
||||
if (refresh) {
|
||||
yield this.viewItem(_lastItem, null, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -311,7 +279,6 @@ var ZoteroItemPane = new function() {
|
|||
// noteEditor.clearUndo();
|
||||
// }
|
||||
|
||||
document.getElementById('zotero-view-note-sidebar-button').hidden = !!item.parentID;
|
||||
document.getElementById('zotero-view-note-button').hidden = !editable;
|
||||
document.getElementById('zotero-item-pane-content').selectedIndex = 2;
|
||||
};
|
||||
|
@ -321,17 +288,6 @@ var ZoteroItemPane = new function() {
|
|||
// ZoteroPane.setItemPaneMessage(Zotero.getString('pane.item.notes.editingInWindow'));
|
||||
};
|
||||
|
||||
this.openNoteSidebar = async function () {
|
||||
var selectedNote = Zotero.Items.get(_selectedNoteID);
|
||||
|
||||
if (!selectedNote.parentID) {
|
||||
let editor = document.getElementById('zotero-item-pane-pinned-note');
|
||||
editor.mode = 'edit';
|
||||
editor.item = selectedNote;
|
||||
document.getElementById('zotero-item-pane-pin-deck2').setAttribute('selectedIndex', 1);
|
||||
this.togglePane(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the parent item and open the note editor
|
||||
|
@ -480,11 +436,6 @@ var ZoteroItemPane = new function() {
|
|||
};
|
||||
|
||||
|
||||
function _updateTitle() {
|
||||
document.getElementById('item-pane-title').textContent = _lastItem.getDisplayTitle();
|
||||
}
|
||||
|
||||
|
||||
function _updateNoteCount() {
|
||||
var c = _notesList.childNodes.length;
|
||||
|
||||
|
@ -503,508 +454,6 @@ var ZoteroItemPane = new function() {
|
|||
|
||||
_notesLabel.value = Zotero.getString(str, [c]);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
this.togglePane = function (forceItem) {
|
||||
var pane = document.getElementById('zotero-item-pane');
|
||||
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;
|
||||
}
|
||||
|
||||
if (value == 0) {
|
||||
pane.setAttribute('data-mode', 'item');
|
||||
document.getElementById('temp-toggle-1').innerHTML = '[📄] 📒';
|
||||
document.getElementById('temp-toggle-2').innerHTML = '[📄] 📒';
|
||||
}
|
||||
else {
|
||||
pane.setAttribute('data-mode', 'notes');
|
||||
document.getElementById('temp-toggle-1').innerHTML = '📄 [📒]';
|
||||
document.getElementById('temp-toggle-2').innerHTML = '📄 [📒]';
|
||||
}
|
||||
|
||||
mainDeck.selectedIndex = value;
|
||||
|
||||
let contextualDeck = document.getElementById('zotero-item-pane-contextual-deck');
|
||||
contextualDeck.children[contextualDeck.selectedIndex].setAttribute('state', value);
|
||||
}
|
||||
|
||||
this.initStandaloneNotesView = 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);
|
||||
|
||||
var listLabel = document.createElementNS(HTML_NS, 'div');
|
||||
listLabel.className = 'notes-list-label';
|
||||
listLabel.textContent = Zotero.getString('pane.item.notes.allNotes');
|
||||
|
||||
let list = document.createElement('vbox');
|
||||
list.setAttribute('flex', 1);
|
||||
list.className = 'zotero-box';
|
||||
|
||||
list.appendChild(listLabel);
|
||||
|
||||
var noteContainer = document.createElement('vbox');
|
||||
var backButton = document.createElementNS(HTML_NS, 'div');
|
||||
backButton.className = 'item-pane-back-button';
|
||||
backButton.textContent = (Zotero.dir == 'ltr' ? '←' : '→') + ' '
|
||||
+ Zotero.getString('general.back');
|
||||
backButton.addEventListener('click', () => {
|
||||
inner.setAttribute('selectedIndex', 0);
|
||||
});
|
||||
let note = document.createElement('zoteronoteeditor');
|
||||
note.id = 'zotero-item-pane-pinned-note';
|
||||
note.setAttribute('flex', 1);
|
||||
noteContainer.appendChild(backButton);
|
||||
noteContainer.appendChild(note);
|
||||
|
||||
inner.append(list, noteContainer);
|
||||
inner.setAttribute('selectedIndex', 0);
|
||||
|
||||
let head = document.createElement('hbox');
|
||||
let label = document.createElement('label');
|
||||
let button = document.createElement('button');
|
||||
button.setAttribute('label', Zotero.Intl.strings['zotero.item.add']);
|
||||
button.addEventListener('click', async () => {
|
||||
inner.setAttribute('selectedIndex', 1);
|
||||
let item = new Zotero.Item('note');
|
||||
item.libraryID = ZoteroPane_Local.getSelectedLibraryID();
|
||||
// item.parentKey = parentItem.key;
|
||||
note.mode = 'edit';
|
||||
note.item = item;
|
||||
note.parentItem = null;
|
||||
note.focus();
|
||||
});
|
||||
|
||||
head.style.paddingRight = '10px';
|
||||
|
||||
|
||||
let input = document.createElement('textbox');
|
||||
input.setAttribute('type', 'search');
|
||||
input.setAttribute('timeout', '250');
|
||||
|
||||
input.addEventListener('command', (event) => {
|
||||
_updateStandaloneNotesList();
|
||||
})
|
||||
|
||||
|
||||
let vbox1 = document.createElement('vbox');
|
||||
vbox1.append(label, button);
|
||||
|
||||
let vbox2 = document.createElement('vbox');
|
||||
vbox2.append(input);
|
||||
|
||||
head.append(vbox2, vbox1);
|
||||
|
||||
head.style.display = 'flex';
|
||||
vbox2.style.flex = '1';
|
||||
|
||||
|
||||
let listBox = document.createElement('vbox');
|
||||
listBox.style.display = 'flex';
|
||||
listBox.setAttribute('flex', '1')
|
||||
|
||||
var listInner = document.createElementNS(HTML_NS, 'div');
|
||||
listInner.className = 'notes-list-container';
|
||||
list.append(head, listBox);
|
||||
|
||||
listBox.append(listInner);
|
||||
|
||||
let noteListRef = React.createRef();
|
||||
|
||||
let _updateStandaloneNotesList = async (reset) => {
|
||||
if (reset) {
|
||||
input.value = '';
|
||||
inner.setAttribute('selectedIndex', 0);
|
||||
}
|
||||
let text = input.value;
|
||||
|
||||
await Zotero.Schema.schemaUpdatePromise;
|
||||
var s = new Zotero.Search();
|
||||
s.addCondition('libraryID', 'is', ZoteroPane_Local.getSelectedLibraryID());
|
||||
s.addCondition('itemType', 'is', 'note');
|
||||
s.addCondition('noChildren', 'true');
|
||||
if (text) {
|
||||
s.addCondition('note', 'contains', text, 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);
|
||||
});
|
||||
|
||||
noteListRef.current.setNotes(notes.map(note => {
|
||||
let text2 = note.note;
|
||||
text2 = text2.trim();
|
||||
// TODO: Fix a potential performance issuse
|
||||
text2 = Zotero.Utilities.unescapeHTML(text2);
|
||||
let parts = text2.split('\n').map(x => x.trim()).filter(x => x.length);
|
||||
return {
|
||||
id: note.id,
|
||||
title: parts[0] || Zotero.getString('pane.item.notes.untitled'),
|
||||
body: parts[1] || '',
|
||||
date: (new Date(note.dateModified).toLocaleDateString(Zotero.locale))
|
||||
};
|
||||
}));
|
||||
|
||||
var c = notes.length;
|
||||
var str = 'pane.item.notes.count.' + (c == 0 && 'zero' || c == 1 && 'singular' || 'plural');
|
||||
label.value = Zotero.getString(str, [c]);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<NotesList
|
||||
ref={noteListRef}
|
||||
onClick={(id) => {
|
||||
this._setPinnedNote(id);
|
||||
}}
|
||||
/>,
|
||||
listInner,
|
||||
() => {
|
||||
_updateStandaloneNotesList();
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
this.updateStandaloneNotesList = _updateStandaloneNotesList;
|
||||
}
|
||||
|
||||
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.removeTabContext = function (tabID) {
|
||||
document.getElementById(tabID + '-context').remove();
|
||||
_contextNoteUpdaters = _contextNoteUpdaters.filter(x => x.tabID != tabID);
|
||||
};
|
||||
|
||||
this.selectTabContext = function (tabID, type) {
|
||||
var pane = document.getElementById('zotero-item-pane');
|
||||
pane.setAttribute('data-type', type);
|
||||
|
||||
let contextualDeck = document.getElementById('zotero-item-pane-contextual-deck');
|
||||
let prevIndex = contextualDeck.selectedIndex;
|
||||
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 (prevIndex != 0) {
|
||||
_pdfTabHidden = itemPane.hidden;
|
||||
}
|
||||
|
||||
if (type == 'library') {
|
||||
toolbar.hidden = false;
|
||||
extendedToolbar.hidden = true;
|
||||
itemPane.hidden = false;
|
||||
}
|
||||
else {
|
||||
toolbar.hidden = true;
|
||||
extendedToolbar.hidden = false;
|
||||
itemPane.hidden = _pdfTabHidden;
|
||||
}
|
||||
|
||||
let state = contextualDeck.children[contextualDeck.selectedIndex].getAttribute('state');
|
||||
let mainDeck = document.getElementById('zotero-item-pane-main-deck');
|
||||
if (state == 0) {
|
||||
pane.setAttribute('data-mode', 'item');
|
||||
document.getElementById('temp-toggle-1').innerHTML = '[📄] 📒';
|
||||
document.getElementById('temp-toggle-2').innerHTML = '[📄] 📒';
|
||||
mainDeck.selectedIndex = state;
|
||||
}
|
||||
else if (state == 1) {
|
||||
pane.setAttribute('data-mode', 'notes');
|
||||
document.getElementById('temp-toggle-1').innerHTML = '📄 [📒]';
|
||||
document.getElementById('temp-toggle-2').innerHTML = '📄 [📒]';
|
||||
mainDeck.selectedIndex = state;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.addPDFTabContext = function (tabID, itemID) {
|
||||
let contextualDeck = document.getElementById('zotero-item-pane-contextual-deck');
|
||||
|
||||
let container = document.createElement('vbox');
|
||||
container.id = tabID + '-context';
|
||||
container.className = 'zotero-item-pane-content';
|
||||
contextualDeck.appendChild(container);
|
||||
|
||||
var item = Zotero.Items.get(itemID);
|
||||
if (!item.parentID) {
|
||||
container.append('The PDF doesn\'t have a parent');
|
||||
return;
|
||||
}
|
||||
|
||||
let parentID = item.parentID;
|
||||
|
||||
let mainDeck = document.getElementById('zotero-item-pane-main-deck');
|
||||
let pinDeck = document.getElementById('zotero-item-pane-pin-deck2');
|
||||
container.setAttribute('state', (mainDeck.selectedIndex == 1 && pinDeck.selectedIndex == 1) ? 1 : 0)
|
||||
|
||||
|
||||
let parentItem = Zotero.Items.get(parentID);
|
||||
|
||||
let tabbox = document.createElement('tabbox');
|
||||
tabbox.setAttribute('flex', '1');
|
||||
tabbox.className = 'zotero-view-tabbox';
|
||||
let tabs = document.createElement('tabs');
|
||||
tabs.className = 'zotero-editpane-tabs';
|
||||
|
||||
container.append(tabbox);
|
||||
|
||||
|
||||
let tabInfo = document.createElement('tab');
|
||||
tabInfo.setAttribute('label', Zotero.Intl.strings['zotero.tabs.info.label']);
|
||||
let tabNotes = document.createElement('tab');
|
||||
tabNotes.setAttribute('label', Zotero.Intl.strings['zotero.tabs.notes.label']);
|
||||
let tabTags = document.createElement('tab');
|
||||
tabTags.setAttribute('label', Zotero.Intl.strings['zotero.tabs.tags.label']);
|
||||
let tabRelated = document.createElement('tab');
|
||||
tabRelated.setAttribute('label', Zotero.Intl.strings['zotero.tabs.related.label']);
|
||||
tabs.append(tabInfo, tabNotes, tabTags, tabRelated);
|
||||
|
||||
let tabpanels = document.createElement('tabpanels');
|
||||
tabpanels.setAttribute('flex', '1');
|
||||
tabpanels.className = 'zotero-view-item';
|
||||
|
||||
tabbox.append(tabs, tabpanels);
|
||||
|
||||
let panelInfo = document.createElement('tabpanel');
|
||||
panelInfo.setAttribute('flex', '1')
|
||||
panelInfo.className = 'zotero-editpane-item-box';
|
||||
let itemBox = document.createElement('zoteroitembox');
|
||||
itemBox.setAttribute('flex', '1');
|
||||
panelInfo.append(itemBox);
|
||||
|
||||
let panelNotes = document.createElement('tabpanel');
|
||||
panelNotes.setAttribute('flex', '1');
|
||||
panelNotes.setAttribute('orient', 'vertical');
|
||||
|
||||
var deck = document.createElement('deck');
|
||||
deck.setAttribute('flex', '1');
|
||||
|
||||
panelNotes.append(deck);
|
||||
|
||||
var vbox2 = document.createElement('vbox');
|
||||
|
||||
var backButton = document.createElementNS(HTML_NS, 'div');
|
||||
backButton.className = 'item-pane-back-button';
|
||||
backButton.textContent = (Zotero.dir == 'ltr' ? '←' : '→') + ' '
|
||||
+ Zotero.getString('general.back');
|
||||
backButton.addEventListener('click', () => {
|
||||
deck.setAttribute('selectedIndex', 0);
|
||||
});
|
||||
|
||||
let note = document.createElement('zoteronoteeditor');
|
||||
note.setAttribute('flex', 1);
|
||||
|
||||
vbox2.append(backButton, note);
|
||||
|
||||
|
||||
var vbox = document.createElement('vbox');
|
||||
vbox.setAttribute('flex', '1');
|
||||
vbox.setAttribute('class', 'zotero-box');
|
||||
panelNotes.append(vbox);
|
||||
|
||||
var hbox = document.createElement('hbox');
|
||||
hbox.setAttribute('align', 'center');
|
||||
|
||||
var label = document.createElement('label');
|
||||
var button = document.createElement('button');
|
||||
button.setAttribute('label', Zotero.Intl.strings['zotero.item.add']);
|
||||
button.addEventListener('click', () => {
|
||||
deck.setAttribute('selectedIndex', 1);
|
||||
let item = new Zotero.Item('note');
|
||||
item.libraryID = parentItem.libraryID;
|
||||
item.parentItemID = parentItem.id;
|
||||
note.mode = 'edit';
|
||||
note.item = item;
|
||||
note.focus();
|
||||
});
|
||||
hbox.append(label, button);
|
||||
|
||||
var grid = document.createElement('grid');
|
||||
grid.setAttribute('flex', 1);
|
||||
var columns = document.createElement('columns');
|
||||
var column = document.createElement('column');
|
||||
column.setAttribute('flex', 1);
|
||||
columns.append(column);
|
||||
var column = document.createElement('column');
|
||||
columns.append(column);
|
||||
grid.append(columns);
|
||||
var rows = document.createElement('rows');
|
||||
rows.setAttribute('flex', 1);
|
||||
grid.append(rows);
|
||||
|
||||
vbox.append(hbox, grid);
|
||||
|
||||
deck.append(vbox, vbox2);
|
||||
|
||||
deck.setAttribute('selectedIndex', 0);
|
||||
deck.className = 'zotero-item-pane-content';
|
||||
|
||||
|
||||
let panelTags = document.createElement('tabpanel');
|
||||
panelTags.setAttribute('orient', 'vertical');
|
||||
panelTags.setAttribute('context', 'tags-context-menu');
|
||||
panelTags.className = 'tags-pane';
|
||||
panelTags.style.display = 'flex';
|
||||
|
||||
var div = document.createElementNS(HTML_NS, 'div');
|
||||
div.className = 'tags-box-container';
|
||||
div.style.display = 'flex';
|
||||
div.style.flexGrow = '1';
|
||||
panelTags.append(div);
|
||||
|
||||
let panelRelated = document.createElement('tabpanel');
|
||||
let relatedBox = document.createElement('relatedbox');
|
||||
relatedBox.setAttribute('flex', '1');
|
||||
relatedBox.className = 'zotero-editpane-related';
|
||||
panelRelated.append(relatedBox);
|
||||
|
||||
tabpanels.append(panelInfo, panelNotes, panelTags, panelRelated);
|
||||
|
||||
itemBox.mode = 'edit';
|
||||
itemBox.item = Zotero.Items.get(parentID);
|
||||
|
||||
relatedBox.mode = 'edit';
|
||||
relatedBox.item = parentItem;
|
||||
|
||||
panelRelated.addEventListener('click', (event) => {
|
||||
if (event.originalTarget.closest('.zotero-clicky')) {
|
||||
Zotero_Tabs.select('zotero-pane');
|
||||
}
|
||||
});
|
||||
|
||||
let _renderNotesPanel = () => {
|
||||
while (rows.firstChild) {
|
||||
rows.firstChild.remove();
|
||||
}
|
||||
|
||||
let parentNotes = Zotero.Items.get(parentItem.getNotes());
|
||||
this._appendNoteRows(parentNotes, rows, true, (id) => {
|
||||
deck.setAttribute('selectedIndex', 1);
|
||||
note.mode = 'edit';
|
||||
note.item = Zotero.Items.get(id);
|
||||
note.parentItem = null;
|
||||
}, (id) => {
|
||||
ZoteroItemPane.removeNote(id);
|
||||
});
|
||||
|
||||
var c = parentNotes.length;
|
||||
var str = 'pane.item.notes.count.' + (c == 0 && 'zero' || c == 1 && 'singular' || 'plural');
|
||||
label.value = Zotero.getString(str, [c]);
|
||||
}
|
||||
|
||||
_contextNoteUpdaters.push({
|
||||
tabID,
|
||||
callback: _renderNotesPanel
|
||||
});
|
||||
|
||||
_renderNotesPanel();
|
||||
|
||||
let mode = 'edit';
|
||||
|
||||
let _tagsBox = { current: null };
|
||||
let focusItemsList = false;
|
||||
|
||||
let _renderTagsPanel = () => {
|
||||
ReactDOM.render(
|
||||
<TagsBoxContainer
|
||||
key={'tagsBox-' + parentItem.id}
|
||||
item={parentItem}
|
||||
editable={mode != 'view'}
|
||||
ref={_tagsBox}
|
||||
onResetSelection={focusItemsList}
|
||||
/>,
|
||||
div
|
||||
);
|
||||
}
|
||||
|
||||
_renderTagsPanel();
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener("load", function(e) { ZoteroItemPane.onLoad(e); }, false);
|
||||
|
|
|
@ -34,138 +34,116 @@
|
|||
<script src="include.js"/>
|
||||
<script src="itemPane.js"></script>
|
||||
|
||||
<vbox id="zotero-item-pane"
|
||||
zotero-persist="width height"
|
||||
data-type="library"
|
||||
data-mode="item"
|
||||
>
|
||||
<hbox id="zotero-item-pane-padding-top" height="32" hidden="true" align="right">
|
||||
<button id="temp-toggle-2" style="min-width: 37px; padding: 2px; font-size: 13px;">[📄] 📒</button>
|
||||
<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>
|
||||
|
||||
<html:div id="item-pane-title"/>
|
||||
<!-- 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>
|
||||
|
||||
<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>
|
||||
|
||||
<!-- 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" class="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" class="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" class="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" class="zotero-view-item" flex="1">
|
||||
<tabpanel flex="1">
|
||||
<zoteroitembox id="zotero-editpane-item-box" class="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" class="tags-pane" orient="vertical" context="tags-context-menu">
|
||||
<html:div id="tags-box-container" class="tags-box-container"></html:div>
|
||||
</tabpanel>
|
||||
|
||||
<tabpanel>
|
||||
<relatedbox id="zotero-editpane-related" class="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'*/"/>
|
||||
<!-- TODO: Localize -->
|
||||
<button id="zotero-view-note-sidebar-button"
|
||||
label="Edit in notes sidebar"
|
||||
oncommand="ZoteroItemPane.openNoteSidebar()"/>
|
||||
<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>
|
||||
<!-- 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" class="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>
|
||||
|
||||
<vbox id="zotero-item-pane-pin-deck"></vbox>
|
||||
<!-- Regular item -->
|
||||
<tabbox id="zotero-view-tabbox" class="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" class="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" class="zotero-view-item" flex="1">
|
||||
<tabpanel flex="1">
|
||||
<zoteroitembox id="zotero-editpane-item-box" class="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" class="tags-pane" orient="vertical" context="tags-context-menu">
|
||||
<html:div id="tags-box-container" class="tags-box-container"></html:div>
|
||||
</tabpanel>
|
||||
|
||||
<tabpanel>
|
||||
<relatedbox id="zotero-editpane-related" class="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="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>
|
||||
</overlay>
|
|
@ -24,9 +24,10 @@
|
|||
<script type="application/javascript">
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
</script>
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||
<script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
|
||||
<script type="application/javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
|
||||
<script src="include.js"/>
|
||||
<commandset id="mainCommandSet">
|
||||
<!--FILE-->
|
||||
<command id="cmd_quitApplication" oncommand="goQuitApplication();"/>
|
||||
|
@ -115,27 +116,5 @@
|
|||
<popupset id="zotero-reader-popupset">
|
||||
</popupset>
|
||||
</vbox>
|
||||
<splitter id="zotero-reader-splitter"
|
||||
hidden="true"
|
||||
resizebefore="closest"
|
||||
resizeafter="closest"
|
||||
collapse="after"
|
||||
orient="horizontal"
|
||||
zotero-persist="state orient" />
|
||||
<vbox flex="0" id="zotero-reader-note-sidebar" width="350" hidden="true">
|
||||
<vbox id="zotero-reader-sidebar-cover" flex="1">
|
||||
<label>Drag a note here…</label>
|
||||
</vbox>
|
||||
<vbox id="zotero-reader-sidebar-container" flex="1" style="overflow:auto;" hidden="true">
|
||||
<zoteronoteeditor id="zotero-reader-editor" flex="1" notitle="1"
|
||||
previousfocus="zotero-items-tree"
|
||||
onerror="/*this.mode = 'view'*/"
|
||||
/>
|
||||
|
||||
<button id="zotero-view-note-button" label="Close"
|
||||
oncommand="document.getElementById('zotero-reader-sidebar-container').hidden = true;document.getElementById('zotero-reader-sidebar-cover').hidden = false;"/>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<script src="include.js"/>
|
||||
</window>
|
||||
|
|
|
@ -54,7 +54,8 @@ const ZoteroStandalone = new function() {
|
|||
notify: async (action, type, ids, extraData) => {
|
||||
if (action == 'select') {
|
||||
// "library" or "reader"
|
||||
this.switchMenuType(extraData.type);
|
||||
this.switchMenuType(extraData[ids[0]].type);
|
||||
setTimeout(() => ZoteroPane.updateToolbarPosition(), 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -113,7 +113,7 @@ var Zotero_Tabs = new function () {
|
|||
index = index || this._tabs.length;
|
||||
this._tabs.splice(index, 0, tab);
|
||||
this._update();
|
||||
Zotero.Notifier.trigger('add', 'tab', id, notifierData);
|
||||
Zotero.Notifier.trigger('add', 'tab', [id], { [id]: notifierData });
|
||||
if (select) {
|
||||
this.select(id);
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ var Zotero_Tabs = new function () {
|
|||
if (tab.onClose) {
|
||||
tab.onClose();
|
||||
}
|
||||
Zotero.Notifier.trigger('close', 'tab', tab.id);
|
||||
Zotero.Notifier.trigger('close', 'tab', [tab.id]);
|
||||
this._update();
|
||||
};
|
||||
|
||||
|
@ -199,7 +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();
|
||||
Zotero.Notifier.trigger('select', 'tab', tab.id, { type: tab.type });
|
||||
Zotero.Notifier.trigger('select', 'tab', [tab.id], { [tab.id]: { type: tab.type } });
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,6 +33,7 @@ class EditorInstance {
|
|||
this.onNavigate = options.onNavigate;
|
||||
this._item = options.item;
|
||||
this._readOnly = options.readOnly;
|
||||
this._onReturn = options.onReturn;
|
||||
this._iframeWindow = options.iframeWindow;
|
||||
this._popup = options.popup;
|
||||
this._state = options.state;
|
||||
|
@ -63,6 +64,7 @@ class EditorInstance {
|
|||
action: 'init',
|
||||
value: this._state || this._item.note,
|
||||
readOnly: this._readOnly,
|
||||
enableReturnButton: !!this._onReturn,
|
||||
placeholder: options.placeholder,
|
||||
dir: Zotero.dir,
|
||||
font: this._getFont(),
|
||||
|
@ -139,6 +141,30 @@ class EditorInstance {
|
|||
_handleFontChange = () => {
|
||||
this._postMessage({ action: 'updateFont', font: this._getFont() });
|
||||
}
|
||||
|
||||
async _digestExternalNote(itemID) {
|
||||
let item = await Zotero.Items.getAsync(itemID);
|
||||
item._loaded.childItems = true;
|
||||
let note = item.note;
|
||||
let attachments = await Zotero.Items.getAsync(item.getAttachments());
|
||||
for (let attachment of attachments) {
|
||||
let path = await attachment.getFilePathAsync();
|
||||
let buf = await OS.File.read(path, {});
|
||||
buf = new Uint8Array(buf).buffer;
|
||||
let blob = new this._iframeWindow.Blob([buf], { type: attachment.attachmentContentType });
|
||||
let clonedAttachment = await Zotero.Attachments.importEmbeddedImage({
|
||||
blob,
|
||||
parentItemID: this._item.id,
|
||||
saveOptions: {
|
||||
notifierData: {
|
||||
noteEditorID: this.instanceID
|
||||
}
|
||||
}
|
||||
});
|
||||
note = note.replace(attachment.key, clonedAttachment.key);
|
||||
}
|
||||
return note;
|
||||
}
|
||||
|
||||
async _annotationsToInsertionList(annotations) {
|
||||
let list = [];
|
||||
|
@ -148,25 +174,28 @@ class EditorInstance {
|
|||
continue;
|
||||
}
|
||||
let item = attachmentItem.parentID && await Zotero.Items.getAsync(attachmentItem.parentID) || attachmentItem;
|
||||
annotation.uri = Zotero.URI.getItemURI(attachmentItem);
|
||||
if (item !== attachmentItem) {
|
||||
annotation.parentURI = Zotero.URI.getItemURI(item);
|
||||
|
||||
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: {}
|
||||
};
|
||||
let formattedCitation = (await this._getFormattedCitationParts(citation)).join(';');
|
||||
list.push({ annotation, citation, formattedCitation });
|
||||
}
|
||||
else {
|
||||
list.push({ annotation });
|
||||
}
|
||||
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: {}
|
||||
};
|
||||
let formattedCitation = (await this._getFormattedCitationParts(citation)).join(';');
|
||||
list.push({ annotation, citation, formattedCitation });
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
@ -187,18 +216,24 @@ class EditorInstance {
|
|||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let citation = {
|
||||
citationItems: [{
|
||||
uris: [Zotero.URI.getItemURI(item)],
|
||||
itemData: Zotero.Cite.System.prototype.retrieveItem(item)
|
||||
}],
|
||||
properties: {}
|
||||
};
|
||||
|
||||
if (item.isRegularItem()) {
|
||||
let citation = {
|
||||
citationItems: [{
|
||||
uris: [Zotero.URI.getItemURI(item)],
|
||||
itemData: Zotero.Cite.System.prototype.retrieveItem(item)
|
||||
}],
|
||||
properties: {}
|
||||
};
|
||||
|
||||
let formattedCitation = (await this._getFormattedCitationParts(citation)).join(';');
|
||||
let formattedCitation = (await this._getFormattedCitationParts(citation)).join(';');
|
||||
|
||||
list.push({ citation, formattedCitation });
|
||||
list.push({ citation, formattedCitation });
|
||||
}
|
||||
else if (item.isNote()) {
|
||||
let note = await this._digestExternalNote(item.id);
|
||||
list.push({ note });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type === 'zotero/annotation') {
|
||||
|
@ -343,6 +378,10 @@ class EditorInstance {
|
|||
this._openPopup(x, y, pos, itemGroups);
|
||||
return;
|
||||
}
|
||||
case 'return': {
|
||||
this._onReturn();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,17 +8,21 @@ class ReaderInstance {
|
|||
constructor() {
|
||||
this.pdfStateFileName = '.zotero-pdf-state';
|
||||
this.annotationItemIDs = [];
|
||||
this.onChangeSidebarWidth = null;
|
||||
this._instanceID = Zotero.Utilities.randomString();
|
||||
this._window = null;
|
||||
this._iframeWindow = null;
|
||||
this._itemID = null;
|
||||
this._state = null;
|
||||
this._prevHistory = [];
|
||||
this._nextHistory = [];
|
||||
this._isReaderInitialized = false;
|
||||
this._showItemPaneToggle = false;
|
||||
this._initPromise = new Promise((resolve, reject) => {
|
||||
this._resolveInitPromise = resolve;
|
||||
this._rejectInitPromise = reject;
|
||||
});
|
||||
}
|
||||
|
||||
async open({ itemID, state, location, skipHistory }) {
|
||||
async open({ itemID, state, location }) {
|
||||
if (itemID === this._itemID) {
|
||||
return false;
|
||||
}
|
||||
|
@ -26,13 +30,6 @@ class ReaderInstance {
|
|||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
if (this._itemID && !skipHistory) {
|
||||
this._prevHistory.push({
|
||||
itemID: this._itemID,
|
||||
state: this._state
|
||||
});
|
||||
this._nextHistory = [];
|
||||
}
|
||||
this._itemID = item.id;
|
||||
let path = await item.getFilePathAsync();
|
||||
let buf = await OS.File.read(path, {});
|
||||
|
@ -51,9 +48,11 @@ class ReaderInstance {
|
|||
annotations,
|
||||
state,
|
||||
location,
|
||||
enablePrev: !!this._prevHistory.length,
|
||||
enableNext: !!this._nextHistory.length,
|
||||
promptImport: !!Zotero.PDF.hasUnmachedAnnotations[this._itemID]
|
||||
promptImport: !!Zotero.PDF.hasUnmachedAnnotations[this._itemID],
|
||||
showItemPaneToggle: this._showItemPaneToggle,
|
||||
sidebarWidth: this._sidebarWidth,
|
||||
sidebarOpen: this._sidebarOpen,
|
||||
bottomPlaceholderHeight: this._bottomPlaceholderHeight
|
||||
}, [buf]);
|
||||
return true;
|
||||
}
|
||||
|
@ -97,6 +96,28 @@ class ReaderInstance {
|
|||
toggleImportPrompt(enable) {
|
||||
this._postMessage({ action: 'toggleImportPrompt', enable });
|
||||
}
|
||||
|
||||
enableAddToNote(enable) {
|
||||
this._postMessage({ action: 'enableAddToNote', enable });
|
||||
}
|
||||
|
||||
setSidebarWidth(width) {
|
||||
this._postMessage({ action: 'setSidebarWidth', width });
|
||||
}
|
||||
|
||||
setSidebarOpen(open) {
|
||||
this._postMessage({ action: 'setSidebarOpen', open });
|
||||
}
|
||||
|
||||
async setBottomPlaceholderHeight(height) {
|
||||
await this._initPromise;
|
||||
this._postMessage({ action: 'setBottomPlaceholderHeight', height });
|
||||
}
|
||||
|
||||
async setToolbarPlaceholderWidth(width) {
|
||||
await this._initPromise;
|
||||
this._postMessage({ action: 'setToolbarPlaceholderWidth', width });
|
||||
}
|
||||
|
||||
async _saveState(state) {
|
||||
let item = Zotero.Items.get(this._itemID);
|
||||
|
@ -137,20 +158,6 @@ class ReaderInstance {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Pass sidebar state to the responsible pdf-reader button
|
||||
_toggleNoteSidebar(isToggled) {
|
||||
let splitter = this._window.document.getElementById('zotero-reader-splitter');
|
||||
let sidebar = this._window.document.getElementById('zotero-reader-note-sidebar');
|
||||
if (isToggled) {
|
||||
splitter.hidden = false;
|
||||
sidebar.hidden = false;
|
||||
}
|
||||
else {
|
||||
splitter.hidden = true;
|
||||
sidebar.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
_getColorIcon(color, selected) {
|
||||
let stroke = selected ? 'lightgray' : 'transparent';
|
||||
let fill = '%23' + color.slice(1);
|
||||
|
@ -176,20 +183,23 @@ class ReaderInstance {
|
|||
popup.addEventListener('popuphidden', function () {
|
||||
popup.remove();
|
||||
});
|
||||
let menuitem;
|
||||
// Add to note
|
||||
let menuitem = this._window.document.createElement('menuitem');
|
||||
menuitem.setAttribute('label', 'Add to Note');
|
||||
menuitem.addEventListener('command', () => {
|
||||
let data = {
|
||||
action: 'popupCmd',
|
||||
cmd: 'addToNote',
|
||||
id: annotationId
|
||||
};
|
||||
this._postMessage(data);
|
||||
});
|
||||
popup.appendChild(menuitem);
|
||||
// Separator
|
||||
popup.appendChild(this._window.document.createElement('menuseparator'));
|
||||
if (this._window.ZoteroContextPane.getActiveEditor()) {
|
||||
menuitem = this._window.document.createElement('menuitem');
|
||||
menuitem.setAttribute('label', 'Add to Note');
|
||||
menuitem.addEventListener('command', () => {
|
||||
let data = {
|
||||
action: 'popupCmd',
|
||||
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');
|
||||
|
@ -270,26 +280,8 @@ class ReaderInstance {
|
|||
Zotero.debug('Received message from pdf-reader iframe: ' + JSON.stringify(data));
|
||||
message = data.message;
|
||||
switch (message.action) {
|
||||
case 'navigatePrev': {
|
||||
let prev = this._prevHistory.pop();
|
||||
if (prev) {
|
||||
this._nextHistory.push({
|
||||
itemID: this._itemID,
|
||||
state: this._state
|
||||
});
|
||||
this.open({ itemID: prev.itemID, state: prev.state, skipHistory: true });
|
||||
}
|
||||
return;
|
||||
}
|
||||
case 'navigateNext': {
|
||||
let next = this._nextHistory.pop();
|
||||
if (next) {
|
||||
this._prevHistory.push({
|
||||
itemID: this._itemID,
|
||||
state: this._state
|
||||
});
|
||||
this.open({ itemID: next.itemID, state: next.state, skipHistory: true });
|
||||
}
|
||||
case 'initialized': {
|
||||
this._resolveInitPromise();
|
||||
return;
|
||||
}
|
||||
case 'setAnnotation': {
|
||||
|
@ -395,6 +387,20 @@ class ReaderInstance {
|
|||
this._toggleNoteSidebar(isToggled);
|
||||
return;
|
||||
}
|
||||
case 'changeSidebarWidth': {
|
||||
let { width } = message;
|
||||
if (this.onChangeSidebarWidth) {
|
||||
this.onChangeSidebarWidth(width);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case 'changeSidebarOpen': {
|
||||
let { open } = message;
|
||||
if (this.onChangeSidebarOpen) {
|
||||
this.onChangeSidebarOpen(open);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -459,8 +465,12 @@ class ReaderInstance {
|
|||
}
|
||||
|
||||
class ReaderTab extends ReaderInstance {
|
||||
constructor(itemID) {
|
||||
constructor({ itemID, sidebarWidth, sidebarOpen, bottomPlaceholderHeight }) {
|
||||
super();
|
||||
this._sidebarWidth = sidebarWidth;
|
||||
this._sidebarOpen = sidebarOpen;
|
||||
this._bottomPlaceholderHeight = bottomPlaceholderHeight;
|
||||
this._showItemPaneToggle = true;
|
||||
this._window = Services.wm.getMostRecentWindow('navigator:browser');
|
||||
let { id, container } = this._window.Zotero_Tabs.add({
|
||||
type: 'reader',
|
||||
|
@ -493,7 +503,7 @@ class ReaderTab extends ReaderInstance {
|
|||
}
|
||||
});
|
||||
|
||||
this._iframe.setAttribute('tooltip', 'iframeTooltip');
|
||||
this._iframe.setAttribute('tooltip', 'html-tooltip');
|
||||
}
|
||||
|
||||
close() {
|
||||
|
@ -534,7 +544,7 @@ class ReaderTab extends ReaderInstance {
|
|||
}
|
||||
|
||||
_addToNote(annotations) {
|
||||
let noteEditor = this._window.ZoteroItemPane.getActiveNote();
|
||||
let noteEditor = this._window.ZoteroContextPane.getActiveEditor();
|
||||
if (!noteEditor) {
|
||||
return;
|
||||
}
|
||||
|
@ -548,9 +558,11 @@ class ReaderTab extends ReaderInstance {
|
|||
|
||||
|
||||
class ReaderWindow extends ReaderInstance {
|
||||
constructor() {
|
||||
constructor({ sidebarWidth, sidebarOpen, bottomPlaceholderHeight }) {
|
||||
super();
|
||||
|
||||
this._sidebarWidth = sidebarWidth;
|
||||
this._sidebarOpen = sidebarOpen;
|
||||
this._bottomPlaceholderHeight = bottomPlaceholderHeight;
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
@ -564,8 +576,6 @@ class ReaderWindow extends ReaderInstance {
|
|||
|
||||
this._window.addEventListener('DOMContentLoaded', (event) => {
|
||||
if (event.target === this._window.document) {
|
||||
this._window.addEventListener('dragover', this._handleDragOver, true);
|
||||
this._window.addEventListener('drop', this._handleDrop, true);
|
||||
this._window.addEventListener('keypress', this._handleKeyPress);
|
||||
|
||||
this._popupset = this._window.document.getElementById('zotero-reader-popupset');
|
||||
|
@ -583,23 +593,6 @@ class ReaderWindow extends ReaderInstance {
|
|||
this._postMessage(data);
|
||||
};
|
||||
|
||||
let editor = this._window.document.getElementById('zotero-reader-editor');
|
||||
editor.navigateHandler = async (uri, location) => {
|
||||
let item = await Zotero.URI.getURIItem(uri);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
if (item.id === this._itemID) {
|
||||
this.navigate(location);
|
||||
}
|
||||
else {
|
||||
await this.open({
|
||||
itemID: item.id,
|
||||
location
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this._iframe = this._window.document.getElementById('reader');
|
||||
}
|
||||
|
||||
|
@ -618,78 +611,82 @@ class ReaderWindow extends ReaderInstance {
|
|||
this._window.document.title = title;
|
||||
}
|
||||
|
||||
_handleDragOver = (event) => {
|
||||
if (event.dataTransfer.getData('zotero/item')) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
_handleDrop = (event) => {
|
||||
let data;
|
||||
if (!(data = event.dataTransfer.getData('zotero/item'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ids = data.split(',').map(id => parseInt(id));
|
||||
let item = Zotero.Items.get(ids[0]);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.isNote()) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
let cover = this._window.document.getElementById('zotero-reader-sidebar-cover');
|
||||
let container = this._window.document.getElementById('zotero-reader-sidebar-container');
|
||||
let splitter = this._window.document.getElementById('zotero-reader-splitter');
|
||||
|
||||
cover.hidden = true;
|
||||
container.hidden = false;
|
||||
splitter.hidden = false;
|
||||
|
||||
let editor = this._window.document.getElementById('zotero-reader-editor');
|
||||
let notebox = this._window.document.getElementById('zotero-reader-note-sidebar');
|
||||
editor.mode = 'edit';
|
||||
notebox.hidden = false;
|
||||
editor.item = item;
|
||||
}
|
||||
else if (item.isAttachment() && item.attachmentContentType === 'application/pdf') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.open({ itemID: item.id });
|
||||
}
|
||||
else if (item.isRegularItem()) {
|
||||
let attachments = item.getAttachments();
|
||||
if (attachments.length === 1) {
|
||||
let id = attachments[0];
|
||||
let attachment = Zotero.Items.get(id);
|
||||
if (attachment.attachmentContentType === 'application/pdf') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.open({ itemID: attachment.id });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_handleKeyPress = (event) => {
|
||||
if ((Zotero.isMac && event.metaKey || event.ctrlKey)
|
||||
&& !event.shiftKey && !event.altKey && event.key === 'w') {
|
||||
this._window.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class Reader {
|
||||
constructor() {
|
||||
this._sidebarWidth = 200;
|
||||
this._sidebarOpen = false;
|
||||
this._bottomPlaceholderHeight = 800;
|
||||
this._readers = [];
|
||||
this._notifierID = Zotero.Notifier.registerObserver(this, ['item'], 'reader');
|
||||
this.onChangeSidebarWidth = null;
|
||||
this.onChangeSidebarOpen = null;
|
||||
|
||||
this._debounceSidebarWidthUpdate = Zotero.Utilities.debounce(() => {
|
||||
let readers = this._readers.filter(r => r instanceof ReaderTab);
|
||||
for (let reader of readers) {
|
||||
reader.setSidebarWidth(this._sidebarWidth);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
getSidebarWidth() {
|
||||
return this._sidebarWidth;
|
||||
}
|
||||
|
||||
_loadSidebarOpenState() {
|
||||
let win = Zotero.getMainWindow();
|
||||
if (win) {
|
||||
let pane = win.document.getElementById('zotero-reader-sidebar-pane');
|
||||
this._sidebarOpen = pane.getAttribute('collapsed') == 'false';
|
||||
}
|
||||
}
|
||||
|
||||
_setSidebarOpenState() {
|
||||
let win = Zotero.getMainWindow();
|
||||
if (win) {
|
||||
let pane = win.document.getElementById('zotero-reader-sidebar-pane');
|
||||
pane.setAttribute('collapsed', this._sidebarOpen ? 'false' : 'true');
|
||||
}
|
||||
}
|
||||
|
||||
getSidebarOpen() {
|
||||
return this._sidebarOpen;
|
||||
}
|
||||
|
||||
setSidebarWidth(width) {
|
||||
this._sidebarWidth = width;
|
||||
let readers = this._readers.filter(r => r instanceof ReaderTab);
|
||||
for (let reader of readers) {
|
||||
reader.setSidebarWidth(width);
|
||||
}
|
||||
}
|
||||
|
||||
setSidebarOpen(open) {
|
||||
this._sidebarOpen = open;
|
||||
let readers = this._readers.filter(r => r instanceof ReaderTab);
|
||||
for (let reader of readers) {
|
||||
reader.setSidebarOpen(open);
|
||||
}
|
||||
this._setSidebarOpenState();
|
||||
}
|
||||
|
||||
setBottomPlaceholderHeight(height) {
|
||||
this._bottomPlaceholderHeight = height;
|
||||
let readers = this._readers.filter(r => r instanceof ReaderTab);
|
||||
for (let reader of readers) {
|
||||
reader.setBottomPlaceholderHeight(height);
|
||||
}
|
||||
}
|
||||
|
||||
notify(event, type, ids, extraData) {
|
||||
// Listen for the parent item, PDF attachment and its annotation items updates
|
||||
for (let readerWindow of this._readers) {
|
||||
|
@ -746,6 +743,7 @@ class Reader {
|
|||
}
|
||||
|
||||
async open(itemID, location, openWindow) {
|
||||
this._loadSidebarOpenState();
|
||||
this.triggerAnnotationsImportCheck(itemID);
|
||||
let reader;
|
||||
|
||||
|
@ -762,21 +760,44 @@ class Reader {
|
|||
}
|
||||
}
|
||||
else if (openWindow) {
|
||||
reader = new ReaderWindow();
|
||||
reader = new ReaderWindow({
|
||||
sidebarWidth: this._sidebarWidth,
|
||||
sidebarOpen: this._sidebarOpen,
|
||||
bottomPlaceholderHeight: this._bottomPlaceholderHeight
|
||||
});
|
||||
this._readers.push(reader);
|
||||
if (!(await reader.open({ itemID, location }))) {
|
||||
return;
|
||||
}
|
||||
this._readers.push(reader);
|
||||
reader._window.addEventListener('unload', () => {
|
||||
this._readers.splice(this._readers.indexOf(reader), 1);
|
||||
});
|
||||
}
|
||||
else {
|
||||
reader = new ReaderTab(itemID);
|
||||
reader = new ReaderTab({
|
||||
itemID,
|
||||
sidebarWidth: this._sidebarWidth,
|
||||
sidebarOpen: this._sidebarOpen,
|
||||
bottomPlaceholderHeight: this._bottomPlaceholderHeight
|
||||
});
|
||||
this._readers.push(reader);
|
||||
if (!(await reader.open({ itemID, location }))) {
|
||||
return;
|
||||
}
|
||||
this._readers.push(reader);
|
||||
reader.onChangeSidebarWidth = (width) => {
|
||||
this._sidebarWidth = width;
|
||||
this._debounceSidebarWidthUpdate();
|
||||
if (this.onChangeSidebarWidth) {
|
||||
this.onChangeSidebarWidth(width);
|
||||
}
|
||||
};
|
||||
reader.onChangeSidebarOpen = (open) => {
|
||||
this._sidebarOpen = open;
|
||||
this.setSidebarOpen(open);
|
||||
if (this.onChangeSidebarOpen) {
|
||||
this.onChangeSidebarOpen(open);
|
||||
}
|
||||
};
|
||||
reader.onClose = () => {
|
||||
this._readers.splice(this._readers.indexOf(reader), 1);
|
||||
};
|
||||
|
|
|
@ -1199,8 +1199,6 @@ var ZoteroPane = new function()
|
|||
// Rename tab
|
||||
Zotero_Tabs.rename('zotero-pane', collectionTreeRow.getName());
|
||||
|
||||
ZoteroItemPane.updateStandaloneNotesList(true);
|
||||
|
||||
// Clear quick search and tag selector when switching views
|
||||
document.getElementById('zotero-tb-search').value = "";
|
||||
if (ZoteroPane.tagSelector) {
|
||||
|
@ -5060,6 +5058,7 @@ var ZoteroPane = new function()
|
|||
|
||||
this.updateToolbarPosition();
|
||||
this.updateTagsBoxSize();
|
||||
ZoteroContextPane.update();
|
||||
}
|
||||
|
||||
|
||||
|
@ -5195,8 +5194,6 @@ 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
|
||||
|
||||
// TODO: Fix this together with stacked view
|
||||
itemPane.setAttribute("flex", stackedLayout ? 1 : 0);
|
||||
|
||||
this.handleTagSelectorResize();
|
||||
|
|
|
@ -156,6 +156,8 @@
|
|||
<!ENTITY zotero.toolbar.attachment.add "Store Copy of File…">
|
||||
<!ENTITY zotero.toolbar.attachment.weblink "Save Link to Current Page">
|
||||
<!ENTITY zotero.toolbar.attachment.snapshot "Take Snapshot of Current Page">
|
||||
<!ENTITY zotero.toolbar.context.item "Item">
|
||||
<!ENTITY zotero.toolbar.context.notes "Notes">
|
||||
|
||||
<!ENTITY zotero.tagSelector.noTagsToDisplay "No tags to display">
|
||||
<!ENTITY zotero.tagSelector.loadingTags "Loading tags…">
|
||||
|
|
|
@ -401,6 +401,8 @@ pane.item.related.count.singular = %S related:
|
|||
pane.item.related.count.plural = %S related:
|
||||
pane.item.parentItem = Parent Item:
|
||||
|
||||
pane.context.noParent = No parent item
|
||||
|
||||
noteEditor.editNote = Edit Note
|
||||
|
||||
itemTypes.note = Note
|
||||
|
|
71
chrome/skin/default/zotero/contextPane.css
Normal file
|
@ -0,0 +1,71 @@
|
|||
#tabs-deck {
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
#zotero-context-pane {
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
#zotero-context-pane.stacked {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
font-size: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#zotero-context-pane.stacked #zotero-context-toolbar-extension {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#zotero-context-pane .stacked-context-placeholder {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
#zotero-context-pane.standard .stacked-context-placeholder {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#zotero-context-splitter-stacked {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
#zotero-context-pane-inner {
|
||||
width: 0;
|
||||
font: message-box;
|
||||
min-height: 100px;
|
||||
height: 100%;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/*#zotero-context-pane.standard .stacked-splitter {*/
|
||||
/* display: none;*/
|
||||
/*}*/
|
||||
|
||||
#zotero-tab-toolbar-container {
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
right: 0;
|
||||
height: 32px;
|
||||
-moz-appearance: none;
|
||||
background: linear-gradient(to top, #aeaeae 0, #aeaeae 1px, #d3d3d3 1px, #e3e3e3 100%);
|
||||
}
|
||||
|
||||
#zotero-tab-toolbar-container #zotero-tb-locate,
|
||||
#zotero-tab-toolbar-container #zotero-pq-buttons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#zotero-context-toolbar-extension {
|
||||
height: 32px;
|
||||
/* To cover the splitter that has a higher stacking order than our parent */
|
||||
opacity: 0.99;
|
||||
width: 100%;
|
||||
margin-inline-start: -5px;
|
||||
background: linear-gradient(to top, #aeaeae 0, #aeaeae 1px, #d3d3d3 1px, #e3e3e3 100%);
|
||||
}
|
||||
|
||||
.zotero-context-notes-list {
|
||||
padding-top: 5px;
|
||||
}
|
|
@ -45,51 +45,13 @@
|
|||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#zotero-item-pane[data-type='library'] #item-pane-title,
|
||||
#zotero-item-pane[data-mode='notes'] #item-pane-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#item-pane-title {
|
||||
font-size: 16px;
|
||||
padding: 0 10px 6px;
|
||||
}
|
||||
|
||||
#zotero-item-pane-contextual-deck .item-pane-back-button {
|
||||
font-size: 12px;
|
||||
margin: 4px 5px 5px;
|
||||
}
|
||||
|
||||
#zotero-item-pane-pin-deck .item-pane-back-button {
|
||||
font-size: 12px;
|
||||
margin: 7px 6px;
|
||||
}
|
||||
|
||||
#zotero-item-pane-padding-top {
|
||||
/*border-bottom: 1px solid lightgray;*/
|
||||
}
|
||||
|
||||
#zotero-item-pane-pinned-note {
|
||||
.zotero-context-pane-pinned-note {
|
||||
border-top: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.zotero-editpane-tabs {
|
||||
background: #ececec;
|
||||
}
|
||||
|
||||
#temp-toggle-1.mode-item, #temp-toggle-2.mode-item {
|
||||
list-style-image: url(chrome://zotero/skin/treeitem.png);
|
||||
}
|
||||
|
||||
#temp-toggle-1.mode-notes, #temp-toggle-2.mode-notes {
|
||||
list-style-image: url(chrome://zotero/skin/treeitem-note.png);
|
||||
}
|
||||
|
||||
.notes-list-label {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 8px 10px 5px;
|
||||
}
|
||||
/*.zotero-editpane-tabs {*/
|
||||
/* background: #ececec;*/
|
||||
/*}*/
|
||||
|
||||
#retraction-box {
|
||||
cursor: default;
|
||||
|
|
BIN
chrome/skin/default/zotero/mac/item-white.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
chrome/skin/default/zotero/mac/item-white@2x.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
chrome/skin/default/zotero/mac/item.png
Normal file
After Width: | Height: | Size: 166 B |
BIN
chrome/skin/default/zotero/mac/item@2x.png
Normal file
After Width: | Height: | Size: 211 B |
BIN
chrome/skin/default/zotero/mac/menubutton-end-active-pressed.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
BIN
chrome/skin/default/zotero/mac/menubutton-end-active.png
Normal file
After Width: | Height: | Size: 233 B |
BIN
chrome/skin/default/zotero/mac/menubutton-end-active@2x.png
Normal file
After Width: | Height: | Size: 399 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
BIN
chrome/skin/default/zotero/mac/menubutton-start-active.png
Normal file
After Width: | Height: | Size: 282 B |
BIN
chrome/skin/default/zotero/mac/menubutton-start-active@2x.png
Normal file
After Width: | Height: | Size: 543 B |
BIN
chrome/skin/default/zotero/mac/notes-white.png
Normal file
After Width: | Height: | Size: 204 B |
BIN
chrome/skin/default/zotero/mac/notes-white@2x.png
Normal file
After Width: | Height: | Size: 286 B |
BIN
chrome/skin/default/zotero/mac/notes.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
chrome/skin/default/zotero/mac/notes@2x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
|
@ -708,9 +708,23 @@
|
|||
display: inherit !important;
|
||||
}
|
||||
|
||||
#zotero-tab-cover {
|
||||
z-index: 2;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #ececec;
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#zotero-tab-cover label {
|
||||
padding-top: 30px;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.zotero-box {
|
||||
/*margin-left: 5px;*/
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.zotero-box-icon {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 1da855a9e2447ff0a1409401bc2ba87f9b307038
|
||||
Subproject commit be1fa9a77fb9090a1aad9a9cd40b8ebb22ee4281
|
|
@ -1 +1 @@
|
|||
Subproject commit 886e714d3344534b66370010e855ea857f460627
|
||||
Subproject commit e3121e75eb82df8bea6381d390983917bd44395b
|
|
@ -11,6 +11,7 @@
|
|||
@import "abstracts/mixins";
|
||||
@import "abstracts/placeholders";
|
||||
@import "abstracts/utilities";
|
||||
@import "abstracts/split-button";
|
||||
|
||||
// Theme
|
||||
// --------------------------------------------------
|
||||
|
|
489
scss/abstracts/_split-button.scss
Normal file
|
@ -0,0 +1,489 @@
|
|||
|
||||
// The split button was originally created by flachware for pdf-reader:
|
||||
// https://github.com/zotero/pdf-reader/blob/master/src/stylesheets/abstracts/mixins/_split-button.scss
|
||||
|
||||
$accent-color: #0a6cf5; // 215° 96 96
|
||||
$accent-color-darken-6: darken($accent-color, 6%);
|
||||
|
||||
$blue-btn: #90c8f6;
|
||||
|
||||
$toolbar-btn-height: 22px;
|
||||
$toolbar-btn-bg: linear-gradient(to bottom, #fafafa, #f2f2f2);
|
||||
$toolbar-btn-padding: 3px 11px;
|
||||
$toolbar-btn-border: 0;
|
||||
$toolbar-btn-border-radius: 3.75px;
|
||||
$toolbar-btn-margin-x: 4px;
|
||||
$toolbar-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.33), 0 0 0 1px rgba(0, 0, 0, 0.08), 0 1px 0 rgba(0, 0, 0, 0.1);
|
||||
$toolbar-btn-box-shadow-2x: inset 0 0.5px 0.5px rgba(255, 255, 255, 1), 0 0 0 0.5px rgba(0, 0, 0, 0.1), 0 0.75px 0 rgba(0, 0, 0, 0.125);
|
||||
$toolbar-btn-focus-box-shadow: 0 0 0 4px rgba($accent-color, 0.5), $toolbar-btn-box-shadow;
|
||||
$toolbar-btn-focus-box-shadow-2x: 0 0 0 4px rgba($accent-color, 0.5), $toolbar-btn-box-shadow-2x;
|
||||
$toolbar-btn-hover-bg: null;
|
||||
$toolbar-btn-border-hover-color: null;
|
||||
$toolbar-btn-active-bg: linear-gradient(to bottom, #e4e4e4, #ddd);
|
||||
$toolbar-btn-blurred-bg: transparent;
|
||||
$toolbar-btn-blurred-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.11);
|
||||
$toolbar-btn-border-active-color: $blue-btn;
|
||||
$toolbar-btn-icon-active-offset: 0;
|
||||
|
||||
|
||||
//
|
||||
// String functions
|
||||
//
|
||||
|
||||
@function str-replace($string, $token, $replace: "") {
|
||||
$i: str-index($string, $token);
|
||||
|
||||
@while (str-index($string, $token) != null) {
|
||||
$first-part: str-slice($string, 1, ($i - 1));
|
||||
$last-part: str-slice($string, ($i + str-length($token)));
|
||||
$string: str-slice($string, 1, ($i - 1)) + $replace + $last-part;
|
||||
|
||||
$i: str-index($string, $token);
|
||||
}
|
||||
|
||||
@return $string;
|
||||
}
|
||||
|
||||
@function str-parse($string, $token) {
|
||||
$i: str-index($string, $token);
|
||||
|
||||
@if $i {
|
||||
$first-part: str-slice($string, 1, ($i - 1));
|
||||
$string: str-parse(str-slice($string, ($i + str-length($token))), $token);
|
||||
|
||||
@return join(simple-selectors($first-part), $string);
|
||||
}
|
||||
|
||||
@return simple-selectors($string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// State mixin
|
||||
@mixin state($states...) {
|
||||
|
||||
@each $state in $states {
|
||||
$string: $state;
|
||||
|
||||
@each $token in ">", "+", "~" {
|
||||
$string: str-replace($string, $token, " ");
|
||||
}
|
||||
|
||||
$string: str-replace($string, " ", " ");
|
||||
|
||||
$selectors: str-parse($string, " ");
|
||||
|
||||
@each $sel in $selectors {
|
||||
@if str-index("#{&}", $sel) != null {
|
||||
@at-root #{selector-replace(&, $sel, $state)} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Variant mixin (alias)
|
||||
@mixin variant($args...) {
|
||||
@include state($args...) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Media queries
|
||||
//
|
||||
|
||||
@mixin retina {
|
||||
@media screen and (min-resolution: 1.25dppx) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Asset URLs
|
||||
//
|
||||
|
||||
@function asset-url($type, $path) {
|
||||
@return url(unquote("#{$type}/#{$path}"));
|
||||
}
|
||||
|
||||
@function icon-url($path) {
|
||||
@return asset-url("chrome://zotero/skin", $path);
|
||||
}
|
||||
|
||||
@function image-url($path) {
|
||||
@return asset-url("chrome://zotero/skin", $path);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
@mixin icon($file-name, $size: 16px) {
|
||||
&::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: $size;
|
||||
height: $size;
|
||||
background-image: icon-url("#{$file-name}.png");
|
||||
background-size: 100%;
|
||||
|
||||
@include retina {
|
||||
background-image: icon-url("#{$file-name}@2x.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.toolbarButton::before {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.toolbarButton > span:first-child {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.toolbarButton {
|
||||
height: $toolbar-btn-height;
|
||||
background: $toolbar-btn-bg;
|
||||
padding: $toolbar-btn-padding;
|
||||
border: $toolbar-btn-border;
|
||||
border-radius: $toolbar-btn-border-radius;
|
||||
margin: 0 $toolbar-btn-margin-x;
|
||||
position: relative;
|
||||
box-shadow: $toolbar-btn-box-shadow;
|
||||
|
||||
@include retina {
|
||||
box-shadow: $toolbar-btn-box-shadow-2x;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: $toolbar-btn-focus-box-shadow;
|
||||
z-index: 1;
|
||||
|
||||
@include retina {
|
||||
box-shadow: $toolbar-btn-focus-box-shadow-2x;
|
||||
}
|
||||
}
|
||||
|
||||
&:-moz-focusring {
|
||||
box-shadow: $toolbar-btn-focus-box-shadow;
|
||||
z-index: 1;
|
||||
|
||||
@include retina {
|
||||
box-shadow: $toolbar-btn-focus-box-shadow-2x;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $toolbar-btn-hover-bg;
|
||||
border-color: $toolbar-btn-border-hover-color;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
background: $toolbar-btn-active-bg;
|
||||
border-color: $toolbar-btn-border-active-color;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
pointer-events: none;
|
||||
|
||||
&::before {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
@include state(".toolbarButton:active", ".toolbarButton.active") {
|
||||
top: $toolbar-btn-icon-active-offset;
|
||||
}
|
||||
}
|
||||
|
||||
// Label for screen readers
|
||||
> span:first-child {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.split-button {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Split button
|
||||
//
|
||||
|
||||
@mixin split-button($height, $button, $padding-x, $padding-y) {
|
||||
height: $height;
|
||||
padding: $padding-y $padding-x $padding-y ($padding-x + 1px);
|
||||
background: none;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
position: relative;
|
||||
|
||||
&:focus-visible {
|
||||
z-index: 2; // Chrome
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: inset 0 0 0 1px rgba($accent-color, 0.5), 0 0 0 3px rgba($accent-color, 0.5);
|
||||
|
||||
@include retina {
|
||||
box-shadow: inset 0 0 0 1px rgba($accent-color, 0.5), 0 0 0 2.5px rgba($accent-color, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:-moz-focusring {
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: inset 0 0 0 1px rgba($accent-color, 0.5), 0 0 0 3px rgba($accent-color, 0.5);
|
||||
z-index: 2; // Firefox
|
||||
|
||||
@include retina {
|
||||
box-shadow: inset 0 0 0 1px rgba($accent-color, 0.5), 0 0 0 2.5px rgba($accent-color, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-right: 0;
|
||||
background: none;
|
||||
|
||||
&:focus-visible {
|
||||
&::after {
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&:-moz-focusring {
|
||||
&::after {
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding: $padding-y ($padding-x + 1px);
|
||||
margin-left: 0;
|
||||
background: image-url("mac/#{$button}-end.png") no-repeat right top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-end@2x.png") no-repeat right top / auto $height;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: image-url("mac/#{$button}-end-pressed.png") no-repeat right top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-end-pressed@2x.png") no-repeat right top / auto $height;
|
||||
}
|
||||
}
|
||||
|
||||
@include state(".toolbarButton.toggled") {
|
||||
background: image-url("mac/#{$button}-end-active.png") no-repeat right top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-end-active@2x.png") no-repeat right top / auto $height;
|
||||
}
|
||||
|
||||
@include state(".toolbarButton:active") {
|
||||
background: image-url("mac/#{$button}-end-active-pressed.png") no-repeat right top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-end-active-pressed@2x.png") no-repeat right top / auto $height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
&::after {
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&:-moz-focusring {
|
||||
&::after {
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
> span:first-child {
|
||||
clip: initial;
|
||||
margin: initial;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-indent: -99em;
|
||||
background:
|
||||
linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1)) no-repeat left center / 1px ($height - 2px),
|
||||
image-url("mac/#{$button}-start.png") no-repeat center top;
|
||||
|
||||
@include retina {
|
||||
background:
|
||||
linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1)) no-repeat left center / 1px ($height - 2px),
|
||||
image-url("mac/#{$button}-start@2x.png") no-repeat center top / auto $height;
|
||||
}
|
||||
|
||||
@include state(".toolbarButton:active") {
|
||||
background: image-url("mac/#{$button}-start-pressed.png") no-repeat center top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-start-pressed@2x.png") no-repeat center top / auto $height;
|
||||
}
|
||||
}
|
||||
|
||||
@include state(".toolbarButton.toggled") {
|
||||
background: image-url("mac/#{$button}-start-active.png") no-repeat center top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-start-active@2x.png") no-repeat center top / auto $height;
|
||||
}
|
||||
|
||||
@include state(".toolbarButton:active") {
|
||||
background: image-url("mac/#{$button}-start-active-pressed.png") no-repeat center top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-start-active-pressed@2x.png") no-repeat center top / auto $height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include state(".toolbarButton.toggled + .toolbarButton:not(:active)") {
|
||||
background: image-url("mac/#{$button}-start.png") no-repeat center top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-start@2x.png") no-repeat center top / auto $height;
|
||||
}
|
||||
}
|
||||
|
||||
@include variant(".toolbarButton:first-child") {
|
||||
background: image-url("mac/#{$button}-start.png") no-repeat left top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-start@2x.png") no-repeat left top / auto $height;
|
||||
}
|
||||
|
||||
@include state(".toolbarButton:active") {
|
||||
background: image-url("mac/#{$button}-start-pressed.png") no-repeat left top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-start-pressed@2x.png") no-repeat left top / auto $height;
|
||||
}
|
||||
}
|
||||
|
||||
@include state(".toolbarButton.toggled") {
|
||||
background: image-url("mac/#{$button}-start-active.png") no-repeat left top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-start-active@2x.png") no-repeat left top / auto $height;
|
||||
}
|
||||
|
||||
@include state(".toolbarButton:active") {
|
||||
background: image-url("mac/#{$button}-start-active-pressed.png") no-repeat left top;
|
||||
|
||||
@include retina {
|
||||
background: image-url("mac/#{$button}-start-active-pressed@2x.png") no-repeat left top / auto $height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include variant(".toolbarButton:last-child") {
|
||||
width: calc(100% - 17px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Move this out from mixins
|
||||
#zotero-tb-split {
|
||||
$item-tool-icon: "mac/item";
|
||||
$item-tool-icon-active: "mac/item-white";
|
||||
$notes-tool-icon: "mac/notes";
|
||||
$notes-tool-icon-active: "mac/notes-white";
|
||||
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.item {
|
||||
@include icon($item-tool-icon);
|
||||
|
||||
&.toggled {
|
||||
@include icon($item-tool-icon-active);
|
||||
}
|
||||
}
|
||||
|
||||
.notes {
|
||||
@include icon($notes-tool-icon);
|
||||
|
||||
&.toggled {
|
||||
@include icon($notes-tool-icon-active);
|
||||
}
|
||||
}
|
||||
|
||||
.toolbarButton {
|
||||
box-sizing: border-box;
|
||||
|
||||
@include split-button(
|
||||
$height: 24px,
|
||||
$button: "menubutton",
|
||||
$padding-x: 11px,
|
||||
$padding-y: 4px
|
||||
);
|
||||
}
|
||||
}
|
|
@ -24,9 +24,31 @@
|
|||
}
|
||||
|
||||
.inner {
|
||||
> *:not(:first-child) {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.first-line {
|
||||
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 {
|
||||
flex-grow: 1;
|
||||
width: 0;
|
||||
|
@ -37,10 +59,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.second-line {
|
||||
.third-line {
|
||||
display: flex;
|
||||
|
||||
.date {
|
||||
color: $shade-6;
|
||||
}
|
||||
|
||||
.body {
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 2px 0 0; // Leave space for textbox border on top tag
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
ul.tags-box-list > li {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f4374cdb6386ba5cdd818ff6e3ece74aae83b394
|
||||
Subproject commit a271598218fa8f52cd6d571d5c1b28e913803409
|