Redesign Document Preferences and Create Bibliography dialogs (#4265)

This commit is contained in:
windingwind 2024-07-01 12:24:35 +08:00 committed by GitHub
parent 2dfb243924
commit c270069639
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 598 additions and 376 deletions

View file

@ -30,18 +30,21 @@
//////////////////////////////////////////////////////////////////////////////
// Class to provide options for bibliography
// Used by rtfScan.xul, integrationDocPrefs.xul, and bibliography.xhtml
// Used by integrationDocPrefs.xhtml and bibliography.xhtml
Components.utils.import("resource://gre/modules/Services.jsm");
var Zotero_File_Interface_Bibliography = new function() {
window.Zotero_File_Interface_Bibliography = new function () {
var _io;
// Only changes when explicitly selected
var lastSelectedStyle,
lastSelectedLocale;
var isDocPrefs = false;
var isRTFScan = false;
var styleConfigurator;
/**
* @type {"bibliography" | "docPrefs"}
*/
var windowType;
/**
* Initialize some variables and prepare event listeners for when chrome is done
@ -49,20 +52,20 @@ var Zotero_File_Interface_Bibliography = new function() {
*
* @param {Object} [args] - Explicit arguments in place of window arguments
*/
this.init = Zotero.Promise.coroutine(function* (args = {}) {
this.init = async function (args = {}) {
window.addEventListener('dialogaccept', () => this.acceptSelection());
window.addEventListener('dialoghelp', () => this.openHelpLink());
// Set font size from pref
// Affects bibliography.xhtml and integrationDocPrefs.xul
// Affects bibliography.xhtml and integrationDocPrefs.xhtml
var bibContainer = document.getElementById("zotero-bibliography-container");
if(bibContainer) {
Zotero.UIProperties.registerRoot(document.getElementById("zotero-bibliography-container"));
if (bibContainer) {
Zotero.UIProperties.registerRoot(bibContainer);
}
if(window.arguments && window.arguments.length) {
if (window.arguments && window.arguments.length) {
_io = window.arguments[0];
if(_io.wrappedJSObject) _io = _io.wrappedJSObject;
if (_io.wrappedJSObject) _io = _io.wrappedJSObject;
}
else if (args) {
_io = args;
@ -70,250 +73,197 @@ var Zotero_File_Interface_Bibliography = new function() {
else {
_io = {};
}
windowType = {
"integration-doc-prefs": "docPrefs",
"bibliography-window": "bibliography"
}[document.querySelector("window").id];
var listbox = document.getElementById("style-listbox");
styleConfigurator = document.querySelector("#style-configurator");
// if no style is requested, get the last style used
if(!_io.style) {
if (!_io.style) {
_io.style = Zotero.Prefs.get("export.lastStyle");
}
// See note in style.js
if (!Zotero.Styles.initialized()) {
// Initialize styles
yield Zotero.Styles.init();
await Zotero.Styles.init();
}
// add styles to list
var styles = Zotero.Styles.getVisible();
var selectIndex = null;
for (let i=0; i < styles.length; i++) {
var itemNode = document.createXULElement("richlistitem");
itemNode.setAttribute("value", styles[i].styleID);
let title = styles[i].title;
// Add acronyms to APA and ASA to avoid confusion
// https://forums.zotero.org/discussion/comment/357135/#Comment_357135
title = title
.replace(/^American Psychological Association/, "American Psychological Association (APA)")
.replace(/^American Sociological Association/, "American Sociological Association (ASA)");
itemNode.append(title);
itemNode.searchLabel = title;
listbox.appendChild(itemNode);
if(styles[i].styleID == _io.style) {
selectIndex = i;
// Wait for CE initialization
let i = 0;
while (!styleConfigurator.initialized && i < 300) {
await Zotero.Promise.delay(10);
i++;
}
// Select supplied style and locale
if (_io.style) {
styleConfigurator.style = _io.style;
if (styleConfigurator.style !== _io.style) {
styleConfigurator.style = styleConfigurator.styles[0];
}
else if (_io.locale) {
styleConfigurator.locale = _io.locale;
}
}
let requestedLocale;
if (selectIndex === null) {
// Requested style not found in list, pre-select first style
selectIndex = 0;
} else {
requestedLocale = _io.locale;
if (_io.supportedNotes?.length < 1) {
styleConfigurator.toggleAttribute("no-multi-notes", true);
}
styleConfigurator.addEventListener("select", event => this.styleChanged(event));
styleConfigurator.toggleAttribute("show-manage-styles", true);
styleConfigurator.addEventListener("manage-styles", this.manageStyles.bind(this));
let style = styles[selectIndex];
lastSelectedLocale = Zotero.Prefs.get("export.lastLocale");
if (requestedLocale && style && !style.locale) {
// pre-select supplied locale
lastSelectedLocale = requestedLocale;
}
// add locales to list
Zotero.Styles.populateLocaleList(document.getElementById("locale-menu"));
// Has to be async to work properly
window.setTimeout(function () {
listbox.ensureIndexIsVisible(selectIndex);
listbox.selectedIndex = selectIndex;
if (listbox.selectedIndex == -1) {
// This can happen in tests if styles aren't loaded
Zotero.debug("No styles to select", 2);
return;
}
Zotero_File_Interface_Bibliography.styleChanged();
}, 0);
// ONLY FOR bibliography.xhtml: export options
if(document.getElementById("save-as-rtf")) {
var settings = Zotero.Prefs.get("export.bibliographySettings");
try {
settings = JSON.parse(settings);
var mode = settings.mode;
var method = settings.method;
}
// If not JSON, assume it's the previous format-as-a-string
catch (e) {
method = settings;
}
if (!mode) mode = "bibliography";
if (!method) method = "save-as-rtf";
// restore saved bibliographic settings
document.getElementById('output-mode-radio').selectedItem =
document.getElementById(mode);
document.getElementById('output-method-radio').selectedItem =
document.getElementById(method);
}
// ONLY FOR integrationDocPrefs.xul: set selected endnotes/footnotes
isDocPrefs = !!document.getElementById("displayAs");
isRTFScan = !document.getElementById("formatUsing");
if (isDocPrefs && !isRTFScan) {
if(_io.useEndnotes && _io.useEndnotes == 1) document.getElementById("displayAs").selectedIndex = 1;
let dialog = document.getElementById("zotero-doc-prefs-dialog");
dialog.setAttribute('title', `${Zotero.clientName} - ${dialog.getAttribute('title')}`);
if (document.getElementById("formatUsing-groupbox")) {
if (["Field", "ReferenceMark"].includes(_io.primaryFieldType)) {
if(_io.fieldType == "Bookmark") document.getElementById("formatUsing").selectedIndex = 1;
var formatOption = (_io.primaryFieldType == "ReferenceMark" ? "referenceMarks" : "fields");
document.getElementById("fields").label =
Zotero.getString("integration."+formatOption+".label");
document.getElementById("fields-caption").textContent =
Zotero.getString("integration."+formatOption+".caption");
document.getElementById("fields-file-format-notice").textContent =
Zotero.getString("integration."+formatOption+".fileFormatNotice");
document.getElementById("bookmarks-file-format-notice").textContent =
Zotero.getString("integration.fields.fileFormatNotice");
} else {
document.getElementById("formatUsing-groupbox").style.display = "none";
_io.fieldType = _io.primaryFieldType;
}
}
if(document.getElementById("automaticJournalAbbreviations-checkbox")) {
if(_io.automaticJournalAbbreviations === undefined) {
_io.automaticJournalAbbreviations = Zotero.Prefs.get("cite.automaticJournalAbbreviations");
}
if(_io.automaticJournalAbbreviations) {
document.getElementById("automaticJournalAbbreviations-checkbox").checked = true;
}
document.getElementById("automaticCitationUpdates-checkbox").checked = !_io.delayCitationUpdates;
}
if (_io.showImportExport) {
document.querySelector('#exportImport').hidden = false;
}
}
this.initBibWindow();
this.initDocPrefsWindow();
setTimeout(() => this.updateWindowSize(), 0);
// set style to false, in case this is cancelled
_io.style = false;
});
this.openHelpLink = function() {
Zotero.launchURL("https://www.zotero.org/support/word_processor_integration");
};
/*
* Called when locale is changed
*/
this.localeChanged = function (selectedValue) {
lastSelectedLocale = selectedValue;
this.initBibWindow = function () {
if (windowType !== "bibliography") return;
var settings = Zotero.Prefs.get("export.bibliographySettings");
try {
settings = JSON.parse(settings);
var mode = settings.mode;
var method = settings.method;
}
// If not JSON, assume it's the previous format-as-a-string
catch (e) {
method = settings;
}
if (!mode) mode = "bibliography";
if (!method) method = "save-as-rtf";
// restore saved bibliographic settings
document.getElementById('output-mode-radio').selectedItem
= document.getElementById(mode);
document.getElementById('output-method-radio').selectedItem
= document.getElementById(method);
this.onBibWindowStyleChange();
};
this.initDocPrefsWindow = function () {
if (windowType !== "docPrefs") return;
this.toggleAdvancedOptions(true);
document.querySelector(".advanced-header").addEventListener("click", () => this.toggleAdvancedOptions());
if (_io.useEndnotes == 1) {
styleConfigurator.displayAs = "endnotes";
}
if (document.getElementById("formatUsing-container")) {
if (["Field", "ReferenceMark"].includes(_io.primaryFieldType)) {
if (_io.fieldType == "Bookmark") document.getElementById("formatUsingBookmarks").checked = true;
document.getElementById("bookmarks-file-format-notice").dataset.l10nArgs = '{"show": "true"}';
}
else {
let formatUsing = document.getElementById("formatUsing-container");
formatUsing.hidden = true;
formatUsing.toggleAttribute("always-hidden", true);
_io.fieldType = _io.primaryFieldType;
}
}
if (document.getElementById("automaticJournalAbbreviations")) {
if (_io.automaticJournalAbbreviations === undefined) {
_io.automaticJournalAbbreviations = Zotero.Prefs.get("cite.automaticJournalAbbreviations");
}
if (_io.automaticJournalAbbreviations) {
document.getElementById("automaticJournalAbbreviations").checked = true;
}
document.getElementById("automaticCitationUpdates-checkbox").checked = !_io.delayCitationUpdates;
}
if (_io.showImportExport) {
document.querySelector('#exportImport').hidden = false;
}
document.querySelector("#exportDocument")?.addEventListener("command", this.exportDocument.bind(this));
this.onDocPrefsWindowStyleChange(Zotero.Styles.get(styleConfigurator.style));
// If any advanced options are checked, expand the advanced options section
let hasCheckedAdvancedOption
= !!Array.from(document.querySelectorAll(".advanced-checkbox"))
.find(elem => elem.checked);
if (hasCheckedAdvancedOption) {
this.toggleAdvancedOptions(false);
}
};
this.openHelpLink = function () {
Zotero.launchURL("https://www.zotero.org/support/word_processor_integration");
};
/*
* Called when style is changed
*/
this.styleChanged = function () {
var selectedItem = document.getElementById("style-listbox").selectedItem;
lastSelectedStyle = selectedItem.getAttribute('value');
var selectedStyleObj = Zotero.Styles.get(lastSelectedStyle);
updateLocaleMenu(selectedStyleObj);
//
// For integrationDocPrefs.xul and rtfScan.xhtml
//
if (isDocPrefs) {
// update status of displayAs box based on style class
var isNote = selectedStyleObj.class == "note";
var multipleNotesSupported = _io.supportedNotes.length > 1;
document.getElementById("displayAs-groupbox").hidden = !isNote || !multipleNotesSupported;
// update status of formatUsing box based on style class
if (document.getElementById("formatUsing")) {
if(isNote) document.getElementById("formatUsing").selectedIndex = 0;
document.getElementById("bookmarks").disabled = isNote;
document.getElementById("bookmarks-caption").disabled = isNote;
}
// update status of displayAs box based on style class
if (document.getElementById("automaticJournalAbbreviations-vbox")) {
document.getElementById("automaticJournalAbbreviations-vbox").hidden =
!selectedStyleObj.usesAbbreviation;
}
this.styleChanged = function (event) {
lastSelectedStyle = styleConfigurator.style;
lastSelectedLocale = styleConfigurator.locale;
let selectedStyleObj = Zotero.Styles.get(lastSelectedStyle);
if (event.detail?.type === "style") {
this.onBibWindowStyleChange(selectedStyleObj);
this.onDocPrefsWindowStyleChange(selectedStyleObj);
}
//
// For bibliography.xhtml
//
// Change label to "Citation" or "Note" depending on style class
if(document.getElementById("citations")) {
let label = "";
if(Zotero.Styles.get(lastSelectedStyle).class == "note") {
label = Zotero.getString('citation.notes');
} else {
label = Zotero.getString('citation.citations');
}
document.getElementById("citations").label = label;
}
window.sizeToContent();
this.updateWindowSize();
};
this.exportDocument = function () {
if (Zotero.Integration.confirmExportDocument()) {
_io.exportDocument = true;
document.querySelector('dialog').acceptDialog();
this.onBibWindowStyleChange = function (style = undefined) {
if (windowType !== "bibliography") return;
if (!style) {
style = Zotero.Styles.get(styleConfigurator.style);
}
}
/*
* Update locale menulist when style is changed
*/
function updateLocaleMenu(selectedStyle) {
Zotero.Styles.updateLocaleList(
document.getElementById("locale-menu"),
selectedStyle,
lastSelectedLocale
);
}
if (!style) return;
let citations = document.getElementById("citations");
// Change label to "Citation" or "Note" depending on style class
citations.dataset.l10nArgs = `{"type": "${style.class}"}`;
};
this.onDocPrefsWindowStyleChange = function (style) {
if (windowType !== "docPrefs") return;
let isNote = style.class == "note";
// update status of formatUsing box based on style class
if (isNote) document.querySelector("#formatUsingBookmarks").checked = false;
let formatUsing = document.querySelector("#formatUsing-container");
if (!formatUsing.hasAttribute("always-hidden")) {
formatUsing.hidden = isNote;
}
let usesAbbreviation = style.usesAbbreviation;
document.querySelector("#automaticJournalAbbreviations-container").hidden = !usesAbbreviation;
let advancedOptions = document.querySelector(".advanced-options");
let hasEnabledOption
= !!Array.from(advancedOptions.querySelector(".advanced-body").childNodes)
.find(elem => !elem.hidden);
advancedOptions.hidden = !hasEnabledOption;
};
this.acceptSelection = function () {
// collect code
_io.style = document.getElementById("style-listbox").value;
_io.style = styleConfigurator.style;
let localeMenu = document.getElementById("locale-menu");
_io.locale = localeMenu.disabled ? undefined : localeMenu.value;
_io.locale = styleConfigurator.locale;
if(document.getElementById("output-method-radio")) {
// collect settings
_io.mode = document.getElementById("output-mode-radio").selectedItem.id;
_io.method = document.getElementById("output-method-radio").selectedItem.id;
// save settings
Zotero.Prefs.set("export.bibliographySettings",
JSON.stringify({ mode: _io.mode, method: _io.method }));
}
this.onBibWindowAccept();
// ONLY FOR integrationDocPrefs.xul:
if(isDocPrefs) {
var automaticJournalAbbreviationsEl = document.getElementById("automaticJournalAbbreviations-checkbox");
_io.automaticJournalAbbreviations = automaticJournalAbbreviationsEl.checked;
if(!automaticJournalAbbreviationsEl.hidden && lastSelectedStyle) {
Zotero.Prefs.set("cite.automaticJournalAbbreviations", _io.automaticJournalAbbreviations);
}
_io.useEndnotes = document.getElementById("displayAs").selectedIndex;
_io.fieldType = (document.getElementById("formatUsing").selectedIndex == 0 ? _io.primaryFieldType : _io.secondaryFieldType);
_io.delayCitationUpdates = !document.getElementById("automaticCitationUpdates-checkbox").checked;
}
this.onDocPrefsWindowAccept();
// remember style and locale if user selected these explicitly
if(lastSelectedStyle) {
if (lastSelectedStyle) {
Zotero.Prefs.set("export.lastStyle", _io.style);
}
@ -321,6 +271,28 @@ var Zotero_File_Interface_Bibliography = new function() {
Zotero.Prefs.set("export.lastLocale", lastSelectedLocale);
}
};
this.onBibWindowAccept = function () {
if (windowType !== "bibliography") return;
// collect settings
_io.mode = document.getElementById("output-mode-radio").selectedItem.id;
_io.method = document.getElementById("output-method-radio").selectedItem.id;
// save settings
Zotero.Prefs.set("export.bibliographySettings",
JSON.stringify({ mode: _io.mode, method: _io.method }));
};
this.onDocPrefsWindowAccept = function () {
if (windowType !== "docPrefs") return;
var automaticJournalAbbreviationsEl = document.getElementById("automaticJournalAbbreviations");
_io.automaticJournalAbbreviations = automaticJournalAbbreviationsEl.checked;
if (!automaticJournalAbbreviationsEl.hidden && lastSelectedStyle) {
Zotero.Prefs.set("cite.automaticJournalAbbreviations", _io.automaticJournalAbbreviations);
}
_io.useEndnotes = styleConfigurator.displayAs == "endnotes" ? 1 : 0;
_io.fieldType = (document.getElementById("formatUsingBookmarks").checked ? _io.secondaryFieldType : _io.primaryFieldType);
_io.delayCitationUpdates = !document.getElementById("automaticCitationUpdates-checkbox").checked;
};
this.manageStyles = function () {
@ -329,8 +301,60 @@ var Zotero_File_Interface_Bibliography = new function() {
var win = Zotero.Utilities.Internal.openPreferences('zotero-prefpane-cite', {
scrollTo: '#styles'
});
if (isDocPrefs) {
if (window.isDocPrefs) {
Zotero.Utilities.Internal.activate(win);
}
};
}
this.updateWindowSize = function () {
this.resizeWindow();
// Keep in sync with _styleConfigurator.scss
const defaultListMaxHeight = 260;
const listMaxHeightProp = "--style-configurator-richlistitem-max-height";
let currentListMaxHeight = parseFloat(document.documentElement.style.getPropertyValue(listMaxHeightProp));
let overflow = window.outerHeight - window.screen.availHeight;
if (overflow > 0) {
let styleList = document.querySelector("#style-list");
let currentHeight = styleList.clientHeight;
let newHeight = Math.max(currentHeight - overflow, 100);
document.documentElement.style.setProperty(listMaxHeightProp, `${newHeight}px`);
this.resizeWindow();
}
else if (!isNaN(currentListMaxHeight) && currentListMaxHeight < defaultListMaxHeight) {
let newHeight = Math.min(defaultListMaxHeight, currentListMaxHeight + Math.abs(overflow));
document.documentElement.style.setProperty(listMaxHeightProp, `${newHeight}px`);
this.resizeWindow();
}
};
this.resizeWindow = function () {
document.documentElement.style.removeProperty("min-height");
window.sizeToContent();
document.documentElement.style.minHeight = document.documentElement.clientHeight + "px";
};
/**
* Toggle advanced options
* only called from docPrefs
*/
this.toggleAdvancedOptions = function (collapsed = undefined) {
let header = document.querySelector(".advanced-header");
if (typeof collapsed === "undefined") {
collapsed = !header.classList.contains("collapsed");
}
document.querySelector(".advanced-body").hidden = collapsed;
header.classList.toggle("collapsed", collapsed);
this.updateWindowSize();
};
/**
* Export the document
* only called from docPrefs
*/
this.exportDocument = function () {
if (Zotero.Integration.confirmExportDocument()) {
_io.exportDocument = true;
document.querySelector('dialog').acceptDialog();
}
};
};

View file

@ -10,46 +10,39 @@
persist="screenX screenY width height sizemode"
id="bibliography-window"
class="bibliography-window"
title="&zotero.bibliography.title;"
data-l10n-id="bibliography-window"
drawintitlebar-platforms="mac"
onload="Zotero_File_Interface_Bibliography.init()">
<dialog
buttons="cancel,accept"
class="zotero-dialog-window"
id="zotero-bibliography">
<script src="include.js"/>
<script src="titlebar.js"/>
<script src="bibliography.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/titlebar.js", this);
Services.scriptloader.loadSubScript("chrome://zotero/content/customElements.js", this);
Services.scriptloader.loadSubScript('chrome://zotero/content/elements/styleConfigurator.js', this);
Services.scriptloader.loadSubScript("chrome://zotero/content/bibliography.js", this);
</script>
<html:link rel="localization" href="zotero.ftl"/>
<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()"/>
<hbox pack="end">
<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>
<label><html:h2>&zotero.bibliography.outputMode;</html:h2></label>
<style-configurator id="style-configurator" />
<groupbox class="radio-row">
<html:label data-l10n-id="bibliography-outputMode-label"></html:label>
<radiogroup id="output-mode-radio">
<radio id="citations"/>
<radio id="bibliography" label="&zotero.bibliography.bibliography;"/>
<radio id="citations" data-l10n-id="bibliography-outputMode-citations"/>
<radio id="bibliography" data-l10n-id="bibliography-outputMode-bibliography"/>
</radiogroup>
</groupbox>
<groupbox>
<label><html:h2>&zotero.bibliography.outputMethod;</html:h2></label>
<groupbox class="radio-col">
<html:label data-l10n-id="bibliography-outputMethod-label"></html:label>
<radiogroup id="output-method-radio">
<radio id="save-as-rtf" label="&zotero.bibliography.saveAsRTF.label;"/>
<radio id="save-as-html" label="&zotero.bibliography.saveAsHTML.label;"/>
<radio id="copy-to-clipboard" label="&zotero.bibliography.copyToClipboard.label;"/>
<radio id="print" label="&zotero.bibliography.print.label;"/>
<radio id="save-as-rtf" data-l10n-id="bibliography-outputMethod-saveAsRTF"/>
<radio id="save-as-html" data-l10n-id="bibliography-outputMethod-saveAsHTML"/>
<radio id="copy-to-clipboard" data-l10n-id="bibliography-outputMethod-copyToClipboard"/>
<radio id="print" data-l10n-id="bibliography-outputMethod-print"/>
</radiogroup>
</groupbox>
</vbox>

View file

@ -192,10 +192,16 @@ Services.scriptloader.loadSubScript('chrome://zotero/content/elements/itemPaneSe
element: "dialog",
// The `attachShadow` are cleared in <dialog>, we need to monkey-patch after `connectedCallback`.
patchedFunction: "connectedCallback",
filename: "wizard-dialog"
}
],
mac: [],
mac: [
"wizard",
{
element: "dialog",
// The `attachShadow` are cleared in <dialog>, we need to monkey-patch after `connectedCallback`.
patchedFunction: "connectedCallback",
}
],
linux: [],
};
for (let [key, configs] of Object.entries(InjectCSSConfig)) {

View file

@ -23,8 +23,6 @@
***** END LICENSE BLOCK *****
*/
/* global XULElementBase: false */
{
class StyleSelector extends XULElementBase {
content = MozXULElement.parseXULToFragment(`
@ -33,19 +31,26 @@
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
>
<div>
<xul:richlistbox id="style-list" tabindex="0" />
<xul:richlistbox id="style-list" class="theme-listbox" tabindex="0" />
</div>
</div>
`);
set value(val) {
this.querySelector('#style-list').value = val;
if (!this.values.includes(val)) return;
let styleList = this.querySelector('#style-list');
styleList.value = val;
this._scrollToSelected();
}
get value() {
return this.querySelector('#style-list').value;
}
get values() {
return Array.from(this.querySelectorAll('#style-list richlistitem')).map(elem => elem.value);
}
async init() {
await Zotero.Styles.init();
const styleListEl = this.querySelector('#style-list');
@ -69,6 +74,16 @@
this.dispatchEvent(event);
});
}
_scrollToSelected() {
let list = this.querySelector('#style-list');
let containerRect = list.getBoundingClientRect();
let rowRect = list.selectedItem.getBoundingClientRect();
let topDistance = rowRect.top - containerRect.top;
let bottomDistance = containerRect.bottom - rowRect.bottom;
let toScroll = (topDistance - bottomDistance) / 2;
list.scrollTo({ top: list.scrollTop + toScroll });
}
}
class LocaleSelector extends XULElementBase {
@ -86,6 +101,7 @@
`);
get value() {
if (this.localeListEl.disabled) return undefined;
return this.localeListEl.value;
}
@ -154,9 +170,12 @@
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
>
<label for="style-selector" data-l10n-id="bibliography-style-label" />
<div class="style-selector-wrapper">
<xul:style-selector id="style-selector" value="${this.getAttribute('style') || Zotero.Prefs.get('export.lastStyle') || ''}" />
<div class="style-list-container">
<label for="style-selector" data-l10n-id="bibliography-style-label" />
<div class="style-selector-wrapper">
<xul:style-selector id="style-selector" value="${this.getAttribute('style') || Zotero.Prefs.get('export.lastStyle') || ''}" />
</div>
<label id="manage-styles" class="text-link" data-l10n-id="bibliography-manageStyles-label"></label>
</div>
<div class="locale-selector-wrapper">
<label for="locale-selector" class="locale-selector-label" data-l10n-id="bibliography-locale-label" />
@ -167,6 +186,7 @@
/>
</div>
<div class="display-as-wrapper">
<label for="style-selector" data-l10n-id="bibliography-displayAs-label" />
<xul:radiogroup id="display-as">
<xul:radio value="footnotes" data-l10n-id="integration-prefs-footnotes" selected="true" />
<xul:radio value="endnotes" data-l10n-id="integration-prefs-endnotes" />
@ -184,6 +204,10 @@
return this.querySelector('#style-selector').value;
}
get styles() {
return this.querySelector('#style-selector').values;
}
set locale(val) {
this.querySelector('#locale-selector').value = val;
}
@ -207,20 +231,40 @@
this.querySelector('#style-selector').addEventListener('select', (_event) => {
this.handleStyleChanged(_event.target.value);
const event = document.createEvent("Events");
event.initEvent("select", true, true);
this.dispatchEvent(event);
const event = new CustomEvent("select", {
detail: {
type: "style",
},
bubbles: true,
cancelable: true
});
this.dispatchEvent(event,);
});
this.querySelector('#locale-selector').addEventListener('select', (_event) => {
const event = document.createEvent("Events");
event.initEvent("select", true, true);
const event = new CustomEvent("select", {
detail: {
type: "locale",
},
bubbles: true,
cancelable: true
});
this.dispatchEvent(event);
});
this.querySelector('#display-as').addEventListener('select', (_event) => {
const event = document.createEvent("Events");
event.initEvent("select", true, true);
const event = new CustomEvent("select", {
detail: {
type: "displayAs",
},
bubbles: true,
cancelable: true
});
this.dispatchEvent(event);
});
this.querySelector('#manage-styles').addEventListener('click', (_e) => {
const event = new CustomEvent("manage-styles");
this.dispatchEvent(event);
});
}
@ -229,7 +273,9 @@
this.querySelector('#locale-selector').style = style;
const styleData = style ? Zotero.Styles.get(style) : null;
const isNoteStyle = (styleData || {}).class === 'note';
this.querySelector('.display-as-wrapper').style.display = isNoteStyle ? '' : 'none';
const noMultipleNotes = this.hasAttribute('no-multi-notes');
this.querySelector('.display-as-wrapper').style.display
= (isNoteStyle && !noMultipleNotes) ? '' : 'none';
}
}

View file

@ -34,72 +34,53 @@
id="integration-doc-prefs"
class="bibliography-window"
persist="screenX screenY width height sizemode"
title="&zotero.integration.docPrefs.title;"
data-l10n-id="integration-docPrefs-window"
onload="Zotero_File_Interface_Bibliography.init();"
>
<dialog
id="zotero-doc-prefs-dialog"
class="zotero-dialog-window"
orient="vertical"
buttons="accept,cancel,help"
ondialogaccept="Zotero_File_Interface_Bibliography.acceptSelection();"
ondialoghelp="Zotero_File_Interface_Bibliography.openHelpLink();"
onclose="document.documentElement.cancelDialog(); event.preventDefault(); event.stopPropagation();">
<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()"/>
<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>
<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/customElements.js", this);
Services.scriptloader.loadSubScript('chrome://zotero/content/elements/styleConfigurator.js', this);
Services.scriptloader.loadSubScript("chrome://zotero/content/bibliography.js", this);
</script>
<html:link rel="localization" href="zotero.ftl"/>
<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 id="zotero-bibliography-container">
<style-configurator id="style-configurator" />
<vbox id="automaticCitationUpdates-vbox">
<checkbox id="automaticCitationUpdates-checkbox" data-l10n-id="integration-prefs-automaticCitationUpdates" native="true"/>
<description class="row-description" data-l10n-id="integration-prefs-automaticCitationUpdates-description"></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 id="exportImport" hidden="true">
<button id="exportDocument" data-l10n-id="integration-prefs-exportDocument" />
</hbox>
<vbox class="advanced-options">
<hbox class="advanced-header">
<html:span class="advanced-header-icon"></html:span>
<html:div data-l10n-id="bibliography-advancedOptions-label"></html:div>
</hbox>
<vbox class="advanced-body">
<vbox class="advanced-row" id="formatUsing-container">
<checkbox id="formatUsingBookmarks" class="advanced-checkbox" data-l10n-id="integration-prefs-bookmarks" native="true"/>
<label class="row-description" id="bookmarks-caption" data-l10n-id="integration-prefs-bookmarks-description"></label>
<label class="row-description" id="bookmarks-file-format-notice" data-l10n-id="integration-prefs-bookmarks-formatNotice"/>
</vbox>
<vbox class="advanced-row" id="automaticJournalAbbreviations-container">
<checkbox id="automaticJournalAbbreviations" class="advanced-checkbox" data-l10n-id="integration-prefs-automaticJournalAbbeviations" native="true"/>
<description class="row-description" data-l10n-id="integration-prefs-automaticJournalAbbeviations-description"></description>
</vbox>
</vbox>
</vbox>
</vbox>
</dialog>
</window>

View file

@ -14,6 +14,7 @@
onload="Zotero_Long_Tag_Fixer.init()">
<dialog
id="zotero-long-tag-fixer"
class="zotero-dialog-window"
buttons="cancel,accept"
>
<html:div id="intro">

View file

@ -21,7 +21,7 @@
Services.scriptloader.loadSubScript("chrome://zotero/content/customElements.js", this);
</script>
<wizard id="rtfscan-wizard" class="rtfscan-wizard" data-l10n-id="rtfScan-wizard">
<wizard id="rtfscan-wizard" class="rtfscan-wizard zotero-dialog-window" data-l10n-id="rtfScan-wizard">
<wizardpage pageid="page-start" data-l10n-id="rtfScan-intro-page">
<div>
<span class="page-start-1" data-l10n-id="rtfScan-introPage-description" />

View file

@ -269,14 +269,65 @@ runJS-result = {
}
runJS-run-async = Run as async function
bibliography-window =
.title = { -app-name } - Create Citation/Bibliography
bibliography-style-label = Citation Style:
bibliography-locale-label = Language:
bibliography-displayAs-label = Display citations as:
bibliography-advancedOptions-label = Advanced Options
bibliography-outputMode-label = Output Mode:
bibliography-outputMode-citations =
.label = {
$type ->
[citation] Citations
[note] Notes
*[other] Citations
}
bibliography-outputMode-bibliography =
.label = Bibliography
bibliography-outputMethod-label = Output Method:
bibliography-outputMethod-saveAsRTF =
.label = Save as RTF
bibliography-outputMethod-saveAsHTML =
.label = Save as HTML
bibliography-outputMethod-copyToClipboard =
.label = Copy to Clipboard
bibliography-outputMethod-print =
.label = Print
bibliography-manageStyles-label = Manage Styles…
integration-docPrefs-window =
.title = { -app-name } - Document Preferences
integration-addEditCitation-window =
.title = { -app-name } - Add/Edit Citation
integration-editBibliography-window =
.title = { -app-name } - Edit Bibliography
integration-quickFormatDialog-window =
.title = { -app-name } - Quick Format Citation
integration-prefs-displayAs-label = Display Citations As:
integration-prefs-footnotes =
.label = Footnotes
integration-prefs-endnotes =
.label = Endnotes
integration-prefs-bookmarks =
.label = Store citation as bookmarks
integration-prefs-bookmarks-description = Bookmarks can be shared between Word and LibreOffice, but may cause errors if accidentally modified and cannot be inserted into footnotes.
integration-prefs-bookmarks-formatNotice = {
$show ->
[true] The document must be saved as .doc or .docx.
*[other] {""}
}
integration-prefs-automaticCitationUpdates =
.label = Automatically update citations
.tooltip = Citations with pending updates will be highlighted in the document
integration-prefs-automaticCitationUpdates-description = Disabling updates can speed up citation insertion in large documents. Click Refresh to update citations manually.
integration-prefs-automaticJournalAbbeviations =
.label = Use MEDLINE journal abbreviations
integration-prefs-automaticJournalAbbeviations-description = The “Journal Abbr” field will be ignored.
integration-prefs-exportDocument =
.label = Switch to a Different Word Processor…
publications-intro-page =

View file

@ -1,43 +0,0 @@
.bibliography-window
{
min-width: 400pt;
}
dialog
{
max-width: 100vw;
}
#style-listbox
{
height: 14rem;
}
#manage-styles {
text-decoration: none;
}
#locale-box h2 {
font-size: 14px;
margin-block: 0;
}
radio:not(:first-child)
{
margin-top: .5em;
}
.radioDescription
{
margin: 0 0 3px 20px;
font-size: .85em;
}
#automaticJournalAbbreviations-vbox, #advanced-settings {
padding: 0 14px;
}
#advanced-settings > * {
margin-bottom: 10px;
}

120
scss/bibliography.scss Normal file
View file

@ -0,0 +1,120 @@
@import "abstracts/variables";
@import "abstracts/functions";
@import "abstracts/mixins";
@import "abstracts/placeholders";
@import "abstracts/utilities";
@import "abstracts/split-button";
@import "abstracts/svgicon";
@import "themes/light";
@import "themes/dark";
// Base
// --------------------------------------------------
@import "base/base";
style-configurator {
--style-configurator-gap: 16px;
}
checkbox, radio {
gap: 6px;
margin: 0;
}
checkbox {
.checkbox-check[native] {
margin-inline: 0;
}
}
radio {
.radio-check {
margin-inline: 0;
}
.radio-label-box {
.radio-icon {
display: none;
}
}
}
button {
margin: 0;
}
.bibliography-window
{
min-width: 575px;
}
dialog
{
max-width: 100vw;
}
#zotero-bibliography-container {
gap: 16px;
}
#manage-styles {
text-decoration: none;
}
.row-description
{
padding: 0 0 0 23px;
margin: 0;
font-size: .8em;
color: var(--fill-secondary);
}
.radio-row {
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
radiogroup {
flex-direction: row;
gap: 8px;
}
}
.radio-col {
display: flex;
flex-direction: column;
gap: 8px;
radiogroup {
flex-direction: column;
gap: 8px;
}
}
.advanced-options {
gap: 8px;
.advanced-header {
gap: 8px;
.advanced-header-icon {
width: 8px;
transition: transform .125s ease;
transform: rotate(0deg);
@include svgicon("chevron-8", "universal", "8");
}
&.collapsed .advanced-header-icon {
transform: rotate(-90deg);
}
}
.advanced-body {
padding: 0 0 0 16px;
gap: 8px;
}
}

View file

@ -26,3 +26,10 @@ window:root .zotero-window {
window:root .zotero-dialog {
@include zotero-dialog();
}
// Dialogs (e.g. the integration doc prefs window) has 20px padding on MacOS
window:root dialog.zotero-dialog-window {
@media (-moz-platform: macos) {
padding: 20px;
}
}

View file

@ -8,8 +8,10 @@ style-configurator {
gap: var(--style-configurator-gap, 24px);
}
.locale-selector-label {
margin: var(--style-configurator-locale-selector-label-margin, 0 8px 0 0);
.style-list-container {
display: flex;
flex-direction: column;
gap: 8px;
}
style-selector {
@ -37,10 +39,6 @@ style-configurator {
}
}
label[for="style-selector"] {
margin: var(--style-configurator-label-margin, 0 $space-min 0 0);
}
.style-selector-wrapper {
margin: var(--style-configurator-style-field-margin, 0);
}
@ -48,21 +46,30 @@ style-configurator {
.locale-selector-wrapper {
display: flex;
align-items: center;
gap: var(--style-configurator-locale-gap, 8px);
}
.display-as-wrapper {
display: flex;
flex-direction: row;
gap: var(--style-configurator-display-as-wrapper-gap, 8px);
radiogroup {
margin: 0;
display: flex;
flex-direction: row;
gap: var(--style-configurator-display-as-wrapper-gap, 8px);
}
radio {
margin: 0;
gap: 6px;
}
radio + radio {
margin-left: var(--style-configurator-radio-margin-left, 16px);
}
&:not([show-manage-styles]) {
#manage-styles {
display: none;
}
}
}
@ -70,6 +77,6 @@ style-configurator {
locale-selector {
menulist {
min-width: 200px;
margin: 0;
}
}

View file

@ -0,0 +1,29 @@
// Override/enhance mozilla <dialog> styles on Windows. See customElements.js
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
@import "../abstracts/variables";
@import "../abstracts/functions";
@import "../abstracts/mixins";
@import "../abstracts/placeholders";
@import "../abstracts/utilities";
@import "../abstracts/split-button";
@import "../abstracts/svgicon";
@import "../themes/light";
@import "../themes/dark";
// Base
// --------------------------------------------------
@import "../base/base";
.dialog-button-box {
gap: 8px;
margin-top: 16px;
button {
margin: 0;
}
}