From b00325942abceed0af443c4f747a130c5e511813 Mon Sep 17 00:00:00 2001 From: Martynas Bagdonas Date: Mon, 22 Feb 2021 20:02:05 +0200 Subject: [PATCH] Improve reworked context pane: - 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 - Cleanup TODO: - Search on parent item title for child notes --- .../zotero/components/itemPane/notesList.jsx | 11 +- chrome/content/zotero/contextPane.js | 189 +++++++++--------- chrome/content/zotero/xpcom/reader.js | 8 +- chrome/locale/en-US/zotero/zotero.properties | 2 + chrome/skin/default/zotero/contextPane.css | 19 ++ scss/components/_notesList.scss | 2 +- 6 files changed, 131 insertions(+), 100 deletions(-) diff --git a/chrome/content/zotero/components/itemPane/notesList.jsx b/chrome/content/zotero/components/itemPane/notesList.jsx index 1c2234e067..a16d330cda 100644 --- a/chrome/content/zotero/components/itemPane/notesList.jsx +++ b/chrome/content/zotero/components/itemPane/notesList.jsx @@ -52,9 +52,18 @@ const NoteRow = ({ title, body, date, onClick, parentItemType, parentTitle }) => const NotesList = forwardRef(({ onClick }, ref) => { const [notes, setNotes] = useState([]); useImperativeHandle(ref, () => ({ setNotes })); + let currentChildNotes = notes.filter(x => x.isCurrentChild); + let allNotes = notes.filter(x => !x.isCurrentChild); return (
- {notes.map(note => onClick(note.id)}/>)} +
+ {!!currentChildNotes.length &&

{Zotero.getString('pane.context.itemNotes')}

} + {currentChildNotes.map(note => onClick(note.id)}/>)} +
+
+ {!!allNotes &&

{Zotero.getString('pane.context.allNotes')}

} + {allNotes.map(note => onClick(note.id)}/>)} +
); }); diff --git a/chrome/content/zotero/contextPane.js b/chrome/content/zotero/contextPane.js index 2194e6b346..c1fadb2580 100644 --- a/chrome/content/zotero/contextPane.js +++ b/chrome/content/zotero/contextPane.js @@ -168,6 +168,11 @@ var ZoteroContextPane = new function () { await reader._initPromise; _tabCover.hidden = true; })(); + + var attachment = Zotero.Items.get(reader.itemID); + _selectNotesContext(attachment.libraryID); + var notesContext = _getNotesContext(attachment.libraryID); + notesContext.updateFromCache(); } _contextPaneSplitter.setAttribute('hidden', false); @@ -177,10 +182,6 @@ var ZoteroContextPane = new function () { _splitButton.classList.remove('hidden'); } - var context = _itemContexts.find(x => x.tabID == ids[0]); - if (context) { - _selectNotesContext(context.libraryID); - } _selectItemContext(ids[0]); _update(); } @@ -365,6 +366,16 @@ var ZoteroContextPane = new function () { _panesDeck.append(_itemPaneDeck, _notesPaneDeck); } + + function _getCurrentParentItem() { + var reader = Zotero.Reader.getByTabID(Zotero_Tabs.selectedID); + if (reader) { + var attachment = Zotero.Items.get(reader.itemID); + if (attachment) { + return attachment.parentItem; + } + } + } function _addNotesContext(libraryID) { var list = document.createElement('vbox'); @@ -372,10 +383,12 @@ var ZoteroContextPane = new function () { list.className = 'zotero-context-notes-list'; var noteContainer = document.createElement('vbox'); + var title = document.createElement('vbox'); + title.className = 'zotero-context-pane-editor-parent-line'; var editor = document.createElement('zoteronoteeditor'); editor.className = 'zotero-context-pane-pinned-note'; editor.setAttribute('flex', 1); - noteContainer.appendChild(editor); + noteContainer.append(title, editor); let contextNode = document.createElement('deck'); contextNode.append(list, noteContainer); @@ -404,7 +417,10 @@ var ZoteroContextPane = new function () { break; case 'context-pane-new-item-note': - // TODO: Get the parent item + var parentItem = _getCurrentParentItem(); + if (!parentItem) { + return; + } parentID = parentItem.id; break; @@ -456,53 +472,71 @@ var ZoteroContextPane = new function () { var notesListRef = React.createRef(); - async function _updateNotesList(reset) { - if (reset) { - input.value = ''; - contextNode.setAttribute('selectedIndex', 0); + async function _updateNotesList(useCached) { + var notes; + if (useCached && context.cachedNotes.length) { + notes = context.cachedNotes; } - var query = input.value; - - await Zotero.Schema.schemaUpdatePromise; - var s = new Zotero.Search(); - s.addCondition('libraryID', 'is', libraryID); - s.addCondition('itemType', 'is', 'note'); - if (query) { - let parts = Zotero.SearchConditions.parseSearchString(query); - for (let part of parts) { - s.addCondition('note', 'contains', part.text); + else { + var query = input.value; + await Zotero.Schema.schemaUpdatePromise; + var s = new Zotero.Search(); + s.addCondition('libraryID', 'is', libraryID); + s.addCondition('itemType', 'is', 'note'); + if (query) { + let parts = Zotero.SearchConditions.parseSearchString(query); + for (let part of parts) { + s.addCondition('note', 'contains', part.text); + } } + 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); + }); + + notes = notes.map(note => { + var parentItem = note.parentItem; + var text = note.note; + text = Zotero.Utilities.unescapeHTML(text); + text = text.trim(); + text = text.slice(0, 500); + var parts = text.split('\n').map(x => x.trim()).filter(x => x.length); + var title = parts[0] && parts[0].slice(0, Zotero.Notes.MAX_TITLE_LENGTH); + return { + id: note.id, + title: title || Zotero.getString('pane.item.notes.untitled'), + body: parts[1] || '', + date: (new Date(note.dateModified).toLocaleDateString(Zotero.locale)), + parentID: note.parentID, + parentItemType: parentItem && parentItem.itemType, + parentTitle: parentItem && parentItem.getDisplayTitle() + }; + }); + context.cachedNotes = notes; } - 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 parentItem = note.parentItem; - var text = note.note; - text = Zotero.Utilities.unescapeHTML(text); - text = text.trim(); - text = text.slice(0, 500); - var parts = text.split('\n').map(x => x.trim()).filter(x => x.length); - var title = parts[0] && parts[0].slice(0, Zotero.Notes.MAX_TITLE_LENGTH); - return { - id: note.id, - title: title || Zotero.getString('pane.item.notes.untitled'), - body: parts[1] || '', - date: (new Date(note.dateModified).toLocaleDateString(Zotero.locale)), - parentItemType: parentItem && parentItem.itemType, - parentTitle: parentItem && parentItem.getDisplayTitle() - }; - })); + var readerParentItem = _getCurrentParentItem(); + notesListRef.current.setNotes(notes.map(note => ({ + ...note, + isCurrentChild: readerParentItem && note.parentID == readerParentItem.id + }))); var c = notes.length; label.value = Zotero.getString('pane.item.notes.count', c, c); } + var context = { + libraryID, + node: contextNode, + editor, + cachedNotes: [], + update: Zotero.Utilities.throttle(_updateNotesList, 1000, { leading: false }), + updateFromCache: () => _updateNotesList(true) + }; + ReactDOM.render( { - onClick(id); - }); - box.appendChild(icon); - box.appendChild(label); - var row = document.createElement('row'); - row.appendChild(box); - if (editable) { - var removeButton = document.createElement('label'); - removeButton.setAttribute('value', '-'); - removeButton.setAttribute('class', 'zotero-clicky zotero-clicky-minus'); - removeButton.addEventListener('click', function () { - onDelete(id); - }); - row.appendChild(removeButton); + node.querySelector('.zotero-context-pane-editor-parent-line').innerHTML = ''; + var parentItem = item.parentItem; + if (parentItem) { + var container = document.createElementNS(HTML_NS, 'div'); + var img = document.createElementNS(HTML_NS, 'img'); + img.src = Zotero.ItemTypes.getImageSrc(parentItem.itemType); + img.className = 'parent-item-type'; + var title = document.createElementNS(HTML_NS, 'div'); + title.append(parentItem.getDisplayTitle()); + title.className = 'parent-title'; + container.append(img, title); + node.querySelector('.zotero-context-pane-editor-parent-line').append(container); } - - list.appendChild(row); + _updateAddToNote(); } } diff --git a/chrome/content/zotero/xpcom/reader.js b/chrome/content/zotero/xpcom/reader.js index 6f7eb51f17..7bb1801322 100644 --- a/chrome/content/zotero/xpcom/reader.js +++ b/chrome/content/zotero/xpcom/reader.js @@ -41,9 +41,6 @@ class ReaderInstance { } async open({ itemID, state, location }) { - if (itemID === this._itemID) { - return false; - } let item = await Zotero.Items.getAsync(itemID); if (!item) { return false; @@ -72,6 +69,10 @@ class ReaderInstance { return true; } + get itemID() { + return this._itemID; + } + updateTitle() { let item = Zotero.Items.get(this._itemID); let title = item.getField('title'); @@ -464,6 +465,7 @@ class ReaderInstance { class ReaderTab extends ReaderInstance { constructor({ itemID, sidebarWidth, sidebarOpen, bottomPlaceholderHeight }) { super(); + this._itemID = itemID; this._sidebarWidth = sidebarWidth; this._sidebarOpen = sidebarOpen; this._bottomPlaceholderHeight = bottomPlaceholderHeight; diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index d9104c5b9f..358c28ef02 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -400,6 +400,8 @@ pane.item.related.count.plural = %S related: pane.item.parentItem = Parent Item: pane.context.noParent = No parent item +pane.context.itemNotes = Item Notes +pane.context.allNotes = All Notes noteEditor.editNote = Edit Note diff --git a/chrome/skin/default/zotero/contextPane.css b/chrome/skin/default/zotero/contextPane.css index 4a60bd926a..16ad9e2d3e 100644 --- a/chrome/skin/default/zotero/contextPane.css +++ b/chrome/skin/default/zotero/contextPane.css @@ -69,3 +69,22 @@ .zotero-context-notes-list { padding-top: 5px; } + +.zotero-context-pane-editor-parent-line > div { + display: flex; + align-items: center; + padding: 5px 5px; +} + +.zotero-context-pane-editor-parent-line .parent-item-type { + margin-right: 3px; + width: 16px; +} + +.zotero-context-pane-editor-parent-line .parent-title { + flex-grow: 1; + width: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/scss/components/_notesList.scss b/scss/components/_notesList.scss index 13ea798da9..02cbb883a2 100644 --- a/scss/components/_notesList.scss +++ b/scss/components/_notesList.scss @@ -16,7 +16,7 @@ &> section > h2 { font-weight: bold; - padding: 7px 8px 3px; + margin: 7px 8px 3px; font-size: 13px; } }