fx-compat: Fix and extract notesBox into a separate element
This commit is contained in:
parent
ed572df563
commit
307701788f
8 changed files with 240 additions and 106 deletions
180
chrome/content/zotero/elements/notesBox.js
Normal file
180
chrome/content/zotero/elements/notesBox.js
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2021 Corporation for Digital Scholarship
|
||||
Vienna, Virginia, USA
|
||||
https://www.zotero.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 *****
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
{
|
||||
class NotesBox extends XULElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._mode = 'view';
|
||||
this._item = null;
|
||||
this._destroyed = false;
|
||||
this._noteIDs = [];
|
||||
|
||||
this.content = MozXULElement.parseXULToFragment(`
|
||||
<box flex="1" style="display: flex" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<div style="flex-grow: 1" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<div class="header">
|
||||
<label id="num"/>
|
||||
<button id="add">&zotero.item.add;</button>
|
||||
</div>
|
||||
<div id="grid" class="grid"/>
|
||||
</div>
|
||||
</box>
|
||||
`, ['chrome://zotero/locale/zotero.dtd']);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this._destroyed = false;
|
||||
window.addEventListener("unload", this.destroy);
|
||||
|
||||
let shadow = this.attachShadow({ mode: "open" });
|
||||
|
||||
let s1 = document.createElement("link");
|
||||
s1.rel = "stylesheet";
|
||||
s1.href = "chrome://zotero-platform/content/notesBox.css";
|
||||
shadow.append(s1);
|
||||
|
||||
let content = document.importNode(this.content, true);
|
||||
shadow.append(content);
|
||||
|
||||
this._id('add').addEventListener('click', this._handleAdd);
|
||||
|
||||
this._notifierID = Zotero.Notifier.registerObserver(this, ['item'], 'notesBox');
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._destroyed) {
|
||||
return;
|
||||
}
|
||||
window.removeEventListener("unload", this.destroy);
|
||||
this._destroyed = true;
|
||||
|
||||
Zotero.Notifier.unregisterObserver(this._notifierID);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.replaceChildren();
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
get mode() {
|
||||
return this._mode;
|
||||
}
|
||||
|
||||
set mode(val) {
|
||||
switch (val) {
|
||||
case 'view':
|
||||
case 'merge':
|
||||
case 'mergeedit':
|
||||
case 'edit':
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Invalid mode '${val}'`);
|
||||
}
|
||||
|
||||
this._mode = val;
|
||||
}
|
||||
|
||||
get item() {
|
||||
return this._item;
|
||||
}
|
||||
|
||||
set item(val) {
|
||||
this._item = val;
|
||||
this._refresh();
|
||||
}
|
||||
|
||||
notify(event, type, ids, extraData) {
|
||||
if (['modify', 'delete'].includes(event) && ids.some(id => this._noteIDs.includes(id))) {
|
||||
this._refresh();
|
||||
}
|
||||
}
|
||||
|
||||
_refresh() {
|
||||
if (!this._item) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._noteIDs = this._item.getNotes();
|
||||
this._id('add').hidden = this._mode != 'edit';
|
||||
|
||||
let grid = this._id('grid');
|
||||
grid.replaceChildren();
|
||||
|
||||
let notes = Zotero.Items.get(this._item.getNotes());
|
||||
for (let item of notes) {
|
||||
let id = item.id;
|
||||
let icon = document.createElement("img");
|
||||
icon.src = item.getImageSrc();
|
||||
|
||||
let label = document.createElement("label");
|
||||
label.append(item.getDisplayTitle());
|
||||
|
||||
let box = document.createElement('div');
|
||||
box.addEventListener('click', () => this._handleShowItem(id));
|
||||
box.className = 'box zotero-clicky';
|
||||
box.appendChild(icon);
|
||||
box.appendChild(label);
|
||||
|
||||
grid.append(box);
|
||||
|
||||
if (this._mode == 'edit') {
|
||||
let remove = document.createElement("label");
|
||||
remove.addEventListener('click', () => this._handleRemove(id));
|
||||
remove.className = 'zotero-clicky zotero-clicky-minus';
|
||||
remove.append('-');
|
||||
grid.append(remove);
|
||||
}
|
||||
}
|
||||
|
||||
let num = this._noteIDs.length;
|
||||
this._id('num').replaceChildren(Zotero.getString('pane.item.notes.count', num, num));
|
||||
}
|
||||
|
||||
_handleAdd = (event) => {
|
||||
ZoteroPane_Local.newNote(event.shiftKey, this._item.key);
|
||||
};
|
||||
|
||||
_handleRemove(id) {
|
||||
var ps = Services.prompt;
|
||||
if (ps.confirm(null, '', Zotero.getString('pane.item.notes.delete.confirm'))) {
|
||||
Zotero.Items.trashTx(id);
|
||||
}
|
||||
}
|
||||
|
||||
_handleShowItem(id) {
|
||||
ZoteroPane_Local.selectItem(id);
|
||||
}
|
||||
|
||||
_id(id) {
|
||||
return this.shadowRoot.querySelector(`[id=${id}]`);
|
||||
}
|
||||
}
|
||||
customElements.define("notes-box", NotesBox);
|
||||
}
|
|
@ -28,10 +28,9 @@ import ReactDOM from 'react-dom';
|
|||
import TagsBoxContainer from 'containers/tagsBoxContainer';
|
||||
|
||||
var ZoteroItemPane = new function() {
|
||||
var _lastItem, _itemBox, _notesLabel, _notesButton, _notesList, _tagsBox, _relatedBox;
|
||||
var _lastItem, _itemBox, _tagsBox, _notesBox, _relatedBox;
|
||||
var _selectedNoteID;
|
||||
var _translationTarget;
|
||||
var _noteIDs;
|
||||
|
||||
this.onLoad = function () {
|
||||
if (!Zotero) {
|
||||
|
@ -45,13 +44,11 @@ var ZoteroItemPane = new function() {
|
|||
return;
|
||||
}
|
||||
|
||||
_notesLabel = document.getElementById('zotero-editpane-notes-label');
|
||||
_notesButton = document.getElementById('zotero-editpane-notes-add');
|
||||
_notesList = document.getElementById('zotero-editpane-dynamic-notes');
|
||||
// Fake a ref
|
||||
_tagsBox = {
|
||||
current: null
|
||||
};
|
||||
_notesBox = document.getElementById('zotero-editpane-notes');
|
||||
_relatedBox = document.getElementById('zotero-editpane-related');
|
||||
|
||||
this._unregisterID = Zotero.Notifier.registerObserver(this, ['item'], 'itemPane');
|
||||
|
@ -84,6 +81,11 @@ var ZoteroItemPane = new function() {
|
|||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
var box = _notesBox;
|
||||
box.parentItem = item;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
var box = _relatedBox;
|
||||
break;
|
||||
|
@ -134,60 +136,6 @@ var ZoteroItemPane = new function() {
|
|||
this.setTranslateButton();
|
||||
}
|
||||
}
|
||||
else if (index == 1) {
|
||||
var editable = ZoteroPane_Local.canEdit();
|
||||
_notesButton.hidden = !editable;
|
||||
|
||||
while(_notesList.hasChildNodes()) {
|
||||
_notesList.removeChild(_notesList.firstChild);
|
||||
}
|
||||
|
||||
_noteIDs = new Set();
|
||||
let notes = yield Zotero.Items.getAsync(item.getNotes());
|
||||
if (notes.length) {
|
||||
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', function () { ZoteroPane_Local.selectItem(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 () { ZoteroItemPane.removeNote(id); });
|
||||
}
|
||||
|
||||
var row = document.createElement('row');
|
||||
row.appendChild(box);
|
||||
if (editable) {
|
||||
row.appendChild(removeButton);
|
||||
}
|
||||
|
||||
_notesList.appendChild(row);
|
||||
_noteIDs.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
_updateNoteCount();
|
||||
return;
|
||||
}
|
||||
else if (index == 2) {
|
||||
ReactDOM.render(
|
||||
<TagsBoxContainer
|
||||
|
@ -221,16 +169,6 @@ var ZoteroItemPane = new function() {
|
|||
|
||||
this.notify = Zotero.Promise.coroutine(function* (action, type, ids, extraData) {
|
||||
var viewBox = document.getElementById('zotero-view-item');
|
||||
// If notes pane is selected, refresh it if any of the notes change or are deleted
|
||||
if (viewBox.selectedIndex == 1 && (action == 'modify' || action == 'delete')) {
|
||||
let refresh = false;
|
||||
if (ids.some(id => _noteIDs.has(id))) {
|
||||
refresh = true;
|
||||
}
|
||||
if (refresh) {
|
||||
yield this.viewItem(_lastItem, null, 1);
|
||||
}
|
||||
}
|
||||
if (viewBox.selectedIndex == 0 && action == 'refresh' && _lastItem) {
|
||||
yield this.viewItem(_lastItem, null, 0);
|
||||
}
|
||||
|
@ -290,20 +228,6 @@ var ZoteroItemPane = new function() {
|
|||
};
|
||||
|
||||
|
||||
this.addNote = function (popup) {
|
||||
ZoteroPane_Local.newNote(popup, _lastItem.key);
|
||||
}
|
||||
|
||||
|
||||
this.removeNote = function (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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.onTagsContextPopupShowing = function () {
|
||||
if (!_lastItem.isEditable()) {
|
||||
return false;
|
||||
|
@ -414,12 +338,6 @@ var ZoteroItemPane = new function() {
|
|||
var tooltip = label + (Zotero.rtl ? ' \u202B' : ' ') + '(' + key + ')'
|
||||
elem.setAttribute('tooltiptext', tooltip);
|
||||
};
|
||||
|
||||
|
||||
function _updateNoteCount() {
|
||||
var c = _notesList.childNodes.length;
|
||||
_notesLabel.value = Zotero.getString('pane.item.notes.count', c, c);
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener("load", function(e) { ZoteroItemPane.onLoad(e); }, false);
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/menulistItemTypes.js", this);
|
||||
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/itemBox.js", this);
|
||||
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/noteEditor.js", this);
|
||||
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/notesBox.js", this);
|
||||
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/relatedBox.js", this);
|
||||
|
||||
Services.scriptloader.loadSubScript("chrome://zotero/content/tabs.js", this);
|
||||
|
@ -1117,20 +1118,8 @@
|
|||
<tabpanels id="zotero-view-item" class="zotero-view-item" flex="1">
|
||||
<tabpanel id="item-box-container"/>
|
||||
|
||||
<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>
|
||||
<notes-box id="zotero-editpane-notes" class="zotero-editpane-notes" flex="1"/>
|
||||
</tabpanel>
|
||||
|
||||
<tabpanel id="tags-pane" class="tags-pane" orient="vertical" context="tags-context-menu">
|
||||
|
|
2
scss/_notesBox.scss
Normal file
2
scss/_notesBox.scss
Normal file
|
@ -0,0 +1,2 @@
|
|||
@import "components/notesBox";
|
||||
@import "components/clicky";
|
42
scss/components/_notesBox.scss
Normal file
42
scss/components/_notesBox.scss
Normal file
|
@ -0,0 +1,42 @@
|
|||
.header {
|
||||
display: flex;
|
||||
padding-left: 10px;
|
||||
align-items: center;
|
||||
|
||||
label {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
button {
|
||||
min-width: 79px;
|
||||
margin: 5px 6px 3px;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
color: ButtonText;
|
||||
text-shadow: none;
|
||||
font-size: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
|
||||
.box {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
margin-left: 5px;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-left: 3px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
1
scss/notesBox-mac.scss
Normal file
1
scss/notesBox-mac.scss
Normal file
|
@ -0,0 +1 @@
|
|||
@import "notesBox";
|
1
scss/notesBox-unix.scss
Normal file
1
scss/notesBox-unix.scss
Normal file
|
@ -0,0 +1 @@
|
|||
@import "notesBox";
|
1
scss/notesBox-win.scss
Normal file
1
scss/notesBox-win.scss
Normal file
|
@ -0,0 +1 @@
|
|||
@import "notesBox";
|
Loading…
Reference in a new issue