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,11 +28,10 @@ import ReactDOM from 'react-dom';
|
||||||
import TagsBoxContainer from 'containers/tagsBoxContainer';
|
import TagsBoxContainer from 'containers/tagsBoxContainer';
|
||||||
|
|
||||||
var ZoteroItemPane = new function() {
|
var ZoteroItemPane = new function() {
|
||||||
var _lastItem, _itemBox, _notesLabel, _notesButton, _notesList, _tagsBox, _relatedBox;
|
var _lastItem, _itemBox, _tagsBox, _notesBox, _relatedBox;
|
||||||
var _selectedNoteID;
|
var _selectedNoteID;
|
||||||
var _translationTarget;
|
var _translationTarget;
|
||||||
var _noteIDs;
|
|
||||||
|
|
||||||
this.onLoad = function () {
|
this.onLoad = function () {
|
||||||
if (!Zotero) {
|
if (!Zotero) {
|
||||||
return;
|
return;
|
||||||
|
@ -44,16 +43,14 @@ var ZoteroItemPane = new function() {
|
||||||
if (!document.getElementById('zotero-view-tabbox')) {
|
if (!document.getElementById('zotero-view-tabbox')) {
|
||||||
return;
|
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
|
// Fake a ref
|
||||||
_tagsBox = {
|
_tagsBox = {
|
||||||
current: null
|
current: null
|
||||||
};
|
};
|
||||||
|
_notesBox = document.getElementById('zotero-editpane-notes');
|
||||||
_relatedBox = document.getElementById('zotero-editpane-related');
|
_relatedBox = document.getElementById('zotero-editpane-related');
|
||||||
|
|
||||||
this._unregisterID = Zotero.Notifier.registerObserver(this, ['item'], 'itemPane');
|
this._unregisterID = Zotero.Notifier.registerObserver(this, ['item'], 'itemPane');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +81,11 @@ var ZoteroItemPane = new function() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
var box = _notesBox;
|
||||||
|
box.parentItem = item;
|
||||||
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
var box = _relatedBox;
|
var box = _relatedBox;
|
||||||
break;
|
break;
|
||||||
|
@ -134,60 +136,6 @@ var ZoteroItemPane = new function() {
|
||||||
this.setTranslateButton();
|
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) {
|
else if (index == 2) {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<TagsBoxContainer
|
<TagsBoxContainer
|
||||||
|
@ -221,16 +169,6 @@ var ZoteroItemPane = new function() {
|
||||||
|
|
||||||
this.notify = Zotero.Promise.coroutine(function* (action, type, ids, extraData) {
|
this.notify = Zotero.Promise.coroutine(function* (action, type, ids, extraData) {
|
||||||
var viewBox = document.getElementById('zotero-view-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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (viewBox.selectedIndex == 0 && action == 'refresh' && _lastItem) {
|
if (viewBox.selectedIndex == 0 && action == 'refresh' && _lastItem) {
|
||||||
yield this.viewItem(_lastItem, null, 0);
|
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 () {
|
this.onTagsContextPopupShowing = function () {
|
||||||
if (!_lastItem.isEditable()) {
|
if (!_lastItem.isEditable()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -414,12 +338,6 @@ var ZoteroItemPane = new function() {
|
||||||
var tooltip = label + (Zotero.rtl ? ' \u202B' : ' ') + '(' + key + ')'
|
var tooltip = label + (Zotero.rtl ? ' \u202B' : ' ') + '(' + key + ')'
|
||||||
elem.setAttribute('tooltiptext', tooltip);
|
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);
|
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/menulistItemTypes.js", this);
|
||||||
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/itemBox.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/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/elements/relatedBox.js", this);
|
||||||
|
|
||||||
Services.scriptloader.loadSubScript("chrome://zotero/content/tabs.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">
|
<tabpanels id="zotero-view-item" class="zotero-view-item" flex="1">
|
||||||
<tabpanel id="item-box-container"/>
|
<tabpanel id="item-box-container"/>
|
||||||
|
|
||||||
<tabpanel flex="1" orient="vertical">
|
<tabpanel>
|
||||||
<vbox flex="1" id="zotero-editpane-notes" class="zotero-box">
|
<notes-box id="zotero-editpane-notes" class="zotero-editpane-notes" flex="1"/>
|
||||||
<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>
|
||||||
|
|
||||||
<tabpanel id="tags-pane" class="tags-pane" orient="vertical" context="tags-context-menu">
|
<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