fx-compat: Fix and extract notesBox into a separate element

This commit is contained in:
Martynas Bagdonas 2022-05-27 13:19:52 +03:00
parent ed572df563
commit 307701788f
8 changed files with 240 additions and 106 deletions

View 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);
}

View file

@ -28,10 +28,9 @@ 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) {
@ -45,13 +44,11 @@ var ZoteroItemPane = new function() {
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);

View file

@ -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
View file

@ -0,0 +1,2 @@
@import "components/notesBox";
@import "components/clicky";

View 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
View file

@ -0,0 +1 @@
@import "notesBox";

1
scss/notesBox-unix.scss Normal file
View file

@ -0,0 +1 @@
@import "notesBox";

1
scss/notesBox-win.scss Normal file
View file

@ -0,0 +1 @@
@import "notesBox";