fx-compat: Restore word processor integration (#2841)

- Word for Windows not tested since there's no build yet
- Word for Mac currently causes a sigsev, and likely we'll see this on
windows too. This is happening on an API call where we pass a callback,
so likely an issue in ctypes that we'll have to work around.
- All integration UIs restored.
- Added a component for richlistitems with a checkbox with corresponding
interactions (spacebar/double-click to toggle).
This commit is contained in:
Adomas Ven 2022-10-06 07:17:28 +03:00 committed by GitHub
parent 03de28a7b7
commit aa1aac6adb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 1279 additions and 390 deletions

View file

@ -78,3 +78,8 @@ contract @mozilla.org/network/protocol;1?name=zotero {9BC3D762-9038-486A-9D70-C
content scaffold chrome/content/scaffold/ content scaffold chrome/content/scaffold/
locale scaffold en-US chrome/locale/en-US/scaffold/ locale scaffold en-US chrome/locale/en-US/scaffold/
skin scaffold default chrome/skin/default/scaffold/ skin scaffold default chrome/skin/default/scaffold/
# Word Plugins
manifest integration/libreoffice/chrome.manifest
manifest integration/word-for-windows/chrome.manifest
manifest integration/word-for-mac/chrome.manifest

View file

@ -51,6 +51,7 @@ var Zotero_File_Interface_Bibliography = new function() {
*/ */
this.init = Zotero.Promise.coroutine(function* (args = {}) { this.init = Zotero.Promise.coroutine(function* (args = {}) {
window.addEventListener('dialogaccept', () => this.acceptSelection()); window.addEventListener('dialogaccept', () => this.acceptSelection());
window.addEventListener('dialoghelp', () => this.openHelpLink());
// Set font size from pref // Set font size from pref
// Affects bibliography.xhtml and integrationDocPrefs.xul // Affects bibliography.xhtml and integrationDocPrefs.xul
@ -267,7 +268,7 @@ var Zotero_File_Interface_Bibliography = new function() {
this.exportDocument = function () { this.exportDocument = function () {
if (Zotero.Integration.confirmExportDocument()) { if (Zotero.Integration.confirmExportDocument()) {
_io.exportDocument = true; _io.exportDocument = true;
document.documentElement.acceptDialog(); document.querySelector('dialog').acceptDialog();
} }
} }
@ -322,7 +323,7 @@ var Zotero_File_Interface_Bibliography = new function() {
this.manageStyles = function () { this.manageStyles = function () {
document.querySelector('dialog').getButton('cancel').click(); document.querySelector('dialog').cancelDialog();
var win = Zotero.Utilities.Internal.openPreferences('zotero-prefpane-cite', { tab: 'styles-tab' }); var win = Zotero.Utilities.Internal.openPreferences('zotero-prefpane-cite', { tab: 'styles-tab' });
if (isDocPrefs) { if (isDocPrefs) {
Zotero.Utilities.Internal.activate(win); Zotero.Utilities.Internal.activate(win);

View file

@ -1593,15 +1593,16 @@ var Columns = class {
}; };
function renderCell(index, data, column) { function renderCell(index, data, column) {
column = column || { columnName: "" }
let span = document.createElement('span'); let span = document.createElement('span');
span.className = `cell ${column.className}`; span.className = `cell ${column.className}`;
span.innerText = data; span.innerText = data;
return span; return span;
} }
function renderCheckboxCell(index, data, column) { function renderCheckboxCell(index, data, columnName) {
let span = document.createElement('span'); let span = document.createElement('span');
span.className = `cell checkbox ${column.className}`; span.className = `cell checkbox ${columnName}`;
span.setAttribute('role', 'checkbox'); span.setAttribute('role', 'checkbox');
span.setAttribute('aria-checked', data); span.setAttribute('aria-checked', data);
if (data) { if (data) {
@ -1626,16 +1627,21 @@ function makeRowRenderer(getRowData) {
div.classList.toggle('focused', selection.focused == index); div.classList.toggle('focused', selection.focused == index);
const rowData = getRowData(index); const rowData = getRowData(index);
for (let column of columns) { if (columns.length) {
if (column.hidden) continue; for (let column of columns) {
if (column.hidden) continue;
if (column.type === 'checkbox') { if (column.type === 'checkbox') {
div.appendChild(renderCheckboxCell(index, rowData[column.dataKey], column)); div.appendChild(renderCheckboxCell(index, rowData[column.dataKey], column));
} }
else { else {
div.appendChild(renderCell(index, rowData[column.dataKey], column)); div.appendChild(renderCell(index, rowData[column.dataKey], column));
}
} }
} }
else {
div.appendChild(renderCell(index, rowData));
}
return div; return div;
}; };

View file

@ -0,0 +1,85 @@
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2022 Corporation for Digital Scholarship
Vienna, Virginia, USA
http://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";
{
if (!customElements.get("richlistitem")) {
delete document.createXULElement("richlistitem");
}
/**
* Extend richlistbox for checkbox inputs since we use them in multiple places
*/
class RichListCheckbox extends customElements.get('richlistitem') {
connectedCallback() {
this._checkbox = document.createXULElement('checkbox');
this._checkbox.setAttribute('native', 'true');
this._checkbox.setAttribute('checked', this.checked);
this._checkbox.addEventListener('focus', () => this.control.focus())
this._label = document.createElement('label');
this._label.textContent = this.label;
this.append(this._checkbox);
this.append(this._label);
// this.control (parent richlistbox) only available after connecting
this.control.addEventListener('keypress', (event) => {
if (
event.key == " " &&
!event.ctrlKey &&
!event.shiftKey &&
!event.altKey &&
!event.metaKey
) {
if (!this.selected) return;
this.checked = !this.checked;
event.stopPropagation();
}
});
this.addEventListener('dblclick', (event) => {
this.checked = !this.checked;
event.stopPropagation();
});
}
get label() {
return this.getAttribute('label');
}
set label(val) {
this._label.innerText = val;
return this.setAttribute('label', 'val');
}
get checked() {
return JSON.parse(this.getAttribute('checked'));
}
set checked(val) {
this._checkbox.setAttribute('checked', !!val);
return this.setAttribute('checked', !!val);
}
}
customElements.define("richlistcheckbox", RichListCheckbox);
}

View file

@ -52,6 +52,7 @@ var Zotero_Citation_Dialog = new function () {
var _sortCheckbox; var _sortCheckbox;
var _citationList; var _citationList;
var _originalHTML; var _originalHTML;
var _editor;
var serial_number; var serial_number;
var io; var io;
@ -85,16 +86,21 @@ var Zotero_Citation_Dialog = new function () {
} }
}, 0); }, 0);
document.documentElement.getButton("extra1").label = Zotero.getString("citation.multipleSources");
document.documentElement.getButton("extra2").label = Zotero.getString("citation.showEditor");
io = window.arguments[0].wrappedJSObject; io = window.arguments[0].wrappedJSObject;
// find accept button // find accept button
_acceptButton = document.getElementById("zotero-add-citation-dialog").getButton("accept"); _acceptButton = document.querySelector('dialog').getButton("accept");
_multipleSourceButton = document.documentElement.getButton("extra1"); _multipleSourceButton = document.querySelector('dialog').getButton("extra1");
_multipleSourceButton.label = Zotero.getString("citation.multipleSources")
document.querySelector('dialog').getButton("extra2").label = Zotero.getString("citation.showEditor");
_autoRegeneratePref = Zotero.Prefs.get("integration.autoRegenerate"); _autoRegeneratePref = Zotero.Prefs.get("integration.autoRegenerate");
_citationList = document.getElementById("citation-list"); _citationList = document.getElementById("item-list");
window.addEventListener('dialogaccept', () => Zotero_Citation_Dialog.accept());
window.addEventListener('dialogcancel', () => Zotero_Citation_Dialog.cancel());
window.addEventListener('dialogextra1', () => Zotero_Citation_Dialog.toggleMultipleSources());
window.addEventListener('dialogextra2', () => Zotero_Citation_Dialog.toggleEditor());
// Manipulated by _addItem(). Discriminates between cite instances // Manipulated by _addItem(). Discriminates between cite instances
// based on the same item in the same citation. Internal throwaway variable, // based on the same item in the same citation. Internal throwaway variable,
@ -137,7 +143,7 @@ var Zotero_Citation_Dialog = new function () {
yield doLoad(); yield doLoad();
// if we already have a citation, load data from it // if we already have a citation, load data from it
document.getElementById('editor').format = "RTF"; _editor = document.querySelector('#editor').contentWindow.editor;
if(io.citation.citationItems.length) { if(io.citation.citationItems.length) {
if(io.citation.citationItems.length === 1) { if(io.citation.citationItems.length === 1) {
// single citation // single citation
@ -217,7 +223,7 @@ var Zotero_Citation_Dialog = new function () {
} }
_multipleSourcesOn = !_multipleSourcesOn; _multipleSourcesOn = !_multipleSourcesOn;
var popup = document.defaultView; var popup = document.defaultView;
var dialog = document.getElementById("zotero-add-citation-dialog"); var dialog = document.documentElement;
if (dialog.getAttribute("height") == 1) { if (dialog.getAttribute("height") == 1) {
popup.sizeToContent(); popup.sizeToContent();
} }
@ -287,7 +293,7 @@ var Zotero_Citation_Dialog = new function () {
// turn off highlight in selected item list // turn off highlight in selected item list
_suppressNextListSelect = true; _suppressNextListSelect = true;
document.getElementById("citation-list").selectedIndex = -1; document.getElementById("item-list").selectedIndex = -1;
// disable all fields // disable all fields
@ -515,7 +521,7 @@ var Zotero_Citation_Dialog = new function () {
* Ask whether to modify the preview * Ask whether to modify the preview
*/ */
function confirmRegenerate(focusShifted) { function confirmRegenerate(focusShifted) {
if(document.getElementById('editor').value == _originalHTML || _originalHTML === undefined) { if(_editor.getContent() == _originalHTML || _originalHTML === undefined) {
// no changes; just update without asking // no changes; just update without asking
_updatePreview(); _updatePreview();
return; return;
@ -563,26 +569,24 @@ var Zotero_Citation_Dialog = new function () {
_previewShown = !_previewShown; _previewShown = !_previewShown;
if(_previewShown) { if(_previewShown) {
document.documentElement.getButton("extra2").label = Zotero.getString("citation.hideEditor"); document.querySelector('dialog').getButton("extra2").label = Zotero.getString("citation.hideEditor");
if (!text && _customHTML) { if (!text && _customHTML) {
text = _customHTML; text = _customHTML;
} }
if(text) { if(text) {
io.preview().then(function(preview) { io.preview().then(function(preview) {
_originalHTML = preview; _originalHTML = preview;
editor.value = text; _editor.setContent(text, true);
}).done(); }).done();
} else { } else {
_updatePreview(); _updatePreview();
} }
} else { } else {
if (editor.initialized) { _customHTML = _editor.getContent(true);
if (editor.value) { document.querySelector('dialog').getButton("extra2").label = Zotero.getString("citation.showEditor");
_customHTML = editor.value;
}
}
document.documentElement.getButton("extra2").label = Zotero.getString("citation.showEditor");
} }
// To resize virtualized-tables
window.dispatchEvent(new Event('resize'));
} }
/* /*
@ -594,10 +598,10 @@ var Zotero_Citation_Dialog = new function () {
_getCitation(); _getCitation();
var isCustom = _previewShown && io.citation.citationItems.length // if a citation is selected var isCustom = _previewShown && io.citation.citationItems.length // if a citation is selected
&& _originalHTML && _originalHTML
&& document.getElementById('editor').value != _originalHTML // and citation has been edited && _editor.getContent(true) != _originalHTML // and citation has been edited
if(isCustom) { if(isCustom) {
var citation = document.getElementById('editor').value; var citation = _editor.getContent(true);
if(Zotero.Utilities.trim(citation) == "") { if(Zotero.Utilities.trim(citation) == "") {
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService); .getService(Components.interfaces.nsIPromptService);
@ -664,23 +668,17 @@ var Zotero_Citation_Dialog = new function () {
*/ */
function _updatePreview() { function _updatePreview() {
if(_previewShown) { if(_previewShown) {
var editor = document.getElementById('editor');
_getCitation(); _getCitation();
editor.readonly = !io.citation.citationItems.length; _editor.setEnabled(io.citation.citationItems.length);
if(io.citation.citationItems.length) { if (io.citation.citationItems.length) {
io.preview().then(function(preview) { io.preview().then((preview) => {
editor.value = preview; _editor.setContent(preview, true);
if (editor.initialized) { _originalHTML = _editor.getContent(true);
_originalHTML = editor.value;
}
else {
editor.onInit(() => _originalHTML = editor.value);
}
}); });
} else { } else {
editor.value = ""; _editor.setContent("");
_originalHTML = ""; _originalHTML = "";
} }
} }
@ -818,7 +816,7 @@ var Zotero_Citation_Dialog = new function () {
* Add an item to the item list (multiple sources only) * Add an item to the item list (multiple sources only)
*/ */
function _addItem(item, forceID) { function _addItem(item, forceID) {
var itemNode = document.createElement("listitem"); var itemNode = document.createXULElement("richlistitem");
var itemDataID; var itemDataID;
if (!forceID) { if (!forceID) {
@ -829,9 +827,11 @@ var Zotero_Citation_Dialog = new function () {
} }
itemNode.setAttribute("value", itemDataID); itemNode.setAttribute("value", itemDataID);
itemNode.setAttribute("label", item.getDisplayTitle()); let image = document.createXULElement('image');
image.src = item.getImageSrc();
itemNode.append(image);
itemNode.setAttribute("class", "listitem-iconic"); itemNode.setAttribute("class", "listitem-iconic");
itemNode.setAttribute("image", item.getImageSrc()); itemNode.append(item.getDisplayTitle());
_citationList.appendChild(itemNode); _citationList.appendChild(itemNode);
return itemNode; return itemNode;
} }

View file

@ -32,36 +32,42 @@
<?xml-stylesheet href="chrome://zotero/skin/integration.css" type="text/css"?> <?xml-stylesheet href="chrome://zotero/skin/integration.css" type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd"> <!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
<dialog <window
id="zotero-add-citation-dialog"
windowtype="zotero:item-selector" windowtype="zotero:item-selector"
orient="vertical" orient="vertical"
title="&zotero.integration.addEditCitation.title;" title="&zotero.integration.addEditCitation.title;"
width="600" height="450" width="600" height="450"
onload="Zotero_Citation_Dialog.load();" onload="Zotero_Citation_Dialog.load();"
onunload="doUnload();" onunload="doUnload();"
ondialogaccept="return Zotero_Citation_Dialog.accept();"
ondialogcancel="Zotero_Citation_Dialog.cancel();"
onclose="Zotero_Citation_Dialog.cancel();" onclose="Zotero_Citation_Dialog.cancel();"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml"
persist="screenX screenY width height" persist="screenX screenY width height"
resizable="true" resizable="true">
buttons="extra1,extra2,accept,cancel" <dialog
ondialogextra2="Zotero_Citation_Dialog.toggleEditor()" id="zotero-add-citation-dialog"
ondialogextra1="Zotero_Citation_Dialog.toggleMultipleSources()"> buttons="extra1,extra2,accept,cancel">
<script src="../include.js"/>
<script src="../selectItemsDialog.js"/>
<script src="addCitationDialog.js"/>
<script>
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
Services.scriptloader.loadSubScript("chrome://zotero/content/include.js", this);
Services.scriptloader.loadSubScript("chrome://zotero/content/selectItemsDialog.js", this);
Services.scriptloader.loadSubScript("chrome://zotero/content/integration/addCitationDialog.js", this);
// Custom elements
Services.scriptloader.loadSubScript("chrome://global/content/customElements.js", this);
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/quickSearchTextbox.js", this);
</script>
<vbox id="zotero-select-items-container" flex="1"> <vbox id="zotero-select-items-container" flex="1">
<vbox flex="1"> <vbox flex="1">
<hbox flex="1"> <hbox flex="1">
<vbox align="stretch" flex="1"> <vbox align="stretch" flex="1" style="min-width: 500px">
<hbox align="center" pack="end"> <hbox align="center" pack="end">
<textbox id="zotero-tb-search" type="search" timeout="250" oncommand="onSearch()" tabindex="1" <quick-search-textbox id="zotero-tb-search" timeout="250" oncommand="onSearch()" dir="reverse"/>
onkeypress="if(event.keyCode == event.DOM_VK_ESCAPE) { if (this.value == '') { cancelDialog(); return false; } this.value = ''; onSearch(); return false; } return true;"/>
</hbox> </hbox>
<hbox flex="1" style="margin-top: 5px"> <hbox flex="1" style="margin-top: 5px">
<vbox id="zotero-collections-tree-container" class="virtualized-table-container" style="min-width: 200px"> <vbox id="zotero-collections-tree-container" class="virtualized-table-container" style="min-width: 200px">
@ -82,8 +88,8 @@
<toolbarbutton id="down" oncommand="Zotero_Citation_Dialog.down()" disabled="true"/> <toolbarbutton id="down" oncommand="Zotero_Citation_Dialog.down()" disabled="true"/>
</vbox> </vbox>
<vbox align="left"> <vbox align="left">
<checkbox id="keepSorted" hidden="true" checked="false" oncommand="Zotero_Citation_Dialog.citationSortUnsort()" label="&zotero.citation.keepSorted.label;"/> <checkbox id="keepSorted" hidden="true" checked="false" oncommand="Zotero_Citation_Dialog.citationSortUnsort()" label="&zotero.citation.keepSorted.label;" native="true"/>
<listbox id="citation-list" flex="1" align="stretch" seltype="single" <richlistbox id="item-list" flex="1" align="stretch" seltype="single" style="width: 250px;"
onselect="Zotero_Citation_Dialog.listItemSelected();"/> onselect="Zotero_Citation_Dialog.listItemSelected();"/>
</vbox> </vbox>
</hbox> </hbox>
@ -93,29 +99,34 @@
<vbox flex="1"> <vbox flex="1">
<hbox align="center"> <hbox align="center">
<label value="&zotero.citation.prefix.label;"/> <label value="&zotero.citation.prefix.label;"/>
<textbox oninput="Zotero_Citation_Dialog.confirmRegenerate(false)" onchange="Zotero_Citation_Dialog.confirmRegenerate(true)" class="fix" id="prefix" align="stretch" flex="1" tabindex="3"/> <html:input type="text" class="fix" id="prefix" tabindex="3"
oninput="Zotero_Citation_Dialog.confirmRegenerate(false)"
onchange="Zotero_Citation_Dialog.confirmRegenerate(true)"/>
</hbox> </hbox>
<hbox align="center"> <hbox align="center">
<label value="&zotero.citation.suffix.label;"/> <label value="&zotero.citation.suffix.label;"/>
<textbox oninput="Zotero_Citation_Dialog.confirmRegenerate(false)" onchange="Zotero_Citation_Dialog.confirmRegenerate(true)" class="fix" id="suffix" align="stretch" flex="1" tabindex="4"/> <html:input type="text" class="fix" id="suffix" tabindex="4"
oninput="Zotero_Citation_Dialog.confirmRegenerate(false)"
onchange="Zotero_Citation_Dialog.confirmRegenerate(true)"/>
</hbox> </hbox>
<spacer flex="1"/> <spacer flex="1"/>
</vbox> </vbox>
<separator flex="4"/> <separator flex="4"/>
<vbox flex="1"> <vbox flex="1">
<hbox align="stretch"> <hbox align="stretch">
<menulist onchange="Zotero_Citation_Dialog.confirmRegenerate(true)" id="label" tabindex="5"> <menulist onchange="Zotero_Citation_Dialog.confirmRegenerate(true)" id="label" tabindex="5" native="true">
<menupopup id="locator-type-popup"/> <menupopup id="locator-type-popup"/>
</menulist> </menulist>
<textbox oninput="Zotero_Citation_Dialog.confirmRegenerate(false)" onchange="Zotero_Citation_Dialog.confirmRegenerate(true)" id="locator" tabindex="2" flex="1"/> <textbox oninput="Zotero_Citation_Dialog.confirmRegenerate(false)" onchange="Zotero_Citation_Dialog.confirmRegenerate(true)" id="locator" tabindex="2" flex="1"/>
</hbox> </hbox>
<separator style="height: 2px" flex="1"/> <separator style="height: 2px" flex="1"/>
<checkbox oncommand="Zotero_Citation_Dialog.confirmRegenerate(true)" id="suppress-author" label="&zotero.citation.suppressAuthor.label;" tabindex="6"/> <checkbox oncommand="Zotero_Citation_Dialog.confirmRegenerate(true)" id="suppress-author" label="&zotero.citation.suppressAuthor.label;" tabindex="6" native="true"/>
</vbox> </vbox>
</hbox> </hbox>
</vbox> </vbox>
<textbox id="editor" type="styled" mode="integration" hidden="true" flex="1"/> <iframe id="editor" src="simpleEditor.html" hidden="true" flex="1" type="content" remote="false" maychangeremoteness="false"/>
<description id="zotero-editor-warning" style="margin: 9px 1px 0" hidden="true">&zotero.citation.editorWarning.label;</description> <description id="zotero-editor-warning" style="margin: 9px 1px 0" hidden="true">&zotero.citation.editorWarning.label;</description>
</vbox> </vbox>
</dialog> </dialog>
</window>

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<!--
***** BEGIN LICENSE BLOCK *****
Copyright © 2022 Center for History and New Media
George Mason University, Fairfax, Virginia, USA
http://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 *****
-->
<html xmlns="http://www.w3.org/1999/xhtml" style="height: 100%">
<head>
<link rel="stylesheet" type="text/css" href="chrome://zotero/skin/integration.css"/>
<link rel="stylesheet" type="text/css" href="chrome://zotero-platform/content/integration.css"/>
</head>
<body contenteditable="true" spellcheck="false" class="citation-dialog editor"></body>
</html>

View file

@ -31,6 +31,7 @@ var Zotero_Bibliography_Dialog = new function () {
var _accepted = false; var _accepted = false;
var _revertButton, _revertAllButton, _addButton, _removeButton; var _revertButton, _revertAllButton, _addButton, _removeButton;
var _itemList; var _itemList;
var _editor;
var _suppressAllSelectEvents = false; var _suppressAllSelectEvents = false;
/** /**
@ -39,18 +40,23 @@ var Zotero_Bibliography_Dialog = new function () {
this.load = async function() { this.load = async function() {
bibEditInterface = window.arguments[0].wrappedJSObject; bibEditInterface = window.arguments[0].wrappedJSObject;
_revertAllButton = document.documentElement.getButton("extra2"); _revertAllButton = document.querySelector('dialog').getButton("extra2");
_revertButton = document.documentElement.getButton("extra1"); _revertButton = document.querySelector('dialog').getButton("extra1");
_addButton = document.getElementById("add"); _addButton = document.getElementById("add");
_removeButton = document.getElementById("remove"); _removeButton = document.getElementById("remove");
_itemList = document.getElementById("item-list"); _itemList = document.getElementById("item-list");
_revertAllButton.label = Zotero.getString("integration.revertAll.button"); _revertAllButton.label = Zotero.getString("integration.revertAll.button");
_revertAllButton.disabled = bibEditInterface.isAnyEdited(); _revertAllButton.disabled = bibEditInterface.isAnyEdited();
_revertAllButton.addEventListener('command', () => Zotero_Bibliography_Dialog.revertAll());
_revertButton.label = Zotero.getString("integration.revert.button"); _revertButton.label = Zotero.getString("integration.revert.button");
_revertButton.disabled = true; _revertButton.disabled = true;
_revertButton.addEventListener('command', () => Zotero_Bibliography_Dialog.revert());
document.getElementById('editor').format = "RTF"; window.addEventListener('dialogaccept', () => Zotero_Bibliography_Dialog.accept());
window.addEventListener('dialogcancel', () => Zotero_Bibliography_Dialog.close());
_editor = document.querySelector('#editor').contentWindow.editor;
// load (from selectItemsDialog.js) // load (from selectItemsDialog.js)
await doLoad(); await doLoad();
@ -274,25 +280,24 @@ var Zotero_Bibliography_Dialog = new function () {
* Updates the contents of the preview pane * Updates the contents of the preview pane
*/ */
function _updatePreview(ignoreSelection) { function _updatePreview(ignoreSelection) {
var index = !ignoreSelection && _itemList.selectedItems.length == 1 ? _itemList.selectedIndex : undefined; var index = !ignoreSelection && _itemList.selectedCount == 1 && _itemList.selectedIndex != -1 ? _itemList.selectedIndex : undefined;
var editor = document.getElementById('editor');
if(_lastSelectedItemID) { if(_lastSelectedItemID) {
var newValue = editor.value; var newValue = _editor.getContent(true);
if(_lastSelectedValue != newValue) { if(_lastSelectedValue != newValue) {
bibEditInterface.setCustomText(_lastSelectedItemID, newValue); bibEditInterface.setCustomText(_lastSelectedItemID, newValue);
} }
} }
editor.readonly = index === undefined; _editor.setEnabled(index !== undefined);
if(index !== undefined) { if(index !== undefined) {
var itemID = bibEditInterface.bib[0].entry_ids[index]; var itemID = bibEditInterface.bib[0].entry_ids[index];
editor.value = bibEditInterface.bib[1][index]; _editor.setContent(bibEditInterface.bib[1][index], true);
_lastSelectedIndex = index; _lastSelectedIndex = index;
_lastSelectedItemID = itemID; _lastSelectedItemID = itemID;
_lastSelectedValue = editor.value; _lastSelectedValue = _editor.getContent(true);
} else { } else {
editor.value = ""; _editor.setContent("");
_lastSelectedIndex = _lastSelectedItemID = _lastSelectedValue = false; _lastSelectedIndex = _lastSelectedItemID = _lastSelectedValue = false;
} }
@ -314,11 +319,13 @@ var Zotero_Bibliography_Dialog = new function () {
// add new items // add new items
for(var i=0; i<items.length; i++) { for(var i=0; i<items.length; i++) {
var itemNode = document.createElement("listitem"); var itemNode = document.createXULElement("richlistitem");
itemNode.setAttribute("value", i); itemNode.setAttribute("value", i);
itemNode.setAttribute("label", items[i].getDisplayTitle()); let image = document.createXULElement('image');
image.src = items[i].getImageSrc();
itemNode.append(image);
itemNode.append(items[i].getDisplayTitle());
itemNode.setAttribute("class", "listitem-iconic"); itemNode.setAttribute("class", "listitem-iconic");
itemNode.setAttribute("image", items[i].getImageSrc());
itemList.appendChild(itemNode); itemList.appendChild(itemNode);
} }

View file

@ -31,34 +31,40 @@
<?xml-stylesheet href="chrome://zotero/skin/integration.css" type="text/css"?> <?xml-stylesheet href="chrome://zotero/skin/integration.css" type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd"> <!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
<dialog <window
id="zotero-edit-bibliography-dialog"
orient="vertical" orient="vertical"
title="&zotero.integration.editBibliography.title;" title="&zotero.integration.editBibliography.title;"
width="750" height="450" width="750" height="450"
onload="Zotero_Bibliography_Dialog.load();" onload="Zotero_Bibliography_Dialog.load();"
ondialogaccept="Zotero_Bibliography_Dialog.accept();"
ondialogcancel="Zotero_Bibliography_Dialog.close();"
onclose="Zotero_Bibliography_Dialog.close();" onclose="Zotero_Bibliography_Dialog.close();"
onunload="doUnload();" onunload="doUnload();"
buttons="extra1,extra2,accept,cancel" buttonpack="end"
xmlns:html="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
persist="screenX screenY width height" persist="screenX screenY width height"
resizable="true" resizable="true">
ondialogextra1="Zotero_Bibliography_Dialog.revert()" <dialog
ondialogextra2="Zotero_Bibliography_Dialog.revertAll()"> id="zotero-edit-bibliography-dialog"
buttons="extra1,extra2,accept,cancel" buttonpack="end">
<script src="../include.js"/> <script>
<script src="../selectItemsDialog.js"/> var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
<script src="editBibliographyDialog.js"/>
Services.scriptloader.loadSubScript("chrome://zotero/content/include.js", this);
Services.scriptloader.loadSubScript("chrome://zotero/content/selectItemsDialog.js", this);
Services.scriptloader.loadSubScript("chrome://zotero/content/integration/editBibliographyDialog.js", this);
// Custom elements
Services.scriptloader.loadSubScript("chrome://global/content/customElements.js", this);
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/quickSearchTextbox.js", this);
</script>
<vbox id="zotero-select-items-container" flex="1"> <vbox id="zotero-select-items-container" flex="1">
<vbox flex="1"> <vbox flex="1">
<hbox flex="1"> <hbox flex="1">
<vbox align="stretch" flex="1"> <vbox align="stretch" flex="1">
<hbox align="center" pack="end"> <hbox align="center" pack="end">
<textbox id="zotero-tb-search" type="search" timeout="250" oncommand="onSearch()" dir="reverse" onkeypress="if(event.keyCode == event.DOM_VK_ESCAPE) { this.value = ''; this.doCommand('cmd_zotero_search'); return false; } return true;"/> <quick-search-textbox id="zotero-tb-search" timeout="250" oncommand="onSearch()" dir="reverse"/>
</hbox> </hbox>
<hbox flex="1" style="margin-top: 5px"> <hbox flex="1" style="margin-top: 5px">
<vbox id="zotero-collections-tree-container" class="virtualized-table-container" style="min-width: 150px"> <vbox id="zotero-collections-tree-container" class="virtualized-table-container" style="min-width: 150px">
@ -78,7 +84,7 @@
</vbox> </vbox>
<vbox> <vbox>
<label value="&zotero.integration.references.label;"/> <label value="&zotero.integration.references.label;"/>
<listbox id="item-list" flex="1" align="stretch" seltype="multiple" <richlistbox id="item-list" flex="1" align="stretch" seltype="multiple"
style="width: 250px;" onselect="Zotero_Bibliography_Dialog.listItemSelected();" style="width: 250px;" onselect="Zotero_Bibliography_Dialog.listItemSelected();"
onchanged="Zotero_Bibliography_Dialog.textChanged()"/> onchanged="Zotero_Bibliography_Dialog.textChanged()"/>
</vbox> </vbox>
@ -86,7 +92,8 @@
</hbox> </hbox>
</vbox> </vbox>
<textbox id="editor" type="styled" mode="integration" flex="1"/> <iframe id="editor" src="simpleEditor.html" flex="1" type="content" remote="false" maychangeremoteness="false"/>
<description id="zotero-editor-warning" style="margin: 9px 1px 0">&zotero.citation.editorWarning.label;</description> <description id="zotero-editor-warning" style="margin: 9px 1px 0">&zotero.citation.editorWarning.label;</description>
</vbox> </vbox>
</dialog> </dialog>
</window>

View file

@ -28,6 +28,7 @@
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?> <?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero/skin/integration.css" type="text/css"?> <?xml-stylesheet href="chrome://zotero/skin/integration.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero-platform/content/integration.css" type="text/css"?> <?xml-stylesheet href="chrome://zotero-platform/content/integration.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero-platform-version/content/style.css" type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd"> <!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
<window <window
@ -50,14 +51,21 @@
<deck class="citation-dialog deck" selectedIndex="0" flex="1"> <deck class="citation-dialog deck" selectedIndex="0" flex="1">
<hbox class="citation-dialog search" flex="1" align="start"> <hbox class="citation-dialog search" flex="1" align="start">
<hbox flex="1"> <hbox flex="1">
<iframe class="citation-dialog iframe" ondragstart="event.stopPropagation()" src="data:application/xhtml+xml,%3C!DOCTYPE%20html%20PUBLIC%20%22-//W3C//DTD%20XHTML%201.0%20Strict//EN%22%20%22http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd%22%3E%3Chtml%20xmlns=%22http://www.w3.org/1999/xhtml%22%3E%3Chead%3E%3Clink%20rel=%22stylesheet%22%20type=%22text/css%22%20href=%22chrome://zotero/skin/integration.css%22/%3E%3Clink%20rel=%22stylesheet%22%20type=%22text/css%22%20href=%22chrome://zotero-platform/content/integration.css%22/%3E%3C/head%3E%3Cbody%20contenteditable=%22true%22%20spellcheck=%22false%22%20class=%22citation-dialog%20editor%22/%3E%3C/html%3E" <iframe
tabindex="1" flex="1"/> class="citation-dialog iframe"
ondragstart="event.stopPropagation()"
src="citationDialogIframe.html"
tabindex="1"
flex="1"
type="content"
remote="false"
maychangeremoteness="false"/>
<vbox class="citation-dialog spinner" style="visibility: hidden"> <vbox class="citation-dialog spinner" style="visibility: hidden">
<image class="zotero-spinner-16"/> <image class="zotero-spinner-16"/>
</vbox> </vbox>
</hbox> </hbox>
</hbox> </hbox>
<progressmeter class="citation-dialog progress-meter" mode="undetermined" value="0" flex="1"/> <html:progress class="citation-dialog progress-meter" max="100"/>
</deck> </deck>
</box> </box>
<panel class="citation-dialog reference-panel" noautofocus="true" norestorefocus="true" <panel class="citation-dialog reference-panel" noautofocus="true" norestorefocus="true"

View file

@ -0,0 +1,104 @@
<?xml version="1.0"?>
<!--
***** BEGIN LICENSE BLOCK *****
Copyright © 2009 Center for History and New Media
George Mason University, Fairfax, Virginia, USA
http://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 *****
-->
<?xml-stylesheet href="chrome://global/skin/"?>
<?xml-stylesheet href="chrome://zotero/skin/zotero.css"?>
<?xml-stylesheet href="chrome://zotero/skin/bibliography.css"?>
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
<window
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
title="&zotero.integration.docPrefs.title;"
onload="Zotero_File_Interface_Bibliography.init();"
>
<dialog
id="zotero-doc-prefs-dialog"
orient="vertical"
buttons="accept,cancel,help"
persist="screenX screenY"
ondialogaccept="Zotero_File_Interface_Bibliography.acceptSelection();"
ondialoghelp="Zotero_File_Interface_Bibliography.openHelpLink();"
onclose="document.documentElement.cancelDialog(); event.preventDefault(); event.stopPropagation();"
style="width: 600px">
<script src="../include.js"/>
<script src="../bibliography.js"/>
<vbox id="zotero-bibliography-container">
<groupbox>
<label><html:h2>&zotero.bibliography.style.label;</html:h2></label>
<richlistbox id="style-listbox" onselect="Zotero_File_Interface_Bibliography.styleChanged()" flex="1"/>
<hbox align="right">
<label id="manage-styles" class="text-link"
onclick="Zotero_File_Interface_Bibliography.manageStyles()">&zotero.bibliography.manageStyles;</label>
</hbox>
</groupbox>
<groupbox id="locale-box">
<hbox align="center">
<label><html:h2>&zotero.bibliography.locale.label;</html:h2></label>
<menulist id="locale-menu" oncommand="Zotero_File_Interface_Bibliography.localeChanged(this.selectedItem.value)" native="true"/>
</hbox>
</groupbox>
<groupbox id="displayAs-groupbox">
<label><html:h2>&zotero.integration.prefs.displayAs.label;</html:h2></label>
<radiogroup id="displayAs" orient="horizontal">
<radio id="footnotes" label="&zotero.integration.prefs.footnotes.label;" selected="true"/>
<radio id="endnotes" label="&zotero.integration.prefs.endnotes.label;"/>
</radiogroup>
</groupbox>
<groupbox id="formatUsing-groupbox">
<label><html:h2>&zotero.integration.prefs.formatUsing.label;</html:h2></label>
<radiogroup id="formatUsing" orient="vertical">
<radio id="fields" selected="true"/>
<label class="radioDescription" id="fields-caption"/>
<label class="radioDescription" id="fields-file-format-notice"/>
<radio id="bookmarks" label="&zotero.integration.prefs.bookmarks.label;"/>
<description class="radioDescription" id="bookmarks-caption">&zotero.integration.prefs.bookmarks.caption;</description>
<description class="radioDescription" id="bookmarks-file-format-notice"/>
</radiogroup>
</groupbox>
<vbox class="pref-vbox" id="automaticJournalAbbreviations-vbox">
<checkbox id="automaticJournalAbbreviations-checkbox" label="&zotero.integration.prefs.automaticJournalAbbeviations.label;" native="true"/>
<description class="radioDescription">&zotero.integration.prefs.automaticJournalAbbeviations.caption;</description>
</vbox>
<vbox id="advanced-settings" hidden="false">
<vbox id="automaticCitationUpdates-vbox">
<checkbox id="automaticCitationUpdates-checkbox" label="&zotero.integration.prefs.automaticCitationUpdates.label;" tooltiptext="&zotero.integration.prefs.automaticCitationUpdates.tooltip;" native="true"/>
<description class="radioDescription">&zotero.integration.prefs.automaticCitationUpdates.description;</description>
</vbox>
<hbox id="exportImport" hidden="true">
<button label="&zotero.integration.prefs.exportDocument;" oncommand="Zotero_File_Interface_Bibliography.exportDocument()"/>
</hbox>
</vbox>
</vbox>
</dialog>
</window>

View file

@ -1,100 +0,0 @@
<?xml version="1.0"?>
<!--
***** BEGIN LICENSE BLOCK *****
Copyright © 2009 Center for History and New Media
George Mason University, Fairfax, Virginia, USA
http://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 *****
-->
<?xml-stylesheet href="chrome://global/skin/global.css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
<?xml-stylesheet href="chrome://zotero/skin/bibliography.css"?>
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
<dialog
id="zotero-doc-prefs-dialog"
orient="vertical"
buttons="accept,cancel,help"
title="&zotero.integration.docPrefs.title;"
onload="Zotero_File_Interface_Bibliography.init();"
ondialogaccept="Zotero_File_Interface_Bibliography.acceptSelection();"
ondialoghelp="Zotero_File_Interface_Bibliography.openHelpLink();"
onclose="document.documentElement.cancelDialog(); event.preventDefault(); event.stopPropagation();"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
persist="screenX screenY"
style="width: 600px">
<script src="../include.js"/>
<script src="../bibliography.js"/>
<vbox id="zotero-bibliography-container">
<groupbox>
<caption label="&zotero.bibliography.style.label;"/>
<listbox id="style-listbox" onselect="Zotero_File_Interface_Bibliography.styleChanged()"/>
<hbox align="right">
<label id="manage-styles" class="text-link"
onclick="Zotero_File_Interface_Bibliography.manageStyles()">&zotero.bibliography.manageStyles;</label>
</hbox>
</groupbox>
<groupbox id="locale-box">
<hbox align="center">
<caption label="&zotero.bibliography.locale.label;"/>
<menulist id="locale-menu" oncommand="Zotero_File_Interface_Bibliography.localeChanged(this.selectedItem.value)"/>
</hbox>
</groupbox>
<groupbox id="displayAs-groupbox">
<caption label="&zotero.integration.prefs.displayAs.label;"/>
<radiogroup id="displayAs" orient="horizontal">
<radio id="footnotes" label="&zotero.integration.prefs.footnotes.label;" selected="true"/>
<radio id="endnotes" label="&zotero.integration.prefs.endnotes.label;"/>
</radiogroup>
</groupbox>
<groupbox id="formatUsing-groupbox">
<caption label="&zotero.integration.prefs.formatUsing.label;"/>
<radiogroup id="formatUsing" orient="vertical">
<radio id="fields" selected="true"/>
<label class="radioDescription" id="fields-caption"/>
<label class="radioDescription" id="fields-file-format-notice"/>
<radio id="bookmarks" label="&zotero.integration.prefs.bookmarks.label;"/>
<description class="radioDescription" id="bookmarks-caption">&zotero.integration.prefs.bookmarks.caption;</description>
<description class="radioDescription" id="bookmarks-file-format-notice"/>
</radiogroup>
</groupbox>
<vbox class="pref-vbox" id="automaticJournalAbbreviations-vbox">
<checkbox id="automaticJournalAbbreviations-checkbox" label="&zotero.integration.prefs.automaticJournalAbbeviations.label;"/>
<description class="radioDescription">&zotero.integration.prefs.automaticJournalAbbeviations.caption;</description>
</vbox>
<vbox id="advanced-settings" hidden="false">
<vbox id="automaticCitationUpdates-vbox">
<checkbox id="automaticCitationUpdates-checkbox" label="&zotero.integration.prefs.automaticCitationUpdates.label;" tooltiptext="&zotero.integration.prefs.automaticCitationUpdates.tooltip;"/>
<description class="radioDescription">&zotero.integration.prefs.automaticCitationUpdates.description;</description>
</vbox>
<hbox id="exportImport" hidden="true">
<button label="&zotero.integration.prefs.exportDocument;" oncommand="Zotero_File_Interface_Bibliography.exportDocument()"/>
</hbox>
</vbox>
</vbox>
</dialog>

View file

@ -81,9 +81,8 @@ var Zotero_ProgressBar = new function () {
function _onProgress(percent) { function _onProgress(percent) {
var meter = document.querySelector(".citation-dialog.progress-meter"); var meter = document.querySelector(".citation-dialog.progress-meter");
if(percent === null) { if(percent === null) {
meter.mode = "undetermined"; meter.removeAttribute('value');
} else { } else {
meter.mode = "determined";
meter.value = Math.round(percent); meter.value = Math.round(percent);
} }
} }

View file

@ -45,7 +45,7 @@
<box orient="horizontal" class="citation-dialog entry"> <box orient="horizontal" class="citation-dialog entry">
<deck class="citation-dialog deck" selectedIndex="0" flex="1"> <deck class="citation-dialog deck" selectedIndex="0" flex="1">
<progressmeter class="citation-dialog progress-meter" mode="undetermined" value="0" flex="1"/> <html:progress class="citation-dialog progress-meter" max="100"/>
</deck> </deck>
</box> </box>
</window> </window>

View file

@ -22,7 +22,8 @@
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
*/ */
Components.utils.import("resource://gre/modules/Services.jsm"); var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/guidancePanel.js", this);
var Zotero_QuickFormat = new function () { var Zotero_QuickFormat = new function () {
const pixelRe = /^([0-9]+)px$/ const pixelRe = /^([0-9]+)px$/
@ -686,7 +687,7 @@ var Zotero_QuickFormat = new function () {
_buildItemDescription(item, infoNode); _buildItemDescription(item, infoNode);
// add to rich list item // add to rich list item
var rll = document.createElement("richlistitem"); var rll = document.createXULElement("richlistitem");
rll.setAttribute("orient", "vertical"); rll.setAttribute("orient", "vertical");
rll.setAttribute("class", "citation-dialog item"); rll.setAttribute("class", "citation-dialog item");
rll.setAttribute("zotero-item", item.cslItemID ? item.cslItemID : item.id); rll.setAttribute("zotero-item", item.cslItemID ? item.cslItemID : item.id);
@ -708,7 +709,7 @@ var Zotero_QuickFormat = new function () {
titleNode.setAttribute("value", labelText); titleNode.setAttribute("value", labelText);
// add to rich list item // add to rich list item
var rll = document.createElement("richlistitem"); var rll = document.createXULElement("richlistitem");
rll.setAttribute("orient", "vertical"); rll.setAttribute("orient", "vertical");
rll.setAttribute("disabled", true); rll.setAttribute("disabled", true);
rll.setAttribute("class", loading ? "citation-dialog loading" : "citation-dialog separator"); rll.setAttribute("class", loading ? "citation-dialog loading" : "citation-dialog separator");
@ -947,7 +948,7 @@ var Zotero_QuickFormat = new function () {
} }
if(!panelFrameHeight) { if(!panelFrameHeight) {
panelFrameHeight = referencePanel.boxObject.height - referencePanel.clientHeight; panelFrameHeight = referencePanel.getBoundingClientRect().height - referencePanel.clientHeight;
var computedStyle = window.getComputedStyle(referenceBox, null); var computedStyle = window.getComputedStyle(referenceBox, null);
for(var attr of ["border-top-width", "border-bottom-width"]) { for(var attr of ["border-top-width", "border-bottom-width"]) {
var val = computedStyle.getPropertyValue(attr); var val = computedStyle.getPropertyValue(attr);
@ -1124,11 +1125,10 @@ var Zotero_QuickFormat = new function () {
* Called when progress changes * Called when progress changes
*/ */
function _onProgress(percent) { function _onProgress(percent) {
var meter = document.querySelector(".citation-dialog .progress-meter"); var meter = document.querySelector(".citation-dialog.progress-meter");
if(percent === null) { if(percent === null) {
meter.mode = "undetermined"; meter.removeAttribute('value');
} else { } else {
meter.mode = "determined";
meter.value = Math.round(percent); meter.value = Math.round(percent);
} }
} }
@ -1204,7 +1204,7 @@ var Zotero_QuickFormat = new function () {
var offset = range.startOffset, var offset = range.startOffset,
childNodes = qfe.childNodes, childNodes = qfe.childNodes,
node = childNodes[offset-(right ? 0 : 1)]; node = childNodes[offset-(right ? 0 : 1)];
if (node && node.dataset.citationItem) return node; if (node && node.dataset && node.dataset.citationItem) return node;
return null; return null;
} }
@ -1507,7 +1507,7 @@ var Zotero_QuickFormat = new function () {
_updateCitationObject(); _updateCitationObject();
var newWindow = window.newWindow = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] var newWindow = window.newWindow = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher) .getService(Components.interfaces.nsIWindowWatcher)
.openWindow(null, 'chrome://zotero/content/integration/addCitationDialog.xul', .openWindow(null, 'chrome://zotero/content/integration/addCitationDialog.xhtml',
'', 'chrome,centerscreen,resizable', io); '', 'chrome,centerscreen,resizable', io);
newWindow.addEventListener("focus", function() { newWindow.addEventListener("focus", function() {
newWindow.removeEventListener("focus", arguments.callee, true); newWindow.removeEventListener("focus", arguments.callee, true);

View file

@ -63,14 +63,22 @@
</menupopup> </menupopup>
</toolbarbutton> </toolbarbutton>
<iframe class="citation-dialog iframe" ondragstart="event.stopPropagation()" src="data:application/xhtml+xml,%3C!DOCTYPE%20html%20PUBLIC%20%22-//W3C//DTD%20XHTML%201.0%20Strict//EN%22%20%22http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd%22%3E%3Chtml%20xmlns=%22http://www.w3.org/1999/xhtml%22%3E%3Chead%3E%3Clink%20rel=%22stylesheet%22%20type=%22text/css%22%20href=%22chrome://zotero/skin/integration.css%22/%3E%3Clink%20rel=%22stylesheet%22%20type=%22text/css%22%20href=%22chrome://zotero-platform/content/integration.css%22/%3E%3C/head%3E%3Cbody%20contenteditable=%22true%22%20spellcheck=%22false%22%20class=%22citation-dialog%20editor%22/%3E%3C/html%3E" <iframe
tabindex="1" flex="1"/> class="citation-dialog iframe"
ondragstart="event.stopPropagation()"
src="citationDialogIframe.html"
tabindex="1"
flex="1"
type="content"
remote="false"
maychangeremoteness="false"/>
<vbox class="citation-dialog spinner" style="visibility: hidden"> <vbox class="citation-dialog spinner" style="visibility: hidden">
<image class="zotero-spinner-16"/> <image class="zotero-spinner-16"/>
</vbox> </vbox>
</hbox> </hbox>
</hbox> </hbox>
<progressmeter class="citation-dialog progress-meter" mode="undetermined" value="0" flex="1"/> <html:progress class="citation-dialog progress-meter" max="100"/>
</deck> </deck>
</box> </box>
<panel class="citation-dialog reference-panel" noautofocus="true" norestorefocus="true" <panel class="citation-dialog reference-panel" noautofocus="true" norestorefocus="true"
@ -84,43 +92,31 @@
<description id="citation-properties-title"/> <description id="citation-properties-title"/>
<hbox id="citation-properties-info"/> <hbox id="citation-properties-info"/>
</vbox> </vbox>
<grid flex="1"> <html:div id="citation-properties-grid">
<columns> <menulist id="locator-label" sizetopopup="none"
<column/> oncommand="Zotero_QuickFormat.onCitationPropertiesChanged(event)" native="true">
<column flex="1"/> <menupopup id="locator-label-popup"/>
</columns> </menulist>
<rows> <html:input type="text" id="locator"
<row align="center"> oninput="window.setTimeout(function(event) { Zotero_QuickFormat.onCitationPropertiesChanged(event) }, 0)"/>
<menulist id="locator-label" sizetopopup="none" <label value="&zotero.citation.prefix.label;"/>
oncommand="Zotero_QuickFormat.onCitationPropertiesChanged(event)"> <html:input type="text" class="citation-textbox" id="prefix" flex="1"
<menupopup id="locator-label-popup"/> oninput="window.setTimeout(function(event) { Zotero_QuickFormat.onCitationPropertiesChanged(event) }, 0)"/>
</menulist> <label value="&zotero.citation.suffix.label;"/>
<textbox id="locator" flex="1" <html:input type="text" class="citation-textbox" id="suffix" flex="1"
oninput="window.setTimeout(function(event) { Zotero_QuickFormat.onCitationPropertiesChanged(event) }, 0)"/> oninput="window.setTimeout(function(event) { Zotero_QuickFormat.onCitationPropertiesChanged(event) }, 0)"/>
</row> <html:div>
<row align="center"> <html:input type="checkbox" id="suppress-author" native="true"
<label value="&zotero.citation.prefix.label;"/> onchange="Zotero_QuickFormat.onCitationPropertiesChanged(event)"/>
<textbox class="citation-textbox" id="prefix" flex="1" <html:label for="suppress-author">
oninput="window.setTimeout(function(event) { Zotero_QuickFormat.onCitationPropertiesChanged(event) }, 0)"/> &zotero.citation.suppressAuthor.label;
</row> </html:label>
<row align="center"> </html:div>
<label value="&zotero.citation.suffix.label;"/> </html:div>
<textbox class="citation-textbox" id="suffix" flex="1"
oninput="window.setTimeout(function(event) { Zotero_QuickFormat.onCitationPropertiesChanged(event) }, 0)"/>
</row>
<html:div>
<html:input type="checkbox" id="suppress-author"
onchange="Zotero_QuickFormat.onCitationPropertiesChanged(event)"/>
<html:label for="suppress-author">
&zotero.citation.suppressAuthor.label;
</html:label>
</html:div>
</rows>
</grid>
<vbox flex="1" align="center"> <vbox flex="1" align="center">
<button id="citation-properties-library-link" onclick="Zotero_QuickFormat.showInLibrary()"/> <button id="citation-properties-library-link" onclick="Zotero_QuickFormat.showInLibrary()"/>
</vbox> </vbox>
</panel> </panel>
<guidance-panel class="citation-dialog guidance" about="quickFormat" <guidance-panel class="citation-dialog guidance" about="quickFormat"
for="zotero-icon" x="26"/> <!-- fx-compat TODO: pull in chrome://zotero/content/elements/guidancePanel.js for this --> for="zotero-icon" x="26"/>
</window> </window>

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<!--
***** BEGIN LICENSE BLOCK *****
Copyright © 2022 Center for History and New Media
George Mason University, Fairfax, Virginia, USA
http://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 *****
-->
<html xmlns="http://www.w3.org/1999/xhtml" style="height: 100%">
<head>
<link rel="stylesheet" type="text/css" href="chrome://zotero/skin/integration.css"/>
<link rel="stylesheet" type="text/css" href="chrome://zotero-platform/content/integration.css"/>
</head>
<body style="margin: 0; height: 100%">
<div id="simple-editor" class="zotero-simpleEditor"></div>
<script type="text/javascript" src="simpleEditor.js"></script>
</body>
</html>

View file

@ -0,0 +1,581 @@
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2022 Corporation for Digital Scholarship
Vienna, Virginia, USA
http://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/>.
*****************************
Based on https://github.com/jaredreich/pell/blob/master/src/pell.js,
which is covered by the following copyright and permission notice:
The MIT License (MIT)
Copyright (c) Jared Reich
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
***** END LICENSE BLOCK *****
*/
// Simple WYSIWYG editor using contenteditable
(function() {
var Zotero = Components.classes['@zotero.org/Zotero;1']
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
const defaultParagraphSeparatorString = 'defaultParagraphSeparator'
const formatBlock = 'formatBlock'
const addEventListener = (parent, type, listener) => parent.addEventListener(type, listener)
const appendChild = (parent, child) => parent.appendChild(child)
const createElement = tag => document.createElement(tag)
const queryCommandState = command => document.queryCommandState(command)
const queryCommandValue = command => document.queryCommandValue(command)
const exec = (command, value = null) => document.execCommand(command, false, value)
const defaultActions = {
bold: {
icon: '<b>B</b>',
title: 'Bold',
state: () => queryCommandState('bold'),
result: () => exec('bold')
},
italic: {
icon: '<i>I</i>',
title: 'Italic',
state: () => queryCommandState('italic'),
result: () => exec('italic')
},
underline: {
icon: '<u>U</u>',
title: 'Underline',
state: () => queryCommandState('underline'),
result: () => exec('underline')
},
strikethrough: {
icon: '<strike>S</strike>',
title: 'Strike-through',
state: () => queryCommandState('strikeThrough'),
result: () => exec('strikeThrough')
},
heading1: {
icon: '<b>H<sub>1</sub></b>',
title: 'Heading 1',
result: () => exec(formatBlock, '<h1>')
},
heading2: {
icon: '<b>H<sub>2</sub></b>',
title: 'Heading 2',
result: () => exec(formatBlock, '<h2>')
},
paragraph: {
icon: '&#182;',
title: 'Paragraph',
result: () => exec(formatBlock, '<p>')
},
quote: {
icon: '&#8220; &#8221;',
title: 'Quote',
result: () => exec(formatBlock, '<blockquote>')
},
olist: {
icon: '&#35;',
title: 'Ordered List',
result: () => exec('insertOrderedList')
},
ulist: {
icon: '&#8226;',
title: 'Unordered List',
result: () => exec('insertUnorderedList')
},
code: {
icon: '&lt;/&gt;',
title: 'Code',
result: () => exec(formatBlock, '<pre>')
},
line: {
icon: '&#8213;',
title: 'Horizontal Line',
result: () => exec('insertHorizontalRule')
},
link: {
icon: '&#128279;',
title: 'Link',
result: () => {
const url = window.prompt('Enter the link URL')
if (url) exec('createLink', url)
}
},
image: {
icon: '&#128247;',
title: 'Image',
result: () => {
const url = window.prompt('Enter the image URL')
if (url) exec('insertImage', url)
}
}
}
const defaultClasses = {
actionbar: 'zotero-simpleEditor-actionbar',
button: 'zotero-simpleEditor-button',
content: 'zotero-simpleEditor-content',
selected: 'zotero-simpleEditor-button-selected'
}
/**
* @param settings
* settings.actions {Array} - array of action names or objects
* settings.element {HTMLElement} - element to which attach the editor
* settings.onChange {Function} - change handler
* settings.classes {Object} - default classes overrides
* settings.defaultParagraphSeparator {String} - ["div"] element name for paragraph separator
*/
const init = settings => {
const actions = settings.actions
? (
settings.actions.map(action => {
if (typeof action === 'string') return defaultActions[action]
else if (defaultActions[action.name]) return { ...defaultActions[action.name], ...action }
return action
})
)
: Object.keys(defaultActions).map(action => defaultActions[action])
const classes = { ...defaultClasses, ...settings.classes }
const defaultParagraphSeparator = settings[defaultParagraphSeparatorString] || 'div'
const actionbar = createElement('div')
actionbar.className = classes.actionbar
appendChild(settings.element, actionbar)
const content = settings.element.content = createElement('div')
content.contentEditable = true
content.className = classes.content
content.oninput = ({ target: { firstChild } }) => {
if (firstChild && firstChild.nodeType === 3) exec(formatBlock, `<${defaultParagraphSeparator}>`)
else if (content.innerHTML === '<br>') content.innerHTML = ''
settings.onChange && settings.onChange(content.innerHTML)
}
content.onkeydown = event => {
if (event.key === 'Enter' && queryCommandValue(formatBlock) === 'blockquote') {
setTimeout(() => exec(formatBlock, `<${defaultParagraphSeparator}>`), 0)
}
}
appendChild(settings.element, content)
actions.forEach(action => {
const button = createElement('button')
button.className = classes.button
button.innerHTML = action.icon
button.title = action.title
button.setAttribute('type', 'button')
button.onclick = () => action.result() && content.focus()
if (action.state) {
const handler = () => button.classList[action.state() ? 'add' : 'remove'](classes.selected)
addEventListener(content, 'keyup', handler)
addEventListener(content, 'mouseup', handler)
addEventListener(button, 'click', handler)
}
appendChild(actionbar, button)
})
if (settings.styleWithCSS) exec('styleWithCSS')
exec(defaultParagraphSeparatorString, defaultParagraphSeparator)
return settings.element
}
var RTFConverter = new function() {
// Atomic units, HTML -> RTF (cleanup)
//[/<\/p>(?!\s*$)/g, "\\par{}"],
//[/ /g, "&nbsp;"],
//[/\u00A0/g, " "],
this._htmlRTFmap = [
[/<br \/>/g, "\x0B"],
[/<span class=\"tab\">&nbsp;<\/span>/g, "\\tab{}"],
[/&lsquo;/g, ""],
[/&rsquo;/g, ""],
[/&ldquo;/g, "“"],
[/&rdquo;/g, "”"],
[/&nbsp;/g, "\u00A0"],
[/"(\w)/g, "“$1"],
[/([\w,.?!])"/g, "$1”"],
[/<p>/g, ""],
[/<\/?div[^>]*>/g, ""]
];
// Atomic units, RTF -> HTML (cleanup)
this._rtfHTMLmap = [
[/\\uc0\{?\\u([0-9]+)\}?(?:{}| )?/g, function(wholeStr, aCode) { return String.fromCharCode(aCode) }],
[/\\tab(?:\{\}| )/g, '<span class="tab">&nbsp;</span>'],
[/(?:\\par{}|\\\r?\n)/g, "</p><p>"]
];
this.prepare = function() {
// DEBUG: Does this actually happen?
if (this.prepared) return;
// Tag data
var _rexData = [
[
[
["<span +style=\"font-variant: *small-caps;\">"],
["{\\scaps ", "{\\scaps{}"]
],
[
["<\/span>"],
["}"]
]
],
[
[
["<span +style=\"text-decoration: *underline;\">"],
["{\\ul{}", "{\\ul "]
],
[
["<\/span>"],
["}"]
]
],
[
[
["<sup>"],
["\\super ", "\\super{}"]
],
[
["</sup>"],
["\\nosupersub{}", "\\nosupersub "]
]
],
[
[
["<sub>"],
["\\sub ", "\\sub{}"]
],
[
["</sub>"],
["\\nosupersub{}", "\\nosupersub "]
]
],
[
[
["<em>"],
["{\\i{}", "{\\i "]
],
[
["</em>"],
["}"]
]
],
[
[
["<i>"],
["{\\i{}", "{\\i "]
],
[
["</i>"],
["}"]
]
],
[
[
["<b>"],
["{\\b{}", "{\\b "]
],
[
["</b>"],
["}"]
]
],
[
[
["<strong>"],
["{\\b{}", "{\\b "]
],
[
["</strong>"],
["}"]
]
],
[
[
["<span +style=\"font-variant: *normal;\">"],
["{\\scaps0{}", "{\\scaps0 "]
],
[
["</span>"],
["}"]
]
],
[
[
["<span +style=\"font-style: *normal;\">"],
["{\\i0{}", "{\\i0 "]
],
[
["</span>"],
["}"]
]
],
[
[
["<span +style=\"font-weight: *normal;\">"],
["{\\b0{}", "{\\b0 "]
],
[
["</span>"],
["}"]
]
]
];
function longestFirst(a, b) {
if (a.length < b.length) {
return 1;
} else if (a.length > b.length) {
return -1;
} else {
return 0;
}
}
function normalizeRegExpString(str) {
if (!str) return str;
return str.replace(/\s+/g, " ")
.replace(/(?:[\+]|\s[\*])/g, "")
.replace(/[\']/g, '\"')
.replace(/:\s/g, ":");
}
this.normalizeRegExpString = normalizeRegExpString;
function composeRex(rexes, noGlobal) {
var lst = [];
for (var rex in rexes) {
lst.push(rex);
}
lst.sort(longestFirst);
var rexStr = "(?:" + lst.join("|") + ")";
return new RegExp(rexStr, "g");
}
// Create splitting regexps
function splitRexMaker(segment) {
var rexes = {};
for (var i=0,ilen=_rexData.length; i < ilen; i++) {
for (var j=0,jlen=_rexData[i].length; j < jlen; j++) {
for (var k=0,klen=_rexData[i][j][segment].length; k < klen; k++) {
rexes[_rexData[i][j][segment][k].replace("\\", "\\\\")] = true;
}
}
}
var ret = composeRex(rexes, true);
return ret;
}
this.rtfHTMLsplitRex = splitRexMaker(1);
this.htmlRTFsplitRex = splitRexMaker(0);
// Create open-tag sniffing regexp
function openSniffRexMaker(segment) {
var rexes = {};
for (var i=0,ilen=_rexData.length; i < ilen; i++) {
for (var j=0,jlen=_rexData[i][0][segment].length; j < jlen; j++) {
rexes[_rexData[i][0][segment][j].replace("\\", "\\\\")] = true;
}
}
return composeRex(rexes);
}
this.rtfHTMLopenSniffRex = openSniffRexMaker(1);
this.htmlRTFopenSniffRex = openSniffRexMaker(0);
// Create open-tag remapper
function openTagRemapMaker(segment) {
var ret = {};
for (var i=0,ilen=_rexData.length; i < ilen; i++) {
var primaryVal = normalizeRegExpString(_rexData[i][0][segment][0]);
for (var j=0,jlen=_rexData[i][0][segment].length; j < jlen; j++) {
var key = normalizeRegExpString(_rexData[i][0][segment][j]);
ret[key] = primaryVal;
}
}
return ret;
}
this.rtfHTMLopenTagRemap = openTagRemapMaker(1);
this.htmlRTFopenTagRemap = openTagRemapMaker(0);
// Create open-tag-keyed close-tag sniffing regexps
function closeTagRexMaker(segment) {
var ret = {};
var rexes = {};
for (var i=0,ilen=_rexData.length; i < ilen; i++) {
var primaryVal = _rexData[i][0][segment][0];
for (var j=0,jlen=_rexData[i][1][segment].length; j < jlen; j++) {
rexes[_rexData[i][1][segment][j]] = true;
}
ret[primaryVal] = composeRex(rexes);
}
return ret;
}
this.rtfHTMLcloseTagRex = closeTagRexMaker(1);
this.htmlRTFcloseTagRex = closeTagRexMaker(0);
// Create open-tag-keyed open/close tag registry
function tagRegistryMaker(segment) {
var antisegment = 1;
if (segment == 1) {
antisegment = 0;
}
var ret = {};
for (var i=0,ilen=_rexData.length; i < ilen; i++) {
var primaryVal = normalizeRegExpString(_rexData[i][0][segment][0]);
ret[primaryVal] = {
open: normalizeRegExpString(_rexData[i][0][antisegment][0]),
close: _rexData[i][1][antisegment][0]
}
}
return ret;
}
this.rtfHTMLtagRegistry = tagRegistryMaker(1);
this.htmlRTFtagRegistry = tagRegistryMaker(0);
this.prepared = true;
}
this.prepare();
this.getSplit = function(mode, txt) {
if (!txt) return [];
var splt = txt.split(this[mode + "splitRex"]);
var mtch = txt.match(this[mode + "splitRex"]);
var lst = [splt[0]];
for (var i=1,ilen=splt.length; i < ilen; i++) {
lst.push(mtch[i-1]);
lst.push(splt[i]);
}
return lst;
}
this.getOpenTag = function(mode, str) {
var m = str.match(this[mode + "openSniffRex"]);
if (m) {
m = this[mode + "openTagRemap"][this.normalizeRegExpString(m[0])];
}
return m;
}
this.convert = function(mode, txt) {
var lst = this.getSplit(mode, txt);
var sdepth = 0;
var depth = 0;
for (var i=1,ilen=lst.length; i < ilen; i += 2) {
var openTag = this.getOpenTag(mode, lst[i]);
if (openTag) {
sdepth++;
depth = sdepth;
for (var j=(i+2),jlen=lst.length; j < jlen; j += 2) {
var closeTag = !this.getOpenTag(mode, lst[j]);
if (closeTag) {
if (depth === sdepth && lst[j].match(this[mode + "closeTagRex"][openTag])) {
lst[i] = this[mode + "tagRegistry"][openTag].open;
lst[j] = this[mode + "tagRegistry"][openTag].close;
break;
}
depth--;
} else {
depth++;
}
}
} else {
sdepth--;
}
}
return lst.join("");
}
this.htmlToRTF = function(txt) {
txt = this.convert("htmlRTF", txt);
for (var i=0,ilen=this._htmlRTFmap.length; i < ilen; i++) {
var entry = this._htmlRTFmap[i];
txt = txt.replace(entry[0], entry[1]);
}
txt = Zotero.Utilities.unescapeHTML(txt);
txt = txt.replace(/[\x7F-\uFFFF]/g, function(aChar) { return "\\uc0\\u"+aChar.charCodeAt(0).toString()+"{}"});
return txt.trim();
}
this.rtfToHTML = function(txt) {
for (var i=0,ilen=this._rtfHTMLmap.length; i < ilen; i++) {
var entry = this._rtfHTMLmap[i];
txt = txt.replace(entry[0], entry[1]);
}
txt = this.convert("rtfHTML", txt);
return txt.trim();
}
}
init({
element: document.querySelector('#simple-editor'),
actions: ['bold', 'italic', 'underline']
});
var editorContents = document.querySelector('.zotero-simpleEditor-content');
window.editor = {
get element() {
document.querySelector('#simple-editor');
},
setContent(content, isRTF) {
if (isRTF) {
content = RTFConverter.rtfToHTML(content);
}
editorContents.innerHTML = content;
},
getContent(asRTF) {
let content = editorContents.innerHTML;
if (asRTF) {
return RTFConverter.htmlToRTF(content);
}
return content;
},
setEnabled(enabled) {
editorContents.setAttribute('contenteditable', !!enabled);
}
}
})();

View file

@ -76,7 +76,7 @@ WindowDraggingElement.prototype = {
return true; return true;
}, },
isPanel : function() { isPanel : function() {
return this._elem instanceof Components.interfaces.nsIDOMXULElement && return this._elem instanceof XULElement &&
this._elem.localName == "panel"; this._elem.localName == "panel";
}, },
handleEvent: function(aEvent) { handleEvent: function(aEvent) {

View file

@ -35,48 +35,32 @@ var { makeRowRenderer } = VirtualizedTable;
Zotero_Preferences.Cite = { Zotero_Preferences.Cite = {
styles: [], styles: [],
wordPluginIDs: new Set([ wordPluginResourcePaths: {
'zoteroOpenOfficeIntegration@zotero.org', libreOffice: 'zotero-libreoffice-integration',
'zoteroMacWordIntegration@zotero.org', macWord: 'zotero-macword-integration',
'zoteroWinWordIntegration@zotero.org' winWord: 'zotero-winword-integration'
]), },
init: async function () { init: async function () {
Components.utils.import("resource://gre/modules/AddonManager.jsm"); // Init word plugin sections
this.updateWordProcessorInstructions(); let wordPlugins = ['libreOffice'];
await this.refreshStylesList(); if (Zotero.isWindows) {
}, wordPlugins.push('winWord');
/**
* Determines if any word processors are disabled and if so, shows a message in the pref pane
*/
updateWordProcessorInstructions: async function () {
var someDisabled = false;
await new Promise(function(resolve) {
AddonManager.getAllAddons(function(addons) {
for (let addon of addons) {
if (Zotero_Preferences.Cite.wordPluginIDs.has(addon.id) && addon.userDisabled) {
someDisabled = true;
}
}
resolve();
});
});
if (someDisabled) {
document.getElementById("wordProcessors-somePluginsDisabled").hidden = undefined;
} }
}, else if (Zotero.isMac) {
wordPlugins.push('macWord');
enableWordPlugins: function () { }
AddonManager.getAllAddons(function(addons) { await Zotero.Promise.delay();
for (let addon of addons) { for (let wordPlugin of wordPlugins) {
if (Zotero_Preferences.Cite.wordPluginIDs.has(addon.id) && addon.userDisabled) { // This is the weirdest indirect code, but let's not fix what's not broken
addon.userDisabled = false; try {
} var installer = Components.utils.import(`resource://${this.wordPluginResourcePaths[wordPlugin]}/installer.jsm`).Installer;
(new installer(true)).showPreferences(document);
} catch(e) {
Zotero.logError(e);
} }
return Zotero.Utilities.Internal.quit(true); }
}); await this.refreshStylesList();
}, },

View file

@ -71,14 +71,6 @@
<vbox class="main-section" id="wordProcessors"> <vbox class="main-section" id="wordProcessors">
<html:h1>&zotero.preferences.cite.wordProcessors;</html:h1> <html:h1>&zotero.preferences.cite.wordProcessors;</html:h1>
<vbox id="wordProcessors-somePluginsDisabled" hidden="true">
<label style="font-weight: bold; margin-top: 1em; text-align: center">Some word processor plugins are disabled.</label>
<hbox pack="center" style="margin-bottom: 2em">
<button id="wordProcessors-enablePlugins"
label="Enable Plugins and Restart Zotero"
oncommand="Zotero_Preferences.Cite.enableWordPlugins()"/>
</hbox>
</vbox>
<checkbox label="&zotero.preferences.cite.wordProcessors.useClassicAddCitationDialog;" preference="extensions.zotero.integration.useClassicAddCitationDialog" native="true"/> <checkbox label="&zotero.preferences.cite.wordProcessors.useClassicAddCitationDialog;" preference="extensions.zotero.integration.useClassicAddCitationDialog" native="true"/>
</vbox> </vbox>
</vbox> </vbox>

View file

@ -1,14 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
<window id="zotero-progress-meter-window"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
windowtype="alert:alert">
<vbox id="zotero-progress-text-box" flex="1">
<label/>
<progressmeter/>
</vbox>
</window>

View file

@ -0,0 +1,49 @@
<?xml version="1.0"?>
<!--
***** BEGIN LICENSE BLOCK *****
Copyright © 2022 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 *****
-->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://global/skin/browser.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
<window id="zotero-progress"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
title="&zotero.progress.title;"
width="300" height="30"
style="max-height: 20px"
windowtype="alert:alert">
<vbox id="zotero-progress-text-box" flex="1" style="padding: 10px">
<hbox align="stretch">
<label id="progress-label" flex="1"/>
</hbox>
<html:progress id="progress-indicator" max="100"/>
</vbox>
<script>
window.addEventListener("DOMContentLoaded", () => window.sizeToContent())
</script>
</window>

View file

@ -1,15 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
<window id="zotero-progress-window"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
windowtype="alert:alert">
<hbox id="zotero-progress-box">
<vbox id="zotero-progress-text-box" flex="1">
<hbox id="zotero-progress-text-headline" pack="start"/>
</vbox>
</hbox>
</window>

View file

@ -73,6 +73,27 @@ Zotero.Integration = new function() {
this.currentWindow = false; this.currentWindow = false;
this.sessions = {}; this.sessions = {};
var upgradeTemplateNotNowTime = 0; var upgradeTemplateNotNowTime = 0;
/**
* Initialize LibreOffice, Word for Mac and Word for Windows plugin components.
*/
this.init = function () {
let classNames = ["@zotero.org/Zotero/integration/initializer?agent=LibreOffice;1"];
if (Zotero.isMac) {
classNames.push("@zotero.org/Zotero/integration/installer?agent=MacWord;1")
} else if (Zotero.isWindows) {
classNames.push("@zotero.org/Zotero/integration/installer?agent=WinWord;1")
}
for (let className of classNames) {
try {
Components.classes[className]
.getService(Components.interfaces.nsISupports);
}
catch (e) {
Zotero.logError(e);
}
}
}
/** /**
* Begin listening for integration commands on the given pipe * Begin listening for integration commands on the given pipe
@ -1443,15 +1464,15 @@ Zotero.Integration.Session.prototype.cite = async function (field, addNote=false
var mode = (!Zotero.isMac && Zotero.Prefs.get('integration.keepAddCitationDialogRaised') var mode = (!Zotero.isMac && Zotero.Prefs.get('integration.keepAddCitationDialogRaised')
? 'popup' : 'alwaysRaised')+',resizable=false'; ? 'popup' : 'alwaysRaised')+',resizable=false';
if (addNote) { if (addNote) {
Zotero.Integration.displayDialog('chrome://zotero/content/integration/insertNoteDialog.xul', Zotero.Integration.displayDialog('chrome://zotero/content/integration/insertNoteDialog.xhtml',
mode, io); mode, io);
} }
else if (Zotero.Prefs.get("integration.useClassicAddCitationDialog")) { else if (Zotero.Prefs.get("integration.useClassicAddCitationDialog")) {
Zotero.Integration.displayDialog('chrome://zotero/content/integration/addCitationDialog.xul', Zotero.Integration.displayDialog('chrome://zotero/content/integration/addCitationDialog.xhtml',
'alwaysRaised,resizable', io); 'alwaysRaised,resizable', io);
} }
else { else {
Zotero.Integration.displayDialog('chrome://zotero/content/integration/quickFormat.xul', Zotero.Integration.displayDialog('chrome://zotero/content/integration/quickFormat.xhtml',
mode, io); mode, io);
} }
@ -1836,7 +1857,7 @@ Zotero.Integration.Session.prototype.setDocPrefs = async function (showImportExp
// Make sure styles are initialized for new docs // Make sure styles are initialized for new docs
await Zotero.Styles.init(); await Zotero.Styles.init();
await Zotero.Integration.displayDialog('chrome://zotero/content/integration/integrationDocPrefs.xul', '', io); await Zotero.Integration.displayDialog('chrome://zotero/content/integration/integrationDocPrefs.xhtml', '', io);
if (io.exportDocument) { if (io.exportDocument) {
return this.exportDocument(); return this.exportDocument();
@ -2292,20 +2313,23 @@ Zotero.Integration.Session.prototype.promptForRetraction = function (citedItem,
* Edits integration bibliography * Edits integration bibliography
* @param {Zotero.Integration.Bibliography} bibliography * @param {Zotero.Integration.Bibliography} bibliography
*/ */
Zotero.Integration.Session.prototype.editBibliography = Zotero.Promise.coroutine(function *(bibliography) { Zotero.Integration.Session.prototype.editBibliography = async function (bibliography) {
if (!Object.keys(this.citationsByIndex).length) { if (!Object.keys(this.citationsByIndex).length) {
throw new Error('Integration.Session.editBibliography: called without loaded citations'); throw new Error('Integration.Session.editBibliography: called without loaded citations');
} }
yield bibliography.loadItemData(); // Update citeproc with citations in the doc
await this._updateCitations();
await bibliography.loadItemData();
await bibliography.getCiteprocBibliography(this.style);
var bibliographyEditor = new Zotero.Integration.BibliographyEditInterface(bibliography, this.citationsByItemID, this.style); var bibliographyEditor = new Zotero.Integration.BibliographyEditInterface(bibliography, this.citationsByItemID, this.style);
yield Zotero.Integration.displayDialog('chrome://zotero/content/integration/editBibliographyDialog.xul', 'resizable', bibliographyEditor); await Zotero.Integration.displayDialog('chrome://zotero/content/integration/editBibliographyDialog.xhtml', 'resizable', bibliographyEditor);
if (bibliographyEditor.cancelled) throw new Zotero.Exception.UserCancelled("bibliography editing"); if (bibliographyEditor.cancelled) throw new Zotero.Exception.UserCancelled("bibliography editing");
this.bibliographyDataHasChanged = this.bibliographyHasChanged = true; this.bibliographyDataHasChanged = this.bibliographyHasChanged = true;
this.bibliography = bibliographyEditor.bibliography; this.bibliography = bibliographyEditor.bibliography;
}); };
/** /**
* @class Interface for bibliography editor to alter document bibliography * @class Interface for bibliography editor to alter document bibliography
@ -2321,9 +2345,10 @@ Zotero.Integration.BibliographyEditInterface = function(bibliography, citationsB
this._update(); this._update();
} }
Zotero.Integration.BibliographyEditInterface.prototype._update = Zotero.Promise.coroutine(function* () {
Zotero.Integration.BibliographyEditInterface.prototype._update = function () {
this.bib = this.bibliography.getCiteprocBibliography(this.citeproc); this.bib = this.bibliography.getCiteprocBibliography(this.citeproc);
}); };
/** /**
* Reverts the text of an individual bibliography entry * Reverts the text of an individual bibliography entry
@ -2336,12 +2361,12 @@ Zotero.Integration.BibliographyEditInterface.prototype.revert = function(itemID)
/** /**
* Reverts bibliography to condition in which no edits have been made * Reverts bibliography to condition in which no edits have been made
*/ */
Zotero.Integration.BibliographyEditInterface.prototype.revertAll = Zotero.Promise.coroutine(function* () { Zotero.Integration.BibliographyEditInterface.prototype.revertAll = function () {
this.bibliography.customEntryText = {}; this.bibliography.customEntryText = {};
this.bibliography.uncitedItemIDs.clear(); this.bibliography.uncitedItemIDs.clear();
this.bibliography.omittedItemIDs.clear(); this.bibliography.omittedItemIDs.clear();
return this._update(); return this._update();
}); };
/** /**
* Reverts bibliography to condition before BibliographyEditInterface was opened * Reverts bibliography to condition before BibliographyEditInterface was opened
@ -3052,7 +3077,7 @@ Zotero.Integration.Citation = class {
io.addBorder = Zotero.isWin; io.addBorder = Zotero.isWin;
io.singleSelection = true; io.singleSelection = true;
await Zotero.Integration.displayDialog('chrome://zotero/content/selectItemsDialog.xul', 'resizable', io); await Zotero.Integration.displayDialog('chrome://zotero/content/selectItemsDialog.xhtml', 'resizable', io);
if (io.dataOut && io.dataOut.length) { if (io.dataOut && io.dataOut.length) {
return Zotero.Items.get(io.dataOut[0]); return Zotero.Items.get(io.dataOut[0]);
@ -3374,7 +3399,7 @@ Zotero.Integration.Progress = class {
io.isNote = this.isNote; io.isNote = this.isNote;
this.window = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] this.window = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher) .getService(Components.interfaces.nsIWindowWatcher)
.openWindow(null, 'chrome://zotero/content/integration/progressBar.xul', '', options, io); .openWindow(null, 'chrome://zotero/content/integration/progressBar.xhtml', '', options, io);
Zotero.Utilities.Internal.activate(this.window); Zotero.Utilities.Internal.activate(this.window);
} }
async hide(fast=false) { async hide(fast=false) {

View file

@ -594,8 +594,11 @@ Zotero.Styles = new function() {
// Make sure the locale we want to select is in the menulist // Make sure the locale we want to select is in the menulist
if (availableLocales.indexOf(selectLocale) == -1) { if (availableLocales.indexOf(selectLocale) == -1) {
let customLocale = menulist.insertItemAt(0, selectLocale, selectLocale); var menuitem = menulist.ownerDocument.createXULElement('menuitem');
customLocale.setAttributeNS('zotero:', 'customLocale', true); menuitem.setAttribute('label', selectLocale);
menuitem.setAttribute('value', selectLocale);
menuitem.setAttributeNS('zotero:', 'customLocale', true);
menulist.append(menuitem);
} }
return menulist.value = selectLocale; return menulist.value = selectLocale;

View file

@ -2362,8 +2362,7 @@ Zotero.Utilities.Internal.activate = new function() {
* Bring a window to the foreground by interfacing directly with X11 * Bring a window to the foreground by interfacing directly with X11
*/ */
function _X11BringToForeground(win, intervalID) { function _X11BringToForeground(win, intervalID) {
var windowTitle = win.QueryInterface(Ci.nsIInterfaceRequestor) var windowTitle = win.getInterface(Ci.nsIWebNavigation).title;
.getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIBaseWindow).title;
var x11Window = _X11FindWindow(_x11RootWindow, windowTitle); var x11Window = _X11FindWindow(_x11RootWindow, windowTitle);
if(!x11Window) return; if(!x11Window) return;

View file

@ -445,6 +445,8 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
Zotero.debug('Triggering "zotero-loaded" event'); Zotero.debug('Triggering "zotero-loaded" event');
Services.obs.notifyObservers(Zotero, "zotero-loaded", null); Services.obs.notifyObservers(Zotero, "zotero-loaded", null);
Zotero.debug('Initializing Word Processor plugins');
Zotero.Integration.init();
await Zotero.Plugins.init(); await Zotero.Plugins.init();
} }

View file

@ -74,10 +74,6 @@
padding: 0 !important; padding: 0 !important;
} }
#prefix, #suffix {
width: 200px;
}
#tree-locator { #tree-locator {
width: 60px; width: 60px;
} }
@ -91,6 +87,12 @@
max-height: 100px; max-height: 100px;
} }
#item-list richlistitem image {
margin-right: 5px;
height: 16px;
vertical-align: top;
}
.citation-dialog.title { .citation-dialog.title {
margin: 0; margin: 0;
font-weight: bold; font-weight: bold;
@ -144,11 +146,13 @@
height: 9999px; height: 9999px;
} }
body { .citation-dialog.editor {
padding: 0 2px 0 2px; padding: 0 2px 0 2px;
margin: 0; margin: 0;
font: -moz-field; font: -moz-field;
overflow: hidden; overflow: hidden;
outline: none;
line-height: 2em;
} }
.citation-dialog.spinner { .citation-dialog.spinner {
@ -190,6 +194,10 @@ richlistitem[selected="true"] {
-moz-user-focus: ignore; -moz-user-focus: ignore;
} }
.citation-dialog.reference-panel:is(panel, menupopup)::part(content) {
display: contents;
}
.citation-dialog.reference-list { .citation-dialog.reference-list {
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -213,6 +221,10 @@ richlistitem[selected="true"] {
margin: 0; margin: 0;
} }
#citation-properties:is(panel, menupopup)::part(content) {
padding: 10px;
}
#citation-properties #suppress-author { #citation-properties #suppress-author {
-moz-user-focus: normal; -moz-user-focus: normal;
} }
@ -237,6 +249,46 @@ richlistitem[selected="true"] {
margin-bottom: 3px; margin-bottom: 3px;
} }
#citation-properties-grid {
display: grid;
align-items: center;
grid-template-columns: max-content 1fr;
}
.zotero-simpleEditor {
box-sizing: border-box;
font-size: 14px;
height: 100%;
}
.zotero-simpleEditor-content {
box-sizing: border-box;
outline: 0;
overflow-y: auto;
padding: 36px 10px 10px 10px;
}
.zotero-simpleEditor-actionbar {
background-color: #fff;
border-bottom: 1px solid rgba(10, 10, 10, 0.1);
position: fixed;
width: 100%;
}
.zotero-simpleEditor-button {
background-color: transparent;
border: none;
cursor: pointer;
height: 30px;
outline: 0;
width: 30px;
vertical-align: bottom;
}
.zotero-simpleEditor-button-selected {
background-color: #f0f0f0;
}
panel button .button-text { panel button .button-text {
margin: 0 !important; margin: 0 !important;
} }

View file

@ -52,6 +52,11 @@ richlistitem, richlistitem > * {
text-overflow: ellipsis; text-overflow: ellipsis;
} }
richlistcheckbox[selected=true] {
background-color: -moz-cellhighlight;
color: -moz-cellhighlighttext;
}
groupbox > label > h2, groupbox > * > label > h2 { groupbox > label > h2, groupbox > * > label > h2 {
font-size: 14px; font-size: 14px;
margin-top: 1em; margin-top: 1em;

View file

@ -36,7 +36,6 @@ var Zotero = Components.classes["@zotero.org/Zotero;1"]
.wrappedJSObject; .wrappedJSObject;
Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AddonManager.jsm");
var installationInProgress = false; var installationInProgress = false;
var _runningTimers = []; var _runningTimers = [];
@ -63,52 +62,32 @@ var ZoteroPluginInstaller = function(addon, failSilently, force) {
this.prefPaneDoc = null; this.prefPaneDoc = null;
var me = this; this.init();
var extensionIDs = [this._addon.EXTENSION_ID].concat(this._addon.REQUIRED_ADDONS.map(req => req.id));
Zotero.debug("PluginInstaller: fetching addon info");
AddonManager.getAddonsByIDs(extensionIDs, function(addons) {
Zotero.debug("PluginInstaller: addon info fetched");
me._addonInfo = addons[0];
me._addonInfoAvailable();
});
}; };
ZoteroPluginInstaller.prototype = { ZoteroPluginInstaller.prototype = {
_errorDisplayed: false, init: async function() {
if (this._initialized) return;
_addonInfoAvailable: function() { Zotero.debug("PluginInstaller: fetching addon info");
Zotero.debug("PluginInstaller: addon info fetched");
try { try {
this._version = this._addonInfo.version; this._version = (await Zotero.File.getContentsFromURLAsync(this._addon.VERSION_FILE)).trim();
var version = this.prefBranch.getCharPref("version");
try { if (this.force || (Services.vc.compare(version, this._addon.LAST_INSTALLED_FILE_UPDATE) < 0
this._addon.verifyNotCorrupt(this); && !this.prefBranch.getBoolPref("skipInstallation"))) {
} catch(e) {
Zotero.debug("Not installing +this._addon.EXTENSION_STRING+: "+e.toString());
return;
}
var version = this.prefBranch.getCharPref("version");
if(this.force || (
(
Services.vc.compare(version, this._addon.LAST_INSTALLED_FILE_UPDATE) < 0
|| (!Zotero.isStandalone && !this.prefBranch.getBoolPref("installed"))
)
&& !this.prefBranch.getBoolPref("skipInstallation")
)) {
var me = this;
if (installationInProgress) { if (installationInProgress) {
Zotero.debug(`${this._addon.APP} extension installation is already in progress`); Zotero.debug(`${this._addon.APP} extension installation is already in progress`);
return; return;
} }
installationInProgress = true; installationInProgress = true;
if(!this._addon.DISABLE_PROGRESS_WINDOW) { if(!this._addon.DISABLE_PROGRESS_WINDOW) {
this._progressWindow = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] this._progressWindow = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher) .getService(Components.interfaces.nsIWindowWatcher)
.openWindow(null, "chrome://"+this._addon.EXTENSION_DIR+"/content/progress.xul", '', .openWindow(null, "chrome://zotero/content/progressWindow.xhtml", '',
"chrome,resizable=no,close=no,centerscreen", null); "chrome,resizable=no,close=no,centerscreen", null);
this._progressWindow.addEventListener("load", function() { me._firstRunListener() }, false); this._progressWindow.addEventListener("load", () => { this._firstRunListener() }, false);
} else { } else {
this._addon.install(this); this._addon.install(this);
} }
@ -118,24 +97,21 @@ ZoteroPluginInstaller.prototype = {
} finally { } finally {
installationInProgress = false; installationInProgress = false;
} }
this._initialized = true;
}, },
_errorDisplayed: false,
isInstalled: function() { isInstalled: function() {
while(!this._version) Zotero.mainThread.processNextEvent(true);
return this.prefBranch.getBoolPref("installed"); return this.prefBranch.getBoolPref("installed");
}, },
getAddonPath: function(addonID) {
return this._addonInfo.getResourceURI().
QueryInterface(Components.interfaces.nsIFileURL).file;
},
setProgressWindowLabel: function(value) { setProgressWindowLabel: function(value) {
if(this._progressWindow) this._progressWindowLabel.value = value; if (this._progressWindow) this._progressWindowLabel.value = value;
}, },
closeProgressWindow: function(value) { closeProgressWindow: function(value) {
if(this._progressWindow) this._progressWindow.close(); if (this._progressWindow) this._progressWindow.close();
}, },
success: function() { success: function() {

View file

@ -41,3 +41,8 @@
@import "components/collection-tree"; @import "components/collection-tree";
@import "components/virtualized-table"; @import "components/virtualized-table";
@import "components/item-tree"; @import "components/item-tree";
// Elements
// --------------------------------------------------
@import "elements/richlistCheckbox";

View file

@ -0,0 +1,49 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
richlistcheckbox {
display: flex;
line-height: 1.5em;
checkbox {
padding: 0;
margin: 0
}
}
richlistcheckbox[selected="true"] {
background-color: -moz-cellhighlight;
color: -moz-cellhighlighttext;
}
richlistbox:where(:focus) > richlistcheckbox[selected="true"] {
background-color: SelectedItem;
color: SelectedItemText;
}
richlistbox[seltype="multiple"]:focus > richlistcheckbox[current="true"],
richlistbox.theme-listbox:focus > richlistcheckbox[current="true"] {
outline: var(--default-focusring);
outline-color: SelectedItem;
outline-offset: calc(-1 * var(--default-focusring-width));
}
richlistbox[seltype="multiple"]:focus > richlistcheckbox[current="true"][selected="true"],
richlistbox.theme-listbox:focus > richlistcheckbox[current="true"][selected="true"] {
outline-color: #F3D982; /* TODO: find a suitable system color */
}
richlistbox.theme-listbox:not(:focus) > richlistcheckbox[selected="true"] {
background-color: -moz-cellhighlight;
color: -moz-cellhighlighttext;
}
richlistbox.theme-listbox > richlistcheckbox > label {
margin: 0px;
padding-top: 0px;
padding-bottom: 1px;
padding-inline-start: 4px;
padding-inline-end: 0px;
white-space: nowrap;
}