Rework context pane in PDF reader
- Remove item pane tabs - Show all notes in notes pane, showing the parent title where appropriate - Show drop-down menu for "New Note" button in notes pane that allows creating standalone or child notes - Add some temporary styling for notes in the notes pane TODO: - Show child notes at top of notes list, with separate headers for "Item Notes" and "All Notes" - Fix "New Child Note" option - Add parent item title above note editor when editing child note - Search on parent item title for child notes
This commit is contained in:
parent
73ba5f9ffe
commit
dba841770c
5 changed files with 102 additions and 175 deletions
|
@ -24,15 +24,23 @@
|
|||
*/
|
||||
|
||||
import React, { forwardRef, useImperativeHandle, useState } from 'react';
|
||||
import cx from 'classnames';
|
||||
|
||||
const NoteRow = ({ title, body, date, onClick }) => {
|
||||
const NoteRow = ({ title, body, date, onClick, parentItemType, parentTitle }) => {
|
||||
return (
|
||||
<div className="note-row" onClick={onClick}>
|
||||
<div className={cx('note-row', { 'standalone-note-row': !parentItemType })} onClick={onClick}>
|
||||
<div className="inner">
|
||||
<div className="first-line">
|
||||
{ parentItemType
|
||||
? <div className="parent-line">
|
||||
<img className="parent-item-type" src={Zotero.ItemTypes.getImageSrc(parentItemType)} />
|
||||
<span className="parent-title">{parentTitle}</span>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
<div className="title-line">
|
||||
<div className="title">{title}</div>
|
||||
</div>
|
||||
<div className="second-line">
|
||||
<div className="body-line">
|
||||
<div className="date">{date}</div>
|
||||
<div className="body">{body}</div>
|
||||
</div>
|
||||
|
|
|
@ -395,19 +395,41 @@ var ZoteroContextPane = new function () {
|
|||
var label = document.createElement('label');
|
||||
var button = document.createElement('button');
|
||||
button.setAttribute('label', Zotero.Intl.strings['zotero.toolbar.newNote']);
|
||||
button.addEventListener('click', () => {
|
||||
|
||||
// Create standalone or child note on menuitem click
|
||||
document.getElementById('context-pane-new-note-button-popup').onclick = function (event) {
|
||||
var parentID = null;
|
||||
switch (event.originalTarget.id) {
|
||||
case 'context-pane-new-standalone-note':
|
||||
break;
|
||||
|
||||
case 'context-pane-new-item-note':
|
||||
// TODO: Get the parent item
|
||||
parentID = parentItem.id;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
contextNode.setAttribute('selectedIndex', 1);
|
||||
var item = new Zotero.Item('note');
|
||||
item.libraryID = libraryID;
|
||||
// item.parentKey = parentItem.key;
|
||||
if (parentID) {
|
||||
item.parentID = parentID;
|
||||
}
|
||||
editor.mode = 'edit';
|
||||
editor.item = item;
|
||||
editor.parentItem = null;
|
||||
editor.focus();
|
||||
_updateAddToNote();
|
||||
};
|
||||
|
||||
button.addEventListener('mousedown', (event) => {
|
||||
var popup = document.getElementById('context-pane-new-note-button-popup');
|
||||
popup.openPopup(event.target, 'after_end');
|
||||
});
|
||||
|
||||
|
||||
var vbox1 = document.createElement('vbox');
|
||||
vbox1.append(label, button);
|
||||
|
||||
|
@ -445,7 +467,6 @@ var ZoteroContextPane = new function () {
|
|||
var s = new Zotero.Search();
|
||||
s.addCondition('libraryID', 'is', libraryID);
|
||||
s.addCondition('itemType', 'is', 'note');
|
||||
s.addCondition('noChildren', 'true');
|
||||
if (query) {
|
||||
let parts = Zotero.SearchConditions.parseSearchString(query);
|
||||
for (let part of parts) {
|
||||
|
@ -461,6 +482,7 @@ var ZoteroContextPane = new function () {
|
|||
});
|
||||
|
||||
notesListRef.current.setNotes(notes.map(note => {
|
||||
var parentItem = note.parentItem;
|
||||
var text = note.note;
|
||||
text = Zotero.Utilities.unescapeHTML(text);
|
||||
text = text.trim();
|
||||
|
@ -471,7 +493,9 @@ var ZoteroContextPane = new function () {
|
|||
id: note.id,
|
||||
title: title || Zotero.getString('pane.item.notes.untitled'),
|
||||
body: parts[1] || '',
|
||||
date: (new Date(note.dateModified).toLocaleDateString(Zotero.locale))
|
||||
date: (new Date(note.dateModified).toLocaleDateString(Zotero.locale)),
|
||||
parentItemType: parentItem && parentItem.itemType,
|
||||
parentTitle: parentItem && parentItem.getDisplayTitle()
|
||||
};
|
||||
}));
|
||||
|
||||
|
@ -636,170 +660,17 @@ var ZoteroContextPane = new function () {
|
|||
}
|
||||
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');
|
||||
// Info pane
|
||||
var panelInfo = document.createElement('vbox');
|
||||
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');
|
||||
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;
|
||||
|
||||
container.append(panelInfo);
|
||||
|
||||
itemBox.mode = editable ? 'edit' : 'view';
|
||||
itemBox.item = parentItem;
|
||||
|
||||
relatedBox.mode = editable ? 'edit' : 'view';
|
||||
relatedBox.item = parentItem;
|
||||
|
||||
function _renderNotesPanel() {
|
||||
rows.innerHTML = '';
|
||||
var parentItem = Zotero.Items.get(parentID);
|
||||
if (!parentItem) {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
label.value = Zotero.getString('pane.item.notes.count', c, c);
|
||||
}
|
||||
|
||||
context.update = Zotero.Utilities.throttle(_renderNotesPanel, 500);
|
||||
_renderNotesPanel();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -624,6 +624,13 @@
|
|||
<hbox id="zotero-context-pane-inner" flex="1" zotero-persist="height"/>
|
||||
</vbox>
|
||||
</box>
|
||||
|
||||
<popupset>
|
||||
<menupopup id="context-pane-new-note-button-popup">
|
||||
<menuitem id="context-pane-new-standalone-note" label="&zotero.toolbar.note.standalone;"/>
|
||||
<menuitem id="context-pane-new-item-note" label="&zotero.toolbar.note.child;"/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
</hbox>
|
||||
|
||||
<!-- Barrier to prevent tabbing into Zotero pane when busy -->
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
margin-bottom: .25em !important;
|
||||
}
|
||||
|
||||
.zotero-item-pane-content {
|
||||
background: -moz-Field; /* Same as background colour for treeview */
|
||||
}
|
||||
|
||||
.zotero-view-item
|
||||
{
|
||||
padding: 0;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
width: 100%;
|
||||
overflow-y: auto;
|
||||
flex-grow: 1;
|
||||
background: #d2d8e2;
|
||||
border-top: 1px solid lightgray;
|
||||
}
|
||||
|
||||
.notes-list {
|
||||
|
@ -10,17 +12,23 @@
|
|||
flex-direction: column;
|
||||
height: 0;
|
||||
flex-grow: 1;
|
||||
padding-top: 2px;
|
||||
|
||||
&> section > h2 {
|
||||
font-weight: bold;
|
||||
padding: 7px 8px 3px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.note-row {
|
||||
padding: 8px 12px;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid $shade-3;
|
||||
}
|
||||
border: 1px solid #bcc4d2;
|
||||
border-radius: 5px;
|
||||
margin: 4px 7px;
|
||||
background-color: #fff;
|
||||
|
||||
&:active {
|
||||
background: #e2e2e2;
|
||||
background: #e4ebf9;
|
||||
}
|
||||
|
||||
.inner {
|
||||
|
@ -28,9 +36,31 @@
|
|||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.first-line {
|
||||
.parent-line {
|
||||
display: flex;
|
||||
|
||||
width: calc(100% - 16px);
|
||||
border-bottom: 1px solid #d7dad7;
|
||||
align-items: center;
|
||||
padding: 5px 8px 4px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.parent-item-type {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.parent-title {
|
||||
flex-grow: 1;
|
||||
width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.title-line {
|
||||
display: flex;
|
||||
padding: 0 8px 0;
|
||||
|
||||
.title {
|
||||
flex-grow: 1;
|
||||
width: 0;
|
||||
|
@ -40,9 +70,10 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.second-line {
|
||||
|
||||
.body-line {
|
||||
display: flex;
|
||||
padding: 0 8px 6px;
|
||||
|
||||
.date {
|
||||
color: $shade-6;
|
||||
|
@ -60,3 +91,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.standalone-note-row {
|
||||
.title-line {
|
||||
padding-top: 6px !important;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue