diff --git a/chrome.manifest b/chrome.manifest
index d4c5700ca0..70743e7294 100644
--- a/chrome.manifest
+++ b/chrome.manifest
@@ -7,7 +7,6 @@ content zotero-platform chrome/content/zotero-platform/unix/ os=FreeBSD
content zotero-platform chrome/content/zotero-platform/unix/ os=OpenBSD
content zotero-platform-version chrome/content/zotero-platform/default-version/
-content zotero-platform-version chrome/content/zotero-platform/mac-big-sur/ os=Darwin osversion>=11
resource zotero resource/
diff --git a/chrome/content/zotero-platform/mac-big-sur/style.css b/chrome/content/zotero-platform/mac-big-sur/style.css
deleted file mode 100644
index b7562719d9..0000000000
--- a/chrome/content/zotero-platform/mac-big-sur/style.css
+++ /dev/null
@@ -1,4 +0,0 @@
-/* Quick Format dialog, which is based on window corners, which are different on Big Sur */
-#quick-format-iframe {
- margin-top: 2px;
-}
diff --git a/chrome/content/zotero/integration/addCitationDialog.js b/chrome/content/zotero/integration/addCitationDialog.js
deleted file mode 100644
index 79fa186ab0..0000000000
--- a/chrome/content/zotero/integration/addCitationDialog.js
+++ /dev/null
@@ -1,876 +0,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 .
-
- ***** END LICENSE BLOCK *****
-*/
-
-import { getCSSItemTypeIcon } from 'components/icons';
-
-
-window.isPristine = true;
-
-var Zotero_Citation_Dialog = new function () {
- // Array value [0] is property name.
- // Array value [1] is default value of property.
- var _preserveData = {
- "prefix":["value", ""],
- "suffix":["value", ""],
- "label":["selectedIndex", 0],
- "locator":["value", ""],
- "suppress-author":["checked", false]
- };
-
- var _accepted = false;
- var _itemData = new Object();
- var _multipleSourcesOn = false;
- var _lastSelected = null;
- var _previewShown = false;
- var _suppressNextTreeSelect = false;
- var _suppressNextListSelect = false;
- var _customHTML = false;
- var _locatorIndexArray = {};
- var _locatorNameArray = {};
- var _autoRegeneratePref;
- var _acceptButton;
- var _multipleSourceButton;
- var _sortCheckbox;
- var _citationList;
- var _originalHTML;
- var _editor;
- var serial_number;
- var io;
-
- this.toggleMultipleSources = toggleMultipleSources;
- this.toggleEditor = toggleEditor;
- this.treeItemSelected = treeItemSelected;
- this.listItemSelected = listItemSelected;
- this.up = up;
- this.down = down;
- this.remove = remove;
- this.setSortToggle = setSortToggle;
- this.confirmRegenerate = confirmRegenerate;
- this.accept = accept;
- this.cancel = cancel;
-
- /*
- * initialize add citation dialog
- */
- this.load = Zotero.Promise.coroutine(function* () {
- // make sure we are visible
- window.setTimeout(async function () {
- let screenX = window.screenX, screenY = window.screenY, i = 5;
- while (!screenX && i--) {
- await new Promise(resolve => window.requestAnimationFrame(resolve));
- screenX = window.screenX;
- screenY = window.screenY;
- }
- var xRange = [window.screen.availLeft, window.screen.left + window.screen.width - window.outerWidth];
- var yRange = [window.screen.availTop, window.screen.top + window.screen.height - window.outerHeight];
- if(screenX < xRange[0] || screenX > xRange[1] || screenY < yRange[0] || screenY > yRange[1]) {
- var targetX = Math.max(Math.min(screenX, xRange[1]), xRange[0]);
- var targetY = Math.max(Math.min(screenY, yRange[1]), yRange[0]);
- Zotero.debug(`Moving window to ${targetX}, ${targetY}`);
- window.moveTo(targetX, targetY);
- }
- }, 0);
-
-
- io = window.arguments[0].wrappedJSObject;
-
- // find accept button
- _acceptButton = document.querySelector('dialog').getButton("accept");
- _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");
- _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
- // based on the same item in the same citation. Internal throwaway variable,
- // reset each time _multipleSourcesOn is set to true.
- serial_number = 0;
-
- // if a style with sortable citations, present checkbox
- if(io.sortable) {
- _sortCheckbox = document.getElementById("keepSorted");
- _sortCheckbox.hidden = false;
- _sortCheckbox.checked = !io.citation.properties.unsorted;
- }
-
- // load locators
- var locators = Zotero.Cite.labels;
- var menu = document.getElementById("label");
- var label_list = document.getElementById("locator-type-popup");
- var i = 0;
- var pageLocatorIndex;
- for(var value in locators) {
- var locator = locators[value];
- let locatorLabel = Zotero.Cite.getLocatorString(locator);
- // add to list of labels
- var child = document.createXULElement("menuitem");
- child.setAttribute("value", value);
- child.setAttribute("label", locatorLabel);
- label_list.appendChild(child);
- // add to array
- _locatorIndexArray[locator] = i;
- _locatorNameArray[i] = locator;
- if (locator == 'page') {
- pageLocatorIndex = i;
- _preserveData.label[1] = i;
- }
- i++;
- }
- menu.selectedIndex = pageLocatorIndex;
-
- if (!io.itemTreeID) {
- io.itemTreeID = "add-citation-select-item-dialog";
- }
-
- // load (from selectItemsDialog.js)
- yield doLoad();
-
- // if we already have a citation, load data from it
- _editor = document.querySelector('#editor').contentWindow.editor;
- if(io.citation.citationItems.length) {
- if(io.citation.citationItems.length === 1) {
- // single citation
- toggleMultipleSources(false);
- _suppressNextTreeSelect = true;
-
- // DEBUG: When editing a citation before the library data has been loaded (i.e., in
- // Firefox before the pane has been opened), this is the citation id, not the item id,
- // and this fails. It works on subsequent attempts. Since this won't happen in
- // Standalone, we can ignore.
- var id = io.citation.citationItems[0].id;
- let selected = yield collectionsView.selectItem(id);
-
- for(var box in _preserveData) {
- var property = _preserveData[box][0];
- if(io.citation.citationItems[0][box]) {
- if(box === "label") {
- document.getElementById(box)[property] = _locatorIndexArray[io.citation.citationItems[0][box]];
- } else {
- document.getElementById(box)[property] = io.citation.citationItems[0][box];
- }
- }
- }
- } else {
- // multiple citations
- toggleMultipleSources(true);
- var _itemData = {};
- // There is a little thrashing here, with repeated writes and
- // overwrites of node content. But sticking to the same
- // workflow for all updates (node -> array -> io.citation) makes
- // debugging a little less painful.
- for(var i=0; i -1) {
- var itemDataID = _citationList.getSelectedItem(0).getAttribute("value");
- itemID = itemDataID.slice(0, itemDataID.indexOf(":"));
- }
-
- // delete item list
- _itemData = new Object();
-
- // delete all items
- _clearCitationList();
-
- // refresh
- if (itemID) {
- collectionsView.selectItem(itemID);
- }
- _updateAccept();
- _updatePreview();
- }
- }
-
- /*
- * called when an item in the item selection tree is clicked
- */
- function treeItemSelected() {
- if(_suppressNextTreeSelect) {
- _suppressNextTreeSelect = false;
- _updateAccept();
- return;
- }
- var items = itemsView.getSelectedItems(true); // treeview from xpcom/itemTreeView.js
- var itemID = (items.length ? items[0] : false);
-
- if(_multipleSourcesOn) {
- // We can safely use itemID here, because none of these operations
- // affect selected items; this is all about the tree and navigation.
-
- // turn off highlight in selected item list
- _suppressNextListSelect = true;
- document.getElementById("item-list").selectedIndex = -1;
-
- // disable all fields
-
- for(var box in _preserveData) {
- document.getElementById(box).disabled = true;
- }
-
- // disable adding nothing
- document.getElementById("add").disabled = !itemID;
- document.getElementById("remove").disabled = true;
- document.getElementById("up").disabled = true;
- document.getElementById("down").disabled = true;
- } else {
- for(var box in _preserveData) {
- document.getElementById(box).disabled = !itemID;
- }
- _updateAccept();
- _updatePreview();
- window.isPristine = false;
- }
- }
-
- /*
- * called when an item in the selected items list is clicked
- */
- function listItemSelected() {
- if(_suppressNextListSelect) {
- _suppressNextListSelect = false;
- _updateAccept();
- return;
- }
- var selectedListItem = _citationList.getSelectedItem(0);
- var selectedListIndex = _citationList.selectedIndex;
- var itemDataID = (selectedListItem ? selectedListItem.getAttribute("value") : false);
- _itemSelected(itemDataID);
- // turn off highlight in item tree
- _suppressNextTreeSelect = true;
- itemsView.selection.clearSelection();
- document.getElementById("remove").disabled = !itemDataID;
- document.getElementById("add").disabled = true;
- _configListPosition(!itemDataID, selectedListIndex);
- }
-
- function _configListPosition(flag, selectedListIndex) {
- if (selectedListIndex > 0) {
- document.getElementById("up").disabled = flag;
- } else {
- document.getElementById("up").disabled = true;
- }
- if (-1 < selectedListIndex && selectedListIndex < (_citationList.getRowCount() - 1)) {
- document.getElementById("down").disabled = flag;
- } else {
- document.getElementById("down").disabled = true;
- }
- }
-
- function _move(direction) {
- // automatically uncheck sorted checkbox if user is rearranging citation
- if(_sortCheckbox && _sortCheckbox.checked) {
- _sortCheckbox.checked = false;
- setSortToggle();
- }
-
- var insertBeforeItem;
- var selectedListItem = _citationList.getSelectedItem(0);
- var selectedListIndex = _citationList.selectedIndex;
- var itemDataID = selectedListItem.getAttribute("value");
- if (direction === -1) {
- insertBeforeItem = selectedListItem.previousSibling;
- } else {
- insertBeforeItem = selectedListItem.nextSibling.nextSibling;
- }
- var listItem = _citationList.removeChild(selectedListItem);
- _citationList.insertBefore(listItem, insertBeforeItem);
- _citationList.selectedIndex = (selectedListIndex + direction);
- _itemSelected(itemDataID);
- _updatePreview();
- _configListPosition(false, (selectedListIndex + direction));
- window.isPristine = false;
- }
-
- function up() {
- _move(-1);
- }
-
- function down() {
- _move(1);
- }
-
- /*
- * Adds an item to the multipleSources list
- */
- this.add = Zotero.Promise.coroutine(function* (first_item) {
- var pos, len;
- var items = itemsView.getSelectedItems(); // treeview from xpcom/itemTreeView.js
- window.isPristine = false;
-
- if (!items.length) {
- yield sortCitation();
- _updateAccept();
- _updatePreview();
- return;
- }
-
- // Add to selection list and generate a new itemDataID for this cite.
- for (let item of items) {
- var selectionNode = _addItem(item);
- var itemDataID = selectionNode.getAttribute("value");
- document.getElementById("add").disabled = !itemDataID;
- }
-
- // Save existing locator and affix field content, if any.
- if (first_item) {
- _itemSelected(itemDataID, true);
- } else {
- _itemSelected();
- // set to defaults
- for(var box in _preserveData) {
- var property = _preserveData[box][0];
- var default_value = _preserveData[box][1];
- document.getElementById(box)[property] = default_value;
- }
- // Save default locator and affix element values to this multi-item.
- _itemSelected(itemDataID, true);
- }
-
- for(var box in _preserveData) {
- document.getElementById(box).disabled = true;
- }
-
- _citationList.ensureElementIsVisible(selectionNode);
-
- // allow user to press OK
- selectionNode = yield sortCitation(selectionNode);
- _citationList.selectItem(selectionNode);
- _updateAccept();
- _updatePreview();
- });
-
- /*
- * Deletes a citation from the multipleSources list
- */
- function remove() {
- var selectedListItem = _citationList.getSelectedItem(0);
- var selectedListIndex = _citationList.selectedIndex;
- var itemDataID = selectedListItem.getAttribute("value");
-
- // remove from _itemData
- delete _itemData[itemDataID];
- _itemData[itemDataID] = undefined;
- _lastSelected = null;
-
- // remove from list
- _citationList.removeChild(selectedListItem);
-
- if (selectedListIndex >= _citationList.getRowCount()) {
- selectedListIndex = _citationList.getRowCount() - 1;
- }
- _citationList.selectedIndex = selectedListIndex;
-
- _updateAccept();
- _updatePreview();
- window.isPristine = false;
- }
-
- /*
- * Sorts preview citations, if preview is open.
- */
- this.citationSortUnsort = Zotero.Promise.coroutine(function* () {
- setSortToggle();
- yield sortCitation();
- _updatePreview();
- });
-
- /*
- * Sets the current sort toggle state persistently on the citation.
- */
- function setSortToggle() {
- if(!_sortCheckbox) return;
- if(!_sortCheckbox.checked) {
- io.citation.properties.unsorted = true;
- } else {
- io.citation.properties.unsorted = false;
- }
- return;
- }
-
- /*
- * Sorts the list of citations
- */
- var sortCitation = Zotero.Promise.coroutine(function* (scrollToItem) {
- if(!_sortCheckbox) return scrollToItem;
- if(!_sortCheckbox.checked) {
- io.citation.properties.unsorted = true;
- return scrollToItem;
- }
- var scrollToItemID = false;
- if (scrollToItem) {
- scrollToItemID = scrollToItem.getAttribute("value");
- }
- _getCitation();
-
- // delete all existing items from list
- _clearCitationList();
-
- // run preview function to re-sort, if it hasn't already been
- // run
- yield io.sort();
-
- // add items back to list
- scrollToItem = null;
- for(var i=0; i 0) {
- if (result == 2) {
- _showItemInLibrary(parseInt(item.id));
- }
- return false;
- }
- if (checkbox.value) {
- Zotero.Retractions.disableCitationWarningsForItem({ id: parseInt(item.id) });
- }
- }
- item.ignoreRetraction = true;
- }
- }
- }
-
- io.accept();
- _accepted = true;
- return true;
- }
-
- /*
- * called when cancel button is clicked
- */
- function cancel() {
- if(_accepted) return true;
- io.cancel();
- _accepted = true;
- return true;
- }
-
- /*
- * Updates the contents of the preview pane
- */
- function _updatePreview() {
- if(_previewShown) {
- _getCitation();
-
- _editor.setEnabled(io.citation.citationItems.length);
- if (io.citation.citationItems.length) {
- io.preview().then((preview) => {
- _editor.setContent(preview, true);
-
- _originalHTML = _editor.getContent(true);
- });
- } else {
- _editor.setContent("");
- _originalHTML = "";
- }
- }
- }
-
- /*
- * Controls whether the accept (OK) button should be enabled
- */
- function _updateAccept() {
- if(_multipleSourcesOn) {
- _acceptButton.disabled = !_citationList.getRowCount();
- // To prevent accidental data loss, do not allow change to
- // single citation mode if multiple items are in selection
- // list.
- if (_citationList.getRowCount() > 1) {
- _multipleSourceButton.disabled = true;
- } else {
- _multipleSourceButton.disabled = false;
- }
- } else {
- collectionsView.onLoad.addListener(Zotero.Promise.coroutine(function* () {
- if (itemsView) {
- yield itemsView.waitForLoad();
- _acceptButton.disabled = !itemsView.getSelectedItems().length;
- }
- }));
- }
- }
-
- /*
- * called when an item is selected; if itemDataID is false, disables fields; if
- * itemDataID is undefined, only updates _itemData array
- *
- * Note: This function no longer disables fields. That operation is
- * now performed separately by explicit code.
- */
- function _itemSelected(itemDataID, forceSave) {
-
- if (forceSave) {
- _lastSelected = itemDataID;
- }
-
- if(_lastSelected && !_itemData[_lastSelected]) {
- _itemData[_lastSelected] = new Object();
- }
-
- for(var box in _preserveData) {
- var domBox = document.getElementById(box);
- var property = _preserveData[box][0];
-
- // save property
- if(_lastSelected) {
- if(property == "label") {
- _itemData[_lastSelected][box] = _locatorNameArray[domBox.selectedIndex];
- } else {
- _itemData[_lastSelected][box] = domBox[property];
- }
- }
- // restore previous property
- if(itemDataID) {
- domBox.disabled = false;
- if(_itemData[itemDataID] && _itemData[itemDataID][box] !== undefined) {
- if(property == "label") {
- domBox[property] = _locatorIndexArray[_itemData[itemDataID][box]];
- } else {
- domBox[property] = _itemData[itemDataID][box];
- }
- }
- }
- }
-
- if(itemDataID !== undefined) _lastSelected = itemDataID;
- }
-
- /*
- * updates io.citation to reflect selected items
- */
- function _getCitation() {
- var key;
- io.citation.citationItems = new Array();
-
- // use to map selectedIndexes back to page/paragraph/line
- var locatorTypeElements = document.getElementById("label").getElementsByTagName("menuitem");
- if(_multipleSourcesOn) {
- _itemSelected(); // store locator info
- var listLength = _citationList.getRowCount();
- if(listLength) {
- // generate citationItems
- for(var i=0; i {
- let onOpen = function () {
- win.removeEventListener('load', onOpen);
- resolve();
- };
- win.addEventListener('load', onOpen);
- });
- pane = win.ZoteroPane;
- }
- pane.selectItem(id);
-
- // Pull window to foreground
- Zotero.Utilities.Internal.activate(pane.document.defaultView);
- }
-}
-
-window.cancel = Zotero_Citation_Dialog.cancel;
diff --git a/chrome/content/zotero/integration/addCitationDialog.xhtml b/chrome/content/zotero/integration/addCitationDialog.xhtml
deleted file mode 100644
index b53b992746..0000000000
--- a/chrome/content/zotero/integration/addCitationDialog.xhtml
+++ /dev/null
@@ -1,129 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/chrome/content/zotero/integration/insertNoteDialog.js b/chrome/content/zotero/integration/insertNoteDialog.js
deleted file mode 100644
index 31697f926d..0000000000
--- a/chrome/content/zotero/integration/insertNoteDialog.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- ***** BEGIN LICENSE BLOCK *****
-
- Copyright © 2021 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 .
-
- ***** END LICENSE BLOCK *****
-*/
-
-var defaultBubbleizeSelected = Zotero_QuickFormat._bubbleizeSelected;
-Zotero_QuickFormat.citingNotes = true;
-Zotero_QuickFormat._bubbleizeSelected = async function () {
- await defaultBubbleizeSelected();
- await Zotero_QuickFormat.accept();
-}
\ No newline at end of file
diff --git a/chrome/content/zotero/integration/insertNoteDialog.xhtml b/chrome/content/zotero/integration/insertNoteDialog.xhtml
deleted file mode 100644
index 7de37fbc3f..0000000000
--- a/chrome/content/zotero/integration/insertNoteDialog.xhtml
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/chrome/content/zotero/integration/quickFormat.js b/chrome/content/zotero/integration/quickFormat.js
deleted file mode 100644
index 7ad3e09b2f..0000000000
--- a/chrome/content/zotero/integration/quickFormat.js
+++ /dev/null
@@ -1,2384 +0,0 @@
-/*
- ***** BEGIN LICENSE BLOCK *****
-
- Copyright © 2011 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 .
-
- ***** END LICENSE BLOCK *****
-*/
-Services.scriptloader.loadSubScript("chrome://zotero/content/customElements.js", this);
-Services.scriptloader.loadSubScript("chrome://zotero/content/titlebar.js", this);
-
-window.isPristine = true;
-
-var Zotero_QuickFormat = new function () {
- const pixelRe = /^([0-9]+)px$/
- const specifiedLocatorRe = /^(?:,? *(p{1,2})(?:\. *| *)|:)([0-9\-–]+) *$/;
- const yearRe = /,? *([0-9]+(?: *[-–] *[0-9]+)?) *(B[. ]*C[. ]*(?:E[. ]*)?|A[. ]*D[. ]*|C[. ]*E[. ]*)?$/i;
- const locatorRe = / (?:,? *(p{0,2})\.?|(\:)) *([0-9\-–]+)$/i;
- const creatorSplitRe = /(?:,| *(?:and|\&)) +/;
- const charRe = /[\w\u007F-\uFFFF]/;
- const numRe = /^[0-9\-–]+$/;
-
- var initialized, io, editor, dialog, qfGuidance,
- keepSorted, showEditor, referencePanel, referenceBox,
- currentLocator, currentLocatorLabel, currentSearchTime, bubbleDraggedIndex = null,
- itemPopover, itemPopoverPrefix, itemPopoverSuffix, itemPopoverSuppressAuthor, itemPopoverLocatorLabel, itemPopoverLocator,
- panelLibraryLink, panelInfo, panelRefersToBubble, panelFrameHeight = 0, accepted = false,
- isPaste = false, _itemPopoverClosed, skipInputRefocus;
- var locatorNode = null;
- var _searchPromise;
-
- var _lastFocusedInput = null;
- var _bubbleMouseDown = false;
-
- const ITEM_LIST_MAX_ITEMS = 50;
- const SEARCH_TIMEOUT = 250;
- const SHOWN_REFERENCES = 7;
- const WINDOW_WIDTH = 800;
- const ESC_ENTER_THROTTLE = 1000;
-
- /**
- * Pre-initialization, when the dialog has loaded but has not yet appeared
- */
- this.onDOMContentLoaded = function(event) {
- if(event.target === document) {
- initialized = true;
- io = window.arguments[0].wrappedJSObject;
-
- Zotero.debug(`Quick Format received citation:`);
- Zotero.debug(JSON.stringify(io.citation.toJSON()));
-
- if (io.disableClassicDialog) {
- document.getElementById('classic-view').hidden = true;
- }
-
- // Hide chrome on linux
- if (Zotero.isLinux) {
- document.documentElement.setAttribute("hidechrome", true);
- }
-
- dialog = document.querySelector(".citation-dialog.entry");
- editor = document.querySelector(".citation-dialog.editor");
- _resizeEditor();
- dialog.addEventListener("click", _onQuickSearchClick, false);
- dialog.addEventListener("keypress", _onQuickSearchKeyPress, false);
- editor.addEventListener("dragover", _onEditorDragOver);
- editor.addEventListener("drop", _onEditorDrop, false);
- referencePanel = document.querySelector(".citation-dialog.reference-panel");
- referenceBox = document.querySelector(".citation-dialog.reference-list");
- // Navigation within the reference panel
- referenceBox.addEventListener("keypress", (event) => {
- // Enter or ; selects the reference
- if ((event.key == "Enter" && !event.shiftKey) || event.charCode == 59) {
- event.preventDefault();
- event.stopPropagation();
- Zotero_QuickFormat._bubbleizeSelected();
- }
- // Tab will move focus back to the input field
- else if (event.key === "Tab") {
- event.preventDefault();
- event.stopPropagation();
- _lastFocusedInput.focus();
- }
- // Can keep typing from the reference box
- else if (isKeypressPrintable(event) || event.key === 'Backspace') {
- event.preventDefault();
- if (event.key === 'Backspace') {
- _lastFocusedInput.value = _lastFocusedInput.value.slice(0, -1);
- }
- else {
- _lastFocusedInput.value += event.key;
- }
- _lastFocusedInput.dispatchEvent(new Event('input', { bubbles: true }));
- _lastFocusedInput.focus();
- }
- else if (["ArrowDown", "ArrowUp"].includes(event.key)) {
- event.preventDefault();
- event.stopPropagation();
- // ArrowUp from first item focuses the input
- if (event.key == "ArrowUp" && referenceBox.selectedIndex == 1 && referenceBox.selectedItem == document.activeElement) {
- _lastFocusedInput.focus();
- referenceBox.selectedIndex = -1;
- }
- else {
- handleItemSelection(event);
- }
- }
- // Right/Left arrow will hide ref panel and move focus to the previour/next element
- else if (event.key == Zotero.arrowPreviousKey) {
- _lastFocusedInput.focus();
- moveFocusBack(_lastFocusedInput);
- }
- else if (event.key == Zotero.arrowNextKey) {
- _lastFocusedInput.focus();
- moveFocusForward(_lastFocusedInput);
- }
- });
- referenceBox.addEventListener("click", (e) => {
- let item = e.target.closest("richlistitem");
- if (!item || e.button !== 0 || item.disabled) return;
-
- let mouseMultiSelect = e.shiftKey || (Zotero.isMac && e.metaKey) || (!Zotero.isMac && e.ctrlKey);
- let multipleSelected = referenceBox.selectedCount > 1;
- let isItemSelected = [...referenceBox.selectedItems].findIndex(node => node == item) !== -1;
- // Click without multiselect modifier will confirm the selection
- if (!mouseMultiSelect) {
- // If item is multi-selected, do not discard the selection
- if (multipleSelected && isItemSelected) {
- e.preventDefault();
- }
- Zotero_QuickFormat._bubbleizeSelected();
- return;
- }
- // Make sure there is a selected item when shift-click is handled
- if (e.shiftKey && referenceBox.selectedCount < 1) {
- _selectFirstReference();
- }
- // Shift-Click selects a range starting from _selectionStart
- // https://searchfox.org/mozilla-central/source/toolkit/content/widgets/richlistbox.js#469
- // which is not be always correct after selecting and un-selecting items
- // with a few cmd/ctrl-clicks. To achieve a more consistent behavior, reset _selectionStart
- // to be the first or last selected node, depending on which item is clicked.
- let allItems = [...referenceBox.childNodes];
- let firstSelectedIndex = allItems.findIndex(node => node == referenceBox.querySelector("[selected=true]"));
- let clickedItemIndex = allItems.findIndex(node => node == item);
- let allSelected = [...referenceBox.querySelectorAll("[selected=true]")];
- if (clickedItemIndex < firstSelectedIndex) {
- referenceBox._selectionStart = allSelected[allSelected.length - 1];
- }
- else {
- referenceBox._selectionStart = allSelected[0];
- }
- // Shift-click can end up selecting disabled separator, so make sure it's removed
- setTimeout(() => {
- let selectedSeparators = [...document.querySelectorAll("richlistitem[disabled='true'][selected='true']")];
- for (let node of selectedSeparators) {
- referenceBox.removeItemFromSelection(node);
- }
- });
- }, true);
- if (Zotero.isWin) {
- if (Zotero.Prefs.get('integration.keepAddCitationDialogRaised')) {
- dialog.setAttribute("square", "true");
- }
- }
-
- keepSorted = document.getElementById("keep-sorted");
- showEditor = document.getElementById("show-editor");
- if(keepSorted && io.sortable) {
- keepSorted.hidden = false;
- if(!io.citation.properties.unsorted) {
- keepSorted.setAttribute("checked", "true");
- }
- }
- // Make icon focusable only if there's a visible menuitem
- for (let menuitemID of ["keep-sorted", "show-editor", "classic-view"]) {
- let menuitem = document.getElementById(menuitemID);
- if (menuitem && menuitem.getAttribute("hidden") != "true") {
- document.getElementById("zotero-icon").removeAttribute("disabled");
- document.getElementById("input-description").setAttribute("data-l10n-args", `{ "dialogMenu":"active"}`);
- }
- }
- // Nodes for citation properties panel
- itemPopover = document.getElementById("citation-properties");
- if (itemPopover) {
- itemPopoverPrefix = document.getElementById("prefix");
- itemPopoverSuffix = document.getElementById("suffix");
- itemPopoverSuppressAuthor = document.getElementById("suppress-author");
- itemPopoverLocatorLabel = document.getElementById("locator-label");
- itemPopoverLocator = document.getElementById("locator");
- panelInfo = document.getElementById("citation-properties-info");
- panelLibraryLink = document.getElementById("citation-properties-library-link");
-
- // add labels to popup
- var locators = Zotero.Cite.labels;
- var labelList = document.getElementById("locator-label-popup");
- for(var locator of locators) {
- let locatorLabel = Zotero.Cite.getLocatorString(locator);
-
- // add to list of labels
- var child = document.createXULElement("menuitem");
- child.setAttribute("value", locator);
- child.setAttribute("label", locatorLabel);
- labelList.appendChild(child);
- }
- // If the focus leaves the citation properties panel, close it
- itemPopover.addEventListener("focusout", (_) => {
- setTimeout(() => {
- if (!itemPopover.contains(document.activeElement)) {
- itemPopover.hidePopup();
- }
- });
- });
- // Focus locator when popover appears
- itemPopover.addEventListener("popupshown", (e) => {
- if (e.target.id == "citation-properties") {
- document.getElementById('locator').focus();
- }
- });
- }
-
- // Don't need to set noautohide dynamically on these platforms, so do it now
- if(Zotero.isMac || Zotero.isWin) {
- referencePanel.setAttribute("noautohide", true);
- }
-
- // Resize whenever a bubble/input is added or removed of their attributes change
- let resizeObserver = new MutationObserver(function (_) {
- // Due to very odd mozilla behavior, calls to resize the window when
- // dragging is happening make the next drag events after resize
- // act strange (dragging doesn't happen, though dragstart fires but dragend doesn't)
- // Resizing after delay in _onEditorDrop seems to not cause this issue
- if (bubbleDraggedIndex === null) {
- _resizeWindow();
- }
- });
- resizeObserver.observe(editor, { childList: true, subtree: true, attributes: true });
- }
- };
-
- /**
- * Initialize add citation dialog
- */
- this.onLoad = async function (event) {
- try {
- if (event.target !== document) return;
- // make sure we are visible
- let resizePromise = (async function () {
- let screenX = window.screenX, screenY = window.screenY, i = 5;
- while (!screenX && i--) {
- await new Promise(resolve => window.requestAnimationFrame(resolve));
- screenX = window.screenX;
- screenY = window.screenY;
- }
- var xRange = [window.screen.availLeft, window.screen.left + window.screen.width - window.outerWidth];
- var yRange = [window.screen.availTop, window.screen.top + window.screen.height - window.outerHeight];
- if (screenX < xRange[0] || screenX > xRange[1] || screenY < yRange[0] || screenY > yRange[1]) {
- var targetX = Math.max(Math.min(screenX, xRange[1]), xRange[0]);
- var targetY = Math.max(Math.min(screenY, yRange[1]), yRange[0]);
- Zotero.debug(`Moving window to ${targetX}, ${targetY}`);
- window.moveTo(targetX, targetY);
- }
- qfGuidance = document.querySelector('.citation-dialog.guidance');
- qfGuidance && qfGuidance.show();
- })();
-
- // load citation data
- if (io.citation.citationItems.length) {
- await resizePromise;
- _showCitation(null);
- }
- requestAnimationFrame(() => {
- _updateItemList({ citedItems: [] });
- });
- refocusInput();
- }
- catch (e) {
- Zotero.logError(e);
- }
- };
-
- // If this input field was counted as previously focused,
- // it will be cleared. Call before removing the field
- function clearLastFocused(input) {
- if (input == _lastFocusedInput) {
- _lastFocusedInput = null;
- }
- }
-
- // Create input in the end of the editor and focus it
- function addInputToTheEnd() {
- let newInput = _createInputField();
- editor.appendChild(newInput);
- newInput.focus();
- return newInput;
- }
-
- // Return the focus to the input.
- // If tryLastFocused=true, try to focus on the last active input first.
- // Then, try to focus the last input from the editor.
- // If there are no inputs, append one to the end and focus that.
- function refocusInput(tryLastFocused = true) {
- let input = tryLastFocused ? _lastFocusedInput : null;
- if (!input) {
- let allInputs = editor.querySelectorAll(".zotero-bubble-input");
- if (allInputs.length > 0) {
- input = allInputs[allInputs.length - 1];
- }
- }
- if (!input) {
- input = addInputToTheEnd();
- }
- input.focus();
- return input;
- }
-
- function _createInputField() {
- let newInput = document.createElement("input");
- newInput.className = "zotero-bubble-input";
- newInput.setAttribute("aria-describedby", "input-description");
- newInput.setAttribute("dir", Zotero.rtl ? "rtl" : "auto");
- newInput.addEventListener("input", (_) => {
- _resetSearchTimer();
- // Expand/shrink the input field to match the width of content
- let width = getContentWidth(newInput);
- newInput.style.width = width + 'px';
- });
- newInput.addEventListener("keypress", onInputPress);
- newInput.addEventListener("paste", _onPaste, false);
- newInput.addEventListener("focus", (_) => {
- // If the input used for the last search run is refocused,
- // just make sure the reference panel is opened if it has items.
- if (_lastFocusedInput == newInput && referenceBox.childElementCount > 0) {
- _openReferencePanel();
- return;
- }
- // Otherwise, run the search if the input is non-empty
- // or if we are citing notes (in which case, if the input is empty,
- // most-recently modified notes are displayed)
- if (!isInputEmpty(newInput) || Zotero_QuickFormat.citingNotes) {
- _resetSearchTimer();
- }
- else {
- _updateItemList({ citedItems: [] });
- }
- });
- // Delete empty input on blur unless focus is inside of the reference panel
- newInput.addEventListener("blur", (_) => {
- // Timeout to know where the focus landed after
- setTimeout(() => {
- let refPanelFocused = referencePanel.contains(document.activeElement);
- if (isInputEmpty(newInput) && !refPanelFocused) {
- // Resizing window right before drag-drop reordering starts, will interrupt the
- // drag event. To avoid it, hide the input immediately and delete it after delay.
- if (_bubbleMouseDown) {
- newInput.style.display = "none";
- setTimeout(() => {
- newInput.remove();
- }, 500);
- clearLastFocused(newInput);
- }
- else if (document.activeElement !== newInput && !isEditorCleared()) {
- // If no dragging, delete it if focus has moved elsewhere.
- // If focus remained, the entire dialog lost focus, so do nothing
- // If this is the last, non-removable, input - do not remove it as well.
- newInput.remove();
- clearLastFocused(newInput);
- }
- }
- // If focus leaves input, hide the reference panel.
- if (refPanelFocused) {
- return;
- }
- let focusedInput = _getCurrentInput();
- if (!focusedInput) {
- referencePanel.hidePopup();
- }
- });
- // If there was a br added before input so that it doesn't appear on the previous line,
- // remove it
- if (newInput.previousElementSibling?.tagName == "br") {
- newInput.previousElementSibling.remove();
- }
- locatorNode = null;
- });
- return newInput;
- }
-
- // Theoritically, we can have two inputs next to each other. For example,
- // if a bubble between two inputs is deleted. In this case,
- // combine two inputs into one.
- function _combineNeighboringInputs() {
- let node = editor.firstChild;
- while (node && node.nextElementSibling) {
- if (node.classList == "zotero-bubble-input"
- && node.nextElementSibling.classList == "zotero-bubble-input") {
- let secondInputValue = node.nextElementSibling.value;
- node.value += ` ${secondInputValue}`;
- node.dispatchEvent(new Event('input', { bubbles: true }));
- // Make sure focus is not lost when two inputs are combined
- if (node.nextElementSibling == document.activeElement) {
- node.focus();
- }
- node.nextElementSibling.remove();
- }
- node = node.nextElementSibling;
- }
- }
-
-
- /**
- * Updates currentLocator based on a string
- * @param {String} str String to search for locator
- * @return {String} str without locator
- */
- function _updateLocator(str) {
- m = !isPaste && locatorRe.exec(str);
- if(m && (m[1] || m[2] || m[3].length !== 4) && m.index > 0) {
- currentLocator = m[3];
- str = str.substr(0, m.index)+str.substring(m.index+m[0].length);
- }
- return str;
- }
-
- /**
- * Does the dirty work of figuring out what the user meant to type
- */
- var _quickFormat = Zotero.Promise.coroutine(function* () {
- var str = _getEditorContent();
- var haveConditions = false;
-
- const etAl = " et al.";
-
- var m,
- year = false,
- isBC = false,
- dateID = false;
-
- currentLocator = false;
- currentLocatorLabel = false;
-
- // check for adding a number onto a previous page number
- if (locatorNode && numRe.test(str)) {
- // add to previous cite
- let citationItem = JSON.parse(locatorNode && locatorNode.dataset.citationItem || "null");
- if (citationItem) {
- if (!("locator" in citationItem)) {
- citationItem.locator = "";
- }
- citationItem.locator += str;
- locatorNode.dataset.citationItem = JSON.stringify(citationItem);
- locatorNode.textContent = _buildBubbleString(citationItem);
- _clearEntryList();
- let input = _getCurrentInput();
- input.value = "";
- input.dispatchEvent(new Event('input', { bubbles: true }));
- return;
- }
- }
-
- if(str && str.length > 1) {
- // check for specified locator
- m = specifiedLocatorRe.exec(str);
- if(m) {
- if(m.index === 0) {
- // add to previous cite
- let node = _getCurrentInput();
- var prevNode = locatorNode || node.previousElementSibling;
- let citationItem = JSON.parse(prevNode && prevNode.dataset.citationItem || "null");
- if (citationItem) {
- citationItem.locator = m[2];
- citationItem.label = "page";
- prevNode.dataset.citationItem = JSON.stringify(citationItem);
- prevNode.textContent = _buildBubbleString(citationItem);
- _clearEntryList();
- let input = _getCurrentInput();
- input.value = "";
- input.dispatchEvent(new Event('input', { bubbles: true }));
- window.isPristine = false;
- return;
- }
- }
-
- // TODO support types other than page
- currentLocator = m[2];
- str = str.substring(0, m.index);
- }
-
- str = _updateLocator(str);
- // check for year and pages
- m = yearRe.exec(str);
- if(m) {
- year = parseInt(m[1]);
- isBC = m[2] && m[2][0] === "B";
- str = str.substr(0, m.index)+str.substring(m.index+m[0].length);
- }
- if(year) str += " "+year;
-
- var s = new Zotero.Search();
- str = str.replace(/ (?:&|and) /g, " ", "g");
- str = str.replace(/^,/, '');
- if(charRe.test(str)) {
- Zotero.debug("QuickFormat: QuickSearch: "+str);
- // Exclude feeds
- Zotero.Feeds.getAll()
- .forEach(feed => s.addCondition("libraryID", "isNot", feed.libraryID));
- if (Zotero_QuickFormat.citingNotes) {
- s.addCondition("quicksearch-titleCreatorYearNote", "contains", str);
- }
- else {
- s.addCondition("quicksearch-titleCreatorYear", "contains", str);
- s.addCondition("itemType", "isNot", "attachment");
- if (io.filterLibraryIDs) {
- io.filterLibraryIDs.forEach(id => s.addCondition("libraryID", "is", id));
- }
- }
- haveConditions = true;
- }
- }
-
- if (!haveConditions && Zotero_QuickFormat.citingNotes) {
- s = new Zotero.Search();
- str = "";
- s.addCondition("quicksearch-titleCreatorYearNote", "contains", str);
- haveConditions = true;
- }
-
- if (haveConditions) {
- var searchResultIDs = (haveConditions ? (yield s.search()) : []);
-
- // Show items list without cited items to start
- yield _updateItemList({ searchString: str, searchResultIDs });
-
- // Check to see which search results match items already in the document
- var citedItems, completed = !!Zotero_QuickFormat.citingNotes, isAsync = false;
- // Save current search time so that when we get items, we know whether it's too late to
- // process them or not
- var lastSearchTime = currentSearchTime = Date.now();
- // This may or may not be synchronous
- if (!Zotero_QuickFormat.citingNotes) {
- io.getItems().then(function(citedItems) {
- // Don't do anything if panel is already closed
- if(isAsync &&
- ((referencePanel.state !== "open" && referencePanel.state !== "showing")
- || lastSearchTime !== currentSearchTime)) return;
-
- completed = true;
-
- if(str.toLowerCase() === Zotero.getString("integration.ibid").toLowerCase()) {
- // If "ibid" is entered, show all cited items
- citedItemsMatchingSearch = citedItems;
- } else {
- Zotero.debug("Searching cited items");
- // Search against items. We do this here because it's possible that some of these
- // items are only in the doc, and not in the DB.
- var splits = Zotero.Fulltext.semanticSplitter(str),
- citedItemsMatchingSearch = [];
- for(var i=0, iCount=citedItems.length; i creator.firstName + " " + creator.lastName)
- .concat([item.getField("title"), item.getField("date", true, true).substr(0, 4)])
- .join(" ");
-
- // See if words match
- for(var j=0, jCount=splits.length; j t.type === 'reader').sort((a, b) => {
- // Sort selected tab first
- if (a.selected) return -1;
- else if (b.selected) return 1;
- // Then in reverse chronological select order
- else if (a.timeUnselected && b.timeUnselected) return b.timeUnselected - a.timeUnselected;
- // Then in reverse order for tabs that never got loaded in this session
- else if (a.timeUnselected) return -1;
- return 1;
- }).map(t => t.data.itemID);
- if (!itemIDs.length) return [];
-
- let items = itemIDs.map((itemID) => {
- let item = Zotero.Items.get(itemID);
- if (item && item.parentItemID) {
- itemID = item.parentItemID;
- }
- return Zotero.Cite.getItem(itemID);
- });
- let matchedItems = new Set(items);
- if (options.searchString) {
- Zotero.debug("QuickFormat: Searching open tabs");
- matchedItems = new Set();
- let splits = Zotero.Fulltext.semanticSplitter(options.searchString);
- for (let item of items) {
- // Generate a string to search for each item
- let itemStr = item.getCreators()
- .map(creator => creator.firstName + " " + creator.lastName)
- .concat([item.getField("title"), item.getField("date", true, true).substr(0, 4)])
- .join(" ");
-
- // See if words match
- for (let split of splits) {
- if (itemStr.toLowerCase().includes(split)) matchedItems.add(item);
- }
- }
- Zotero.debug("QuickFormat: Found matching open tabs");
- }
- // Filter out already cited items
- return Array.from(matchedItems).filter(i => !options.citationItemIDs.has(i.cslItemID ? i.cslItemID : i.id));
- }
-
- async function _getMatchingLibraryItems(options) {
- let { searchString,
- searchResultIDs, nCitedItemsFromLibrary } = options;
-
- let win = Zotero.getMainWindow();
- let selectedItems = [];
- if (win.Zotero_Tabs.selectedType === "library") {
- if (!Zotero_QuickFormat.citingNotes) {
- selectedItems = Zotero.getActiveZoteroPane().getSelectedItems().filter(i => i.isRegularItem());
- // Filter out already cited items
- selectedItems = selectedItems.filter(i => !options.citationItemIDs.has(i.cslItemID ? i.cslItemID : i.id));
- }
- else {
- selectedItems = Zotero.getActiveZoteroPane().getSelectedItems().filter(i => i.isNote());
- }
- }
- if (!searchString && selectedItems.length) {
- return [selectedItems, []];
- }
- else if (!searchResultIDs.length) {
- return [[], []];
- }
-
- // Search results might be in an unloaded library, so get items asynchronously and load
- // necessary data
- var items = await Zotero.Items.getAsync(searchResultIDs);
- await Zotero.Items.loadDataTypes(items);
-
- searchString = searchString.toLowerCase();
- let searchParts = Zotero.SearchConditions.parseSearchString(searchString);
- var collation = Zotero.getLocaleCollation();
-
- function _itemSort(a, b) {
- var firstCreatorA = a.firstCreator, firstCreatorB = b.firstCreator;
-
- // Favor left-bound name matches (e.g., "Baum" < "Appelbaum"),
- // using last name of first author
- if (firstCreatorA && firstCreatorB) {
- for (let part of searchParts) {
- let caStartsWith = firstCreatorA.toLowerCase().startsWith(part.text);
- let cbStartsWith = firstCreatorB.toLowerCase().startsWith(part.text);
- if (caStartsWith && !cbStartsWith) {
- return -1;
- }
- else if (!caStartsWith && cbStartsWith) {
- return 1;
- }
- }
- }
-
- var libA = a.libraryID, libB = b.libraryID;
- if (libA !== libB) {
- // Sort by number of cites for library
- if (nCitedItemsFromLibrary[libA] && !nCitedItemsFromLibrary[libB]) {
- return -1;
- }
- if (!nCitedItemsFromLibrary[libA] && nCitedItemsFromLibrary[libB]) {
- return 1;
- }
- if (nCitedItemsFromLibrary[libA] !== nCitedItemsFromLibrary[libB]) {
- return nCitedItemsFromLibrary[libB] - nCitedItemsFromLibrary[libA];
- }
-
- // Sort by ID even if number of cites is equal
- return libA - libB;
- }
-
- // Sort by last name of first author
- if (firstCreatorA !== "" && firstCreatorB === "") {
- return -1;
- }
- else if (firstCreatorA === "" && firstCreatorB !== "") {
- return 1;
- }
- else if (firstCreatorA) {
- return collation.compareString(1, firstCreatorA, firstCreatorB);
- }
-
- // Sort by date
- var yearA = a.getField("date", true, true).substr(0, 4),
- yearB = b.getField("date", true, true).substr(0, 4);
- return yearA - yearB;
- }
-
- function _noteSort(a, b) {
- return collation.compareString(
- 1, b.getField('dateModified'), a.getField('dateModified')
- );
- }
-
- items.sort(Zotero_QuickFormat.citingNotes ? _noteSort : _itemSort);
-
- // Split filtered items into selected and other bins
- let matchingSelectedItems = [];
- let matchingItems = [];
- for (let item of items) {
- if (selectedItems.findIndex(i => i.id === item.id) !== -1) {
- matchingSelectedItems.push(item);
- }
- else {
- matchingItems.push(item);
- }
- }
- return [matchingSelectedItems, matchingItems];
- }
-
- /**
- * Updates the item list
- */
- async function _updateItemList(options = {}) {
- options = Object.assign({
- citedItems: false,
- citedItemsMatchingSearch: false,
- searchString: "",
- searchResultIDs: [],
- preserveSelection: false,
- nCitedItemsFromLibrary: {},
- citationItemIDs: new Set()
- }, options);
-
- let { preserveSelection, nCitedItemsFromLibrary } = options;
- let previousItemID, selectedIndex = 0;
-
- // Do this so we can preserve the selected item after cited items have been loaded
- if (preserveSelection && referenceBox.selectedIndex !== -1 && referenceBox.selectedIndex !== 2) {
- previousItemID = parseInt(referenceBox.selectedItem.getAttribute("zotero-item"));
- }
-
- // Take into account items cited in this citation. This means that the sorting isn't
- // exactly by # of items cited from each library, but maybe it's better this way.
- _updateCitationObject();
- for (let citationItem of io.citation.citationItems) {
- var citedItem = io.customGetItem && io.customGetItem(citationItem) || Zotero.Cite.getItem(citationItem.id);
- options.citationItemIDs.add(citedItem.cslItemID ? citedItem.cslItemID : citedItem.id);
- if (!citedItem.cslItemID) {
- let libraryID = citedItem.libraryID;
- if (libraryID in nCitedItemsFromLibrary) {
- nCitedItemsFromLibrary[libraryID]++;
- }
- else {
- nCitedItemsFromLibrary[libraryID] = 1;
- }
- }
- }
-
- // To avoid blinking, fetch all necessary data first and then clear the
- // reference box without resizing the panel (it happens later)
- let openItems = await _getMatchingReaderOpenItems(options);
- let citedItems = _getMatchingCitedItems(options);
- let [selectedItems, libraryItems] = await _getMatchingLibraryItems(options);
-
- _clearEntryList(true);
-
- // Selected items are only returned if the currently selected tab is a library tab and
- // in that case displayed at the top
- if (selectedItems.length) {
- referenceBox.appendChild(_buildListSeparator(Zotero.getString("integration.selectedItems")));
- for (let item of selectedItems.slice(0, ITEM_LIST_MAX_ITEMS - referenceBox.children.length)) {
- referenceBox.appendChild(_buildListItem(item));
- }
- }
-
- // Open reader items
- if (openItems.length && ITEM_LIST_MAX_ITEMS - referenceBox.children.length) {
- referenceBox.appendChild(_buildListSeparator(Zotero.getString("integration.openTabs")));
- for (let item of openItems.slice(0, ITEM_LIST_MAX_ITEMS - referenceBox.children.length)) {
- referenceBox.appendChild(_buildListItem(item));
- }
- }
-
- // Items cited in the document
- if (ITEM_LIST_MAX_ITEMS - referenceBox.children.length) {
- if (citedItems === null) {
- // We don't know whether or not we have cited items, because we are waiting for document
- // data
- referenceBox.appendChild(_buildListSeparator(Zotero.getString("integration.cited.loading")));
- }
- else if (citedItems && citedItems.length) {
- referenceBox.appendChild(_buildListSeparator(Zotero.getString("integration.cited")));
- for (let item of citedItems.slice(0, ITEM_LIST_MAX_ITEMS - referenceBox.children.length)) {
- referenceBox.appendChild(_buildListItem(item));
- }
- }
- }
-
- // Any other items matching in any of the user's libraries.
- var previousLibrary = -1;
- for (let item of libraryItems.slice(0, ITEM_LIST_MAX_ITEMS - referenceBox.children.length)) {
- let libraryID = item.libraryID;
-
- if (previousLibrary != libraryID) {
- var libraryName = libraryID
- ? Zotero.Libraries.getName(libraryID)
- : Zotero.getString('pane.collections.library');
- referenceBox.appendChild(_buildListSeparator(libraryName));
- }
-
- referenceBox.appendChild(_buildListItem(item));
- previousLibrary = libraryID;
- }
-
- _resizeReferencePanel();
- if (!referenceBox.children.length) {
- return;
- }
-
- if (previousItemID !== undefined) {
- Array.from(referenceBox.children).some((elem, index) => {
- if (elem.getAttribute('zotero-item') === previousItemID) {
- selectedIndex = index;
- return true;
- }
- return false;
- });
- }
-
- let currentInput = _getCurrentInput();
- // Do not select the item in reference panel if the editor
- // is non-empty and nothing has been typed yet
- if (selectedIndex > 1 || isEditorCleared() || !isInputEmpty(currentInput)) {
- selectedIndex = _selectItem(selectedIndex);
- }
- referenceBox.ensureIndexIsVisible(selectedIndex);
- // Record the last input used for a search
- if (currentInput) {
- _lastFocusedInput = currentInput;
- }
- }
-
- /**
- * Builds a string describing an item. We avoid CSL here for speed.
- */
- function _buildItemDescription(item, infoHbox) {
- var nodes = [];
- // Add a red label to retracted items
- if (Zotero.Retractions.isRetracted(item)) {
- let label = document.createElement("span");
- label.textContent = Zotero.getString("retraction.banner");
- label.style.color = 'red';
- label.style['margin-inline-end'] = '5px';
- infoHbox.appendChild(label);
- }
- if (item.isNote()) {
- var date = Zotero.Date.sqlToDate(item.dateModified, true);
- date = Zotero.Date.toFriendlyDate(date);
- infoHbox.textContent = date;
-
- var text = item.note;
- text = Zotero.Utilities.unescapeHTML(text);
- text = text.trim();
- text = text.slice(0, 500);
- var parts = text.split('\n').map(x => x.trim()).filter(x => x.length);
- if (parts[1]) {
- infoHbox.textContent += ` ${parts[1]}.`;
- }
- }
- else {
- var author, authorDate = "";
- if(item.firstCreator) author = authorDate = item.firstCreator;
- var date = item.getField("date", true, true);
- if(date && (date = date.substr(0, 4)) !== "0000") {
- authorDate += " (" + parseInt(date) + ")";
- }
- authorDate = authorDate.trim();
- if(authorDate) nodes.push(authorDate);
-
- var publicationTitle = item.getField("publicationTitle", false, true);
- if(publicationTitle) {
- let label = document.createElement("span");
- label.textContent = publicationTitle;
- label.style.fontStyle = "italic";
- nodes.push(label);
- }
-
- var volumeIssue = item.getField("volume");
- var issue = item.getField("issue");
- if(issue) volumeIssue += "("+issue+")";
- if(volumeIssue) nodes.push(volumeIssue);
-
- var publisherPlace = [], field;
- if((field = item.getField("publisher"))) publisherPlace.push(field);
- if((field = item.getField("place"))) publisherPlace.push(field);
- if(publisherPlace.length) nodes.push(publisherPlace.join(": "));
-
- var pages = item.getField("pages");
- if(pages) nodes.push(pages);
-
- if(!nodes.length) {
- var url = item.getField("url");
- if(url) nodes.push(url);
- }
-
- // compile everything together
- for(var i=0, n=nodes.length; i with it
- let wrapper = document.createElement("span");
- wrapper.textContent = node;
- infoHbox.appendChild(wrapper);
- }
- }
- }
- // if there is no period in the end, insert it
- if (infoHbox.textContent.length && infoHbox.textContent[infoHbox.textContent.length - 1] !== ".") {
- let period = document.createElement("span");
- period.textContent = ".";
- infoHbox.appendChild(period);
- }
- }
-
- /**
- * Creates an item to be added to the item list
- */
- function _buildListItem(item) {
- var titleNode = document.createXULElement("label");
- titleNode.setAttribute("class", "citation-dialog title");
- titleNode.setAttribute("flex", "1");
- titleNode.setAttribute("crop", "end");
- titleNode.setAttribute("value", item.getDisplayTitle());
-
- var infoNode = document.createXULElement("hbox");
- infoNode.setAttribute("class", "citation-dialog info");
- _buildItemDescription(item, infoNode);
- // if description is empty, insert an empty placeholder to ensure identical row heights
- if (!infoNode.textContent.length) {
- let placeholder = document.createElement("span");
- placeholder.textContent = " ";
- placeholder.style.hidden = true;
- infoNode.appendChild(placeholder);
- }
-
- // add to rich list item
- var rll = document.createXULElement("richlistitem");
- rll.setAttribute("orient", "vertical");
- rll.setAttribute("class", "citation-dialog item");
- rll.setAttribute("zotero-item", item.cslItemID ? item.cslItemID : item.id);
- rll.setAttribute("aria-describedby", "item-description");
- rll.appendChild(titleNode);
- rll.appendChild(infoNode);
-
- return rll;
- }
-
- /**
- * Creates a list separator to be added to the item list
- */
- function _buildListSeparator(labelText, loading) {
- var titleNode = document.createXULElement("label");
- titleNode.setAttribute("class", "citation-dialog separator-title");
- titleNode.setAttribute("flex", "1");
- titleNode.setAttribute("crop", "end");
- titleNode.setAttribute("value", labelText);
-
- // add to rich list item
- var rll = document.createXULElement("richlistitem");
- rll.setAttribute("orient", "vertical");
- rll.setAttribute("disabled", true);
- // This ensures that screen readers don't include it while announcing elements' count
- rll.setAttribute("role", "presentation");
- rll.setAttribute("class", loading ? "citation-dialog loading" : "citation-dialog separator");
- rll.appendChild(titleNode);
- rll.addEventListener("mousedown", _ignoreClick, true);
- rll.addEventListener("click", _ignoreClick, true);
-
- return rll;
- }
-
- /**
- * Builds the string to go inside a bubble
- */
- function _buildBubbleString(citationItem) {
- var item = io.customGetItem && io.customGetItem(citationItem) || Zotero.Cite.getItem(citationItem.id);
- // create text for bubble
-
- // Creator
- var title, delimiter;
- var str = item.getField("firstCreator");
-
- // Title, if no creator (getDisplayTitle in order to get case, e-mail, statute which don't have a title field)
- title = item.getDisplayTitle();
- title = title.substr(0, 32) + (title.length > 32 ? "…" : "");
- if (!str) {
- str = Zotero.getString("punctuation.openingQMark") + title + Zotero.getString("punctuation.closingQMark");
- }
-
- // Date
- var date = item.getField("date", true, true);
- if(date && (date = date.substr(0, 4)) !== "0000") {
- str += ", " + parseInt(date);
- }
-
- // Locator
- if(citationItem.locator) {
- // Try to fetch the short form of the locator label. E.g. "p." for "page"
- // If there is no locator label, default to "page" for now
- let label = (Zotero.Cite.getLocatorString(citationItem.label || 'page', 'short') || '').toLocaleLowerCase();
-
- str += ", "+label+" "+citationItem.locator;
- }
-
- // Prefix
- if(citationItem.prefix && Zotero.CiteProc.CSL.ENDSWITH_ROMANESQUE_REGEXP) {
- let prefix = citationItem.prefix.substr(0, 10) + (citationItem.prefix.length > 10 ? "…" : "")
- str = prefix
- +(Zotero.CiteProc.CSL.ENDSWITH_ROMANESQUE_REGEXP.test(citationItem.prefix) ? " " : "")
- +str;
- }
-
- // Suffix
- if(citationItem.suffix && Zotero.CiteProc.CSL.STARTSWITH_ROMANESQUE_REGEXP) {
- let suffix = citationItem.suffix.substr(0, 10) + (citationItem.suffix.length > 10 ? "…" : "")
- str += (Zotero.CiteProc.CSL.STARTSWITH_ROMANESQUE_REGEXP.test(citationItem.suffix) ? " " : "")
- + suffix;
- }
-
- return str;
- }
-
- /**
- * Insert a bubble into the DOM at a specified position
- */
- function _insertBubble(citationItem, nextNode) {
- var str = _buildBubbleString(citationItem);
- let bubble = document.createElement("div");
- bubble.setAttribute("draggable", "true");
- bubble.setAttribute("role", "button");
- bubble.setAttribute("tabindex", "0");
- bubble.setAttribute("aria-describedby", "bubble-description");
- bubble.setAttribute("aria-haspopup", true);
- bubble.className = "citation-dialog bubble";
- // VoiceOver works better without it
- if (!Zotero.isMac) {
- bubble.setAttribute("aria-label", str);
- }
- bubble.textContent = str;
- bubble.addEventListener("click", _onBubbleClick);
- bubble.addEventListener("dragstart", _onBubbleDrag);
- bubble.addEventListener("dragend", onBubbleDragEnd);
- bubble.addEventListener("keypress", onBubblePress);
- bubble.addEventListener("mousedown", (_) => {
- _bubbleMouseDown = true;
- });
- bubble.addEventListener("mouseup", (_) => {
- _bubbleMouseDown = false;
- });
- bubble.dataset.citationItem = JSON.stringify(citationItem);
- editor.insertBefore(bubble, (nextNode ? nextNode : null));
- return bubble;
- }
-
- function getAllBubbles() {
- return [...editor.querySelectorAll(".bubble")];
- }
-
- // Delete the bubble and clear locator node if it pointed at this bubble
- function _deleteBubble(bubble) {
- if (bubble == locatorNode) {
- locatorNode = null;
- }
- bubble.remove();
- window.isPristine = false;
- }
-
- /**
- * Clear reference box
- */
- function _clearEntryList(skipResize = false) {
- while(referenceBox.hasChildNodes()) referenceBox.removeChild(referenceBox.firstChild);
- if (!skipResize) {
- _resizeReferencePanel();
- }
- referenceBox.selectedIndex = -1;
- }
-
- // Select the first appropriate reference from the items list.
- // If there are multi-selected items, select the first one of them.
- // Otherwise, select the first non-header row.
- function _selectFirstReference() {
- if (referenceBox.selectedIndex > 0) return;
- let firstItem = [...referenceBox.selectedItems].find(node => referenceBox.contains(node));
- if (firstItem) {
- referenceBox.selectedItem = firstItem;
- }
- else {
- referenceBox.selectedIndex = _selectItem(0);
- }
- }
-
- // Selects first valid item for index (avoiding headers)
- function _selectItem(index) {
- // Slice from index and select first non-header row
- let firstItem = [...referenceBox.children].slice(index).findIndex(node => !node.hasAttribute('disabled'));
- if (firstItem != -1) {
- referenceBox.selectedIndex = index + firstItem;
- return index + firstItem;
- }
- else {
- referenceBox.selectedIndex = -1;
- return -1;
- }
- }
-
- /**
- * Converts the selected item to a bubble
- */
- this._bubbleizeSelected = Zotero.Promise.coroutine(function* () {
- let input = _lastFocusedInput || _getCurrentInput();
- if (referenceBox.selectedCount == 0 || referencePanel.state !== 'open' || !input) return false;
- let lastAddedBubble;
- let multipleSelected = referenceBox.selectedCount > 1;
- // It is technically possible for referenceBox.selectedItems to include nodes that were removed
- // (e.g. during panel refreshing). This should never happen but this is a sanity check to make sure
- let selectedItems = [...referenceBox.selectedItems].filter(node => referenceBox.contains(node));
- for (let selectedItem of selectedItems) {
- let itemID = parseInt(selectedItem.getAttribute("zotero-item"));
- let item = { id: itemID };
- if (Zotero.Retractions.isRetracted(item)) {
- if (Zotero.Retractions.shouldShowCitationWarning(item)) {
- var ps = Services.prompt;
- var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
- + ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL
- + ps.BUTTON_POS_2 * ps.BUTTON_TITLE_IS_STRING;
- var checkbox = { value: false };
- var result = ps.confirmEx(null,
- Zotero.getString('general.warning'),
- Zotero.getString('retraction.citeWarning.text1') + '\n\n'
- + Zotero.getString('retraction.citeWarning.text2'),
- buttonFlags,
- Zotero.getString('general.continue'),
- null,
- Zotero.getString('pane.items.showItemInLibrary'),
- Zotero.getString('retraction.citationWarning.dontWarn'), checkbox);
- if (result > 0) {
- if (result == 2) {
- Zotero_QuickFormat.showInLibrary(itemID);
- }
- // Retraction should not be added
- referenceBox.removeItemFromSelection(selectedItem);
- return false;
- }
- if (checkbox.value) {
- Zotero.Retractions.disableCitationWarningsForItem(item);
- }
- }
- }
- }
- for (let selectedItem of selectedItems) {
- var citationItem = { id: selectedItem.getAttribute("zotero-item") };
- if (typeof citationItem.id === "string" && citationItem.id.indexOf("/") !== -1) {
- var item = Zotero.Cite.getItem(citationItem.id);
- citationItem.uris = item.cslURIs;
- citationItem.itemData = item.cslItemData;
- }
- if (currentLocator) {
- citationItem.locator = currentLocator;
- if (currentLocatorLabel) {
- citationItem.label = currentLocatorLabel;
- }
- }
- lastAddedBubble = _insertBubble(citationItem, input);
- }
- if (!lastAddedBubble) {
- return false;
- }
- isPaste = false;
- _clearEntryList();
- clearLastFocused(input);
- input.remove();
-
- yield _previewAndSort();
- refocusInput(false);
- // Do not record locator node if multiple bubbles are added
- if (!multipleSelected) {
- locatorNode = getAllBubbles().filter(bubble => bubble.textContent == lastAddedBubble.textContent)[0];
- }
- window.isPristine = false;
- return true;
- });
-
- /**
- * Ignores clicks (for use on separators in the rich list box)
- */
- function _ignoreClick(e) {
- e.stopPropagation();
- e.preventDefault();
- }
-
- // Set the editor's width so that it fills up all remaining space in the window.
- // It should be window.width - padding - icon wrappers width. The is needed to be explicitly set
- // so that the editor's height expands/shrinks vertically without going outside of the
- // window boundaries.
- function _resizeEditor() {
- let editorParentWidth = editor.parentNode.getBoundingClientRect().width;
- // Find the widths of all icon containers.
- // Quick format dialog has 2 sets of icons but insert note dialog has only one
- let iconWrappers = [...document.querySelectorAll(".citation-dialog.icons")];
- let iconWrapperWidth = iconWrappers.reduce((totalWidth, iconWrapper) => totalWidth + iconWrapper.getBoundingClientRect().width, 0);
- let editorDesiredWidth = editorParentWidth - iconWrapperWidth;
- // Sanity check: editor width should never be that small
- if (editorDesiredWidth > 700) {
- editor.style.width = `${editorDesiredWidth}px`;
- }
- }
- async function _resizeWindow(height, width) {
- let box = document.querySelector(".citation-dialog.entry");
- height = height || box.getBoundingClientRect().height;
- width = width || WINDOW_WIDTH;
- // Force resizing if there is no max height set on the window
- let maySkip = !!document.documentElement.style.maxHeight;
- if (Math.abs(height - window.innerHeight) < 5 && maySkip) {
- // Do not do anything if the difference is just a few pixels
- return;
- }
- // Remove height limitation to let the window resize
- document.documentElement.style.removeProperty("max-height");
- document.documentElement.style.removeProperty("min-height");
- // Need to wait a moment for the css change above to take effect (mainly for mac)
- await Zotero.Promise.delay(5);
- window.resizeTo(width, height);
- // Make sure the window's width cannot be changed by dragging the edge of the window
- document.documentElement.style.maxHeight = height + "px";
- document.documentElement.style.minHeight = height + "px";
- }
-
- function _resizeReferencePanel() {
- let visibleNodes = [];
- let countedItems = 0;
- // Fetch enough list items to include SHOWN_REFERENCES items
- for (let n of [...referenceBox.childNodes]) {
- visibleNodes.push(n);
- if (n.className === "citation-dialog item") {
- countedItems++;
- }
- if (countedItems >= SHOWN_REFERENCES) {
- break;
- }
- }
- // References should be shown whenever there are matching items
- let showReferencePanel = visibleNodes.length > 0;
- if (!showReferencePanel) {
- referencePanel.hidePopup();
- return;
- }
- _openReferencePanel();
- if (!panelFrameHeight) {
- panelFrameHeight = referencePanel.getBoundingClientRect().height - referencePanel.clientHeight;
- var computedStyle = window.getComputedStyle(referenceBox, null);
- for (var attr of ["border-top-width", "border-bottom-width"]) {
- var val = computedStyle.getPropertyValue(attr);
- if (val) {
- var m = pixelRe.exec(val);
- if (m) panelFrameHeight += parseInt(m[1], 10);
- }
- }
- }
- // Find the height needed to display SHOWN_REFERENCES items
- let height = visibleNodes.reduce((prev, cur) => {
- return prev + cur.scrollHeight + 1;
- }, 0);
- referencePanel.sizeTo(window.outerWidth - 30, height + panelFrameHeight);
- }
-
- /**
- * When bubbles are reshufled during drag-drop they may required X or X+1 lines of the editor.
- * Then the height of the window can get out-of-sync with the height of the editor.
- * To avoid the editor being cutoff by the window or having blank space below the editor,
- * this will lock the height of the editor until dragging is over.
- */
- function lockEditorHeight(isLocked) {
- if (isLocked) {
- let editorHeight = editor.getBoundingClientRect().height;
- editor.style.height = `${editorHeight}px`;
- editor.style['overflow-y'] = 'scroll';
- editor.style['scrollbar-width'] = 'none'; // avoid scrollbar/arrows
- return;
- }
- editor.style.removeProperty("height");
- editor.style.removeProperty("overflow-y");
- editor.style.removeProperty("scrollbar-width");
- }
-
- /**
- * Opens the reference panel
- */
- function _openReferencePanel() {
- var panelShowing = referencePanel.state === "open" || referencePanel.state === "showing";
-
- if (!panelShowing && !Zotero.isMac && !Zotero.isWin) {
- // noautohide and noautofocus are incompatible on Linux
- // https://bugzilla.mozilla.org/show_bug.cgi?id=545265
- referencePanel.setAttribute("noautohide", "false");
-
- // reinstate noautohide after the window is shown
- referencePanel.addEventListener("popupshowing", function() {
- referencePanel.removeEventListener("popupshowing", arguments.callee, false);
- referencePanel.setAttribute("noautohide", "true");
- }, false);
- }
- // Try to make the panel appear right in the center on windows
- let leftMargin = Zotero.isWin ? 10 : 15;
- referencePanel.openPopup(dialog, "after_start", leftMargin, 0, false, false, null);
- // Initially, panel has an opacity of 0.9 to prevent a shadow from appearing behind the
- // panel on Windows, but we override it upon the first opening of the panel
- referencePanel.style.opacity = "1";
- }
-
- /**
- * Clears all citations
- */
- function _clearCitation() {
- var citations = document.getElementsByClassName("citation-dialog bubble");
- while(citations.length) {
- citations[0].parentNode.removeChild(citations[0]);
- }
- }
-
- /**
- * Shows citations in the citation object
- */
- function _showCitation(insertBefore) {
- if(!io.citation.properties.unsorted
- && keepSorted && keepSorted.hasAttribute("checked")
- && io.citation.sortedItems
- && io.citation.sortedItems.length) {
- for(var i=0, n=io.citation.sortedItems.length; i _quickFormat())
- .then(() => {
- _searchPromise = null;
- spinner.removeAttribute("status");
- if (acceptButton) acceptButton.style.removeProperty("display");
- });
- }
-
- /**
- * Find the last bubble (lastBubble) before a given coordinate and indicate if there are no bubbles
- * to the left of the x-coordinate (startOfTheLine). If there is no last bubble, null is returned.
- * startOfTheLine indicates if a
should be added so that a new input placed after lastBubble
- * does not land on the previous line.
- * Outputs for a sample of coordiantes (with #3 having startOfTheLine=true):
- * NULL #1 #2 #3
- * ↓ ↓ ↓ ↓
- * [ bubble_1 bubble_2 bubble_3
- * bubble_4, bubble_5 ]
- * ↑ ↑ ↑ ↑
- * #3 #4 #5 #5
- * @param {Int} x - X coordinate
- * @param {Int} y - Y coordinate
- * @returns {lastBubble: Node, startOfTheLine: Bool}
- */
- function getLastBubbleBeforePoint(x, y) {
- let bubbles = getAllBubbles();
- let lastBubble = null;
- let startOfTheLine = false;
- let isClickAfterBubble = (clickX, bubbleRect) => {
- return Zotero.rtl ? clickX < bubbleRect.left : clickX > bubbleRect.right;
- };
- for (let i = 0; i < bubbles.length; i++) {
- let rect = bubbles[i].getBoundingClientRect();
- // If within the vertical range of a bubble
- if (y >= rect.top && y <= rect.bottom) {
- // If the click is after the bubble, it becomes a candidate
- if (isClickAfterBubble(x, rect)) {
- lastBubble = i;
- }
- // Otherwise, stop and return the last bubble we saw if any
- else {
- if (i == 0) {
- lastBubble = null;
- }
- else {
- // Indicate there is no bubble before this one
- startOfTheLine = lastBubble === null;
- lastBubble = Math.max(i - 1, 0);
- }
- break;
- }
- }
- }
- if (lastBubble !== null) {
- lastBubble = bubbles[lastBubble];
- }
- return { lastBubble: lastBubble, startOfTheLine: startOfTheLine };
- }
-
- function _onQuickSearchClick(event) {
- if (qfGuidance) qfGuidance.hide();
- if (!event.target.classList.contains("editor")) return;
- let clickX = event.clientX;
- let clickY = event.clientY;
- let { lastBubble, startOfTheLine } = getLastBubbleBeforePoint(clickX, clickY);
- // If click happened right before another input, focus that input
- // instead of adding another one. There may be a br node on the way, so we have to check
- // more than just the next node. If there is no lastBubble and there is an input
- // at the start of the editor, focus it.
- let nextNode = lastBubble ? lastBubble.nextElementSibling : editor.firstChild;
- while (nextNode && !nextNode.classList.contains("bubble")) {
- if (isInput(nextNode)) {
- nextNode.focus();
- return;
- }
- nextNode = nextNode.nextElementSibling;
- }
- let newInput = _createInputField();
- let currentInput = _getCurrentInput() || _lastFocusedInput;
- // If there is a current input, delete it here.
- // It can be handled by the "blur" event handler but it happens
- // after a small delay which causes bubbles to shift back and forth
- if (currentInput && isInputEmpty(currentInput)) {
- clearLastFocused(currentInput);
- currentInput.remove();
- }
- if (lastBubble !== null) {
- lastBubble.after(newInput);
- if (startOfTheLine) {
- let lineBreak = document.createElement("br");
- lastBubble.after(lineBreak);
- }
- }
- else {
- editor.prepend(newInput);
- }
- locatorNode = null;
- newInput.focus();
- }
-
- // Essentially a rewrite of default richlistbox arrow navigation
- // so that it works with voiceover on CMD-ArrowUp/Down
- var handleItemSelection = (event) => {
- let selected = referenceBox.contains(document.activeElement) ? document.activeElement : referenceBox.selectedItem;
- // Multiselect happens during arrowUp/Down navigation when Shift/Cmd is being held
- let selectMultiple = event.shiftKey || event.metaKey;
- let initiallySelected = null;
- if (referenceBox.contains(document.activeElement) && selectMultiple) {
- initiallySelected = selected;
- }
- let selectNext = (node) => {
- return event.key == "ArrowDown" ? node.nextElementSibling : node.previousElementSibling;
- };
- do {
- selected = selectNext(selected);
- referenceBox.ensureElementIsVisible(selected);
- }
- while (selected && selected.disabled);
- if (selected) {
- selected.focus();
- let multiSelected = [...referenceBox.selectedItems];
- if (selectMultiple) {
- // If the selected item is already selected, the previous one
- // should be un-selected
- if (multiSelected.includes(selected)) {
- referenceBox.removeItemFromSelection(initiallySelected);
- }
- else {
- referenceBox.addItemToSelection(selected);
- // If there are multiple selected items, focus the last one
- let following = selectNext(selected);
- while (following && following.selected) {
- following.focus();
- following = selectNext(following);
- }
- }
- }
- else {
- referenceBox.selectedItem = selected;
- }
- }
- };
-
-
- var onInputPress = function (event) {
- if (accepted) return;
- if ((event.charCode === 59 /* ; */ || (event.key === "Enter" && !event.shiftKey)) && referenceBox.selectedIndex >= 1) {
- event.preventDefault();
- event.stopPropagation();
- Zotero_QuickFormat._bubbleizeSelected();
- }
- else if (["ArrowLeft", "ArrowRight"].includes(event.key) && !event.shiftKey) {
- // On arrow left (right in RTL) from the beginning of the input, move to previous bubble
- if (event.key === Zotero.arrowPreviousKey && isCursorAtInputStart(this)) {
- moveFocusBack(this);
- event.preventDefault();
- }
- // On arrow right (left in RTL) from the end of the input, move to next bubble
- else if (event.key === Zotero.arrowNextKey && isCursorAtInputEnd(this)) {
- moveFocusForward(this);
- event.preventDefault();
- }
- }
- else if (["Backspace", "Delete"].includes(event.key)
- && (this.selectionStart + this.selectionEnd) === 0) {
- event.preventDefault();
- // Backspace/Delete from the beginning of an input will delete the previous bubble.
- // If there are two inputs next to each other as a result, they are merged
- let toDelete = Zotero.rtl ? this.nextElementSibling : this.previousElementSibling;
- if (toDelete) {
- _deleteBubble(toDelete);
- _combineNeighboringInputs();
- }
- // Rerun search to update opened documents section if needed
- _resetSearchTimer();
- }
- else if (["ArrowDown", "ArrowUp"].includes(event.key) && referencePanel.state === "open") {
- event.preventDefault();
- event.stopPropagation();
- // ArrowUp when item is selected does nothing
- if (referenceBox.selectedIndex < 1 && event.key == "ArrowUp") {
- return;
- }
- // Arrow up/down will navigate the references panel if that's opened
- if (referenceBox.selectedIndex < 1) {
- _selectFirstReference();
- referenceBox.selectedItem.focus();
- }
- else {
- handleItemSelection(event);
- }
- }
- else if (event.key == "Tab" && !event.shiftKey && referencePanel.state === "open") {
- // Tab from the input will focus the selected item in the references list
- event.preventDefault();
- event.stopPropagation();
- if (referenceBox.selectedIndex < 1) {
- _selectFirstReference();
- }
- referenceBox.selectedItem.focus();
- }
- };
-
- var onBubblePress = function(event) {
- if (accepted) return;
- if (event.key == "ArrowDown" || event.key == " ") {
- // On arrow down or whitespace, open new citation properties panel
- _showItemPopover(this);
- event.preventDefault();
- }
- else if (["ArrowLeft", "ArrowRight"].includes(event.key) && !event.shiftKey) {
- event.preventDefault();
- let newInput = _createInputField();
-
- if (event.key === Zotero.arrowPreviousKey) {
- if (isInput(this.previousElementSibling)) {
- moveFocusBack(this);
- }
- else {
- this.before(newInput);
- newInput.focus();
- }
- }
- else if (event.key === Zotero.arrowNextKey) {
- if (isInput(this.nextElementSibling)) {
- moveFocusForward(this);
- }
- else {
- this.after(newInput);
- newInput.focus();
- }
- }
- }
- else if (["ArrowLeft", "ArrowRight"].includes(event.key) && event.shiftKey) {
- // On Shift-Left/Right swap focused bubble with it's neighbor
- event.preventDefault();
- let findNextBubble = () => {
- let node = event.target;
- do {
- node = event.key == Zotero.arrowPreviousKey ? node.previousElementSibling : node.nextElementSibling;
- } while (node && !(node.classList.contains("bubble") || node.classList.contains("zotero-bubble-input")));
- return node;
- };
- let nextBubble = findNextBubble();
- if (nextBubble) {
- if (event.key === Zotero.arrowPreviousKey) {
- nextBubble.before(this);
- }
- else {
- nextBubble.after(this);
- }
- // Do not "Keep Sources Sorted"
- if (io.sortable && keepSorted?.hasAttribute("checked")) {
- keepSorted.removeAttribute("checked");
- }
- _previewAndSort();
- }
-
- this.focus();
- }
- else if (["Backspace", "Delete"].includes(event.key)) {
- event.preventDefault();
- if (!moveFocusBack(this)) {
- moveFocusForward(this);
- }
- _deleteBubble(this);
- // Removed item bubble may belong to opened documents section. Reference panel
- // needs to be reset so that it appears among other items.
- _clearEntryList();
- _combineNeighboringInputs();
- // If all bubbles are removed, add and focus an input
- if (getAllBubbles().length == 0) {
- refocusInput();
- }
- }
- else if (isKeypressPrintable(event) && event.key !== " ") {
- event.preventDefault();
- let input = refocusInput();
- // Typing when you are focused on the bubble will re-focus the last input
- input.value += event.key;
- input.dispatchEvent(new Event('input', { bubbles: true }));
- }
- };
-
- /**
- * Handle keyboard navigation not covered by other components
- */
- var _onQuickSearchKeyPress = Zotero.Promise.coroutine(function* (event) {
- // Prevent hang if another key is pressed after Enter
- // https://forums.zotero.org/discussion/59157/
- if (accepted) {
- event.preventDefault();
- return;
- }
- if(qfGuidance) qfGuidance.hide();
-
- var keyCode = event.keyCode;
- let focusedInput = _getCurrentInput();
- if (event.key == ' ') {
- // Space on toolbarbutton opens the popup
- if (event.target.tagName == "toolbarbutton") {
- event.target.firstChild.openPopup();
- }
- }
- // On Home from the beginning of the input, create and focus input in the beginning
- // If there is an input in the beginning already, just focus it
- else if (event.key === "Home"
- && (!focusedInput || (isCursorAtInputStart(focusedInput) && focusedInput.previousElementSibling))) {
- let input;
- if (isInput(editor.firstChild)) {
- input = editor.firstChild;
- }
- else {
- input = _createInputField();
- editor.prepend(input);
- }
- input.focus();
- }
- // On End from the beginning of the input, create and focus input in the end.
- // If there is an input in the end already, just focus it
- else if (event.key === "End"
- && (!focusedInput || (isCursorAtInputEnd(focusedInput) && focusedInput.nextElementSibling))) {
- let input;
- if (isInput(editor.childNodes[editor.childNodes.length - 1])) {
- input = editor.childNodes[editor.childNodes.length - 1];
- input.focus();
- }
- else {
- addInputToTheEnd();
- }
- }
- else if (keyCode == event.DOM_VK_TAB) {
- // Shift-Tab from the input field tries to focus on zotero icon dropdown
- if (event.shiftKey) {
- let icon = document.getElementById("zotero-icon");
- if (icon && icon.getAttribute("disabled") != "true") {
- icon.focus();
- event.preventDefault();
- return;
- }
- }
- // Tab places focus on the existing input or creates a new one in the end
- refocusInput();
-
- event.preventDefault();
- }
- // Shift-Enter will accept the existing dialog's state
- else if (keyCode == "Enter" && event.shiftKey) {
- event.preventDefault();
- event.stopPropagation();
- this.accept();
- }
- else {
- isPaste = false;
- }
- });
-
- // Dragging the bubble for drag-drop reordering
- function _onBubbleDrag(event) {
- this.style.cursor = "grabbing";
- // Sometimes due to odd mozilla drag-drop behavior, the dragend event may not fire
- // so the element will get stuck with the id. Clean it up on next dragstart if it happens.
- let lastDragged = document.querySelector("#dragged-bubble");
- if (lastDragged) {
- lastDragged.removeAttribute("id");
- }
- setTimeout(() => {
- this.setAttribute("id", "dragged-bubble");
- });
- bubbleDraggedIndex = _getBubbleIndex(this);
- event.dataTransfer.setData("zotero/citation_bubble", bubbleDraggedIndex);
- event.dataTransfer.effectAllowed = "move";
- event.stopPropagation();
-
- // Lock editors height till the drag is over
- lockEditorHeight(true);
- }
-
- // Bubble being dragged over the editor
- function _onEditorDragOver(event) {
- event.preventDefault();
- let draggedBubble = document.querySelector("#dragged-bubble");
- let bubble = event.target;
- // If the target is an editor, find the last bubble before
- // mouse location to insert the placeholder after it.
- // This handles an edge case if a bubble is dragged to an empty spot in the end of the editor.
- if (bubble.classList?.contains("editor")) {
- let { lastBubble, _ } = getLastBubbleBeforePoint(event.clientX, event.clientY);
- if (!lastBubble) {
- return false;
- }
- bubble = lastBubble;
- }
- if (!draggedBubble || bubbleDraggedIndex === null || !bubble.classList?.contains("bubble")) {
- return false;
- }
- if (bubble.getAttribute("id") == "dragged-bubble") {
- return true;
- }
-
- let bubbleRect = bubble.getBoundingClientRect();
- let midpoint = (bubbleRect.right + bubbleRect.left) / 2;
- // If dragged-bubble is placed over the right half of another bubble, insert placeholder after it.
- if (event.clientX > midpoint && bubble.nextElementSibling?.id !== "dragged-bubble") {
- bubble.after(draggedBubble);
- }
- // If dragged-bubble is placed over the left half of another bubble, insert placeholder before it.
- else if (event.clientX < midpoint && bubble.previousElementSibling?.id !== "dragged-bubble") {
- bubble.before(draggedBubble);
- }
- return false;
- }
-
- function onBubbleDragEnd(_) {
- bubbleDraggedIndex = null;
- let bubble = document.getElementById("dragged-bubble");
- if (bubble) {
- bubble.style = "";
- bubble.removeAttribute("id");
- }
- // Manual call to resize after delay to avoid strange mozilla behaviors that affect
- // subsequent drag events when resizing happens around the same time as drag events
- setTimeout(() => {
- _resizeWindow();
- }, 50);
- lockEditorHeight(false);
- }
-
- /**
- * Get index of bubble in citations
- */
- function _getBubbleIndex(bubble) {
- var nodes = editor.childNodes, index = 0;
- for (let node of nodes) {
- if (node.dataset && node.dataset.citationItem) {
- if (node == bubble) return index;
- index++;
- }
- }
- return -1;
- }
-
- /**
- * Drop dragged bubble into the editor
- */
- var _onEditorDrop = Zotero.Promise.coroutine(function* (event) {
- event.preventDefault();
- event.stopPropagation();
- let bubble = document.getElementById("dragged-bubble");
- if (bubbleDraggedIndex === null || !bubble) return;
-
- // If moved out of order, turn off "Keep Sources Sorted"
- if(io.sortable && keepSorted && keepSorted.hasAttribute("checked")
- && bubbleDraggedIndex != _getBubbleIndex(bubble)) {
- keepSorted.removeAttribute("checked");
- }
-
- onBubbleDragEnd();
- window.isPristine = false;
-
- yield _previewAndSort();
- });
-
- /**
- * Handle a click on a bubble
- */
- function _onBubbleClick(_) {
- // If citation properties dialog is opened for another bubble, just close it.
- if (panelRefersToBubble) {
- itemPopover.hidePopup();
- return;
- }
- _showItemPopover(this);
- }
-
- /**
- * Called when the user attempts to paste
- */
- function _onPaste(event) {
- event.stopPropagation();
- event.preventDefault();
-
- var str = Zotero.Utilities.Internal.getClipboard("text/plain");
- if (str) {
- isPaste = true;
- this.value += str.replace(/[\r\n]/g, " ").trim();
- let width = getContentWidth(this);
- this.style.width = width + 'px';
- // Move curor to the end
- this.setSelectionRange(str.length, str.length);
- _resetSearchTimer();
- }
- }
-
- /**
- * Handle changes to citation properties
- */
- this.onCitationPropertiesChanged = function(event) {
- window.isPristine = false;
- let citationItem = JSON.parse(panelRefersToBubble.dataset.citationItem || "{}");
- if(itemPopoverPrefix.value) {
- citationItem["prefix"] = itemPopoverPrefix.value;
- } else {
- delete citationItem["prefix"];
- }
- if(itemPopoverSuffix.value) {
- citationItem["suffix"] = itemPopoverSuffix.value;
- } else {
- delete citationItem["suffix"];
- }
- if(itemPopoverLocator.value) {
- citationItem["locator"] = itemPopoverLocator.value;
- citationItem["label"] = itemPopoverLocatorLabel.selectedItem.value;
- } else {
- delete citationItem["locator"];
- delete citationItem["label"];
- }
- if(itemPopoverSuppressAuthor.checked) {
- citationItem["suppress-author"] = true;
- } else {
- delete citationItem["suppress-author"];
- }
- panelRefersToBubble.dataset.citationItem = JSON.stringify(citationItem);
- panelRefersToBubble.textContent = _buildBubbleString(citationItem);
- };
-
- this.ignoreEvent = function (event) {
- event.stopPropagation();
- };
-
- /**
- * Handle closing citation properties panel
- */
- this.onItemPopoverClosed = function(event) {
- if (!panelRefersToBubble) {
- return;
- }
- panelRefersToBubble.removeAttribute("selected");
- Zotero_QuickFormat.onCitationPropertiesChanged();
- // On ArrowUp from the citation popup, keep focus on the bubble
- if (skipInputRefocus) {
- panelRefersToBubble.focus();
- skipInputRefocus = false;
- }
- else {
- refocusInput();
- }
- panelRefersToBubble = null;
- }
-
- /**
- * Keyboard navigation within citation properties dialog
- */
- this.onPanelKeyPress = function(event) {
- let stopEvent = () => {
- event.stopPropagation();
- event.preventDefault();
- };
- // Tabbing through the fields. This should not be necessary but for some reason
- // without manually handling focus, the buttons are skipped during tabbing
- if (event.key === "Tab") {
- event.preventDefault();
- let tabIndex = parseInt(event.target.closest("[tabindex]").getAttribute("tabindex"));
- tabIndex += event.shiftKey ? -1 : 1;
- if (tabIndex == 9) {
- tabIndex = 1;
- }
- if (tabIndex == 0) {
- tabIndex = 8;
- }
-
- itemPopover.querySelector(`[tabindex='${tabIndex}']`).focus();
- }
- // Space or enter triggers a click on buttons, checkboxes or menulist
- if (event.key == ' ' || event.key === "Enter") {
- if (event.target.tagName == "button"
- || event.target.getAttribute("type") == "checkbox") {
- event.target.click();
- return stopEvent();
- }
- else if (event.target.tagName == "menulist") {
- event.target.firstChild.openPopup();
- return stopEvent();
- }
- }
- // Arrow up closes the popup
- // (except on locator type dropdown to allow for default handling)
- if (event.key === "ArrowUp" && event.target.tagName !== "menulist") {
- skipInputRefocus = true;
- itemPopover.hidePopup();
- return stopEvent();
- }
- // Close on Escape or Enter and record when it happened to throttle the next
- // window close attempt
- if (["Enter", "Escape"].includes(event.key)) {
- _itemPopoverClosed = new Date();
- itemPopover.hidePopup();
- }
- };
-
- /**
- * Handle checking/unchecking "Keep Citations Sorted"
- */
- this.onKeepSortedCommand = function(event) {
- _previewAndSort();
- };
-
- /**
- * Open classic Add Citation window
- */
- this.onClassicViewCommand = function(event) {
- _updateCitationObject();
- var newWindow = window.newWindow = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
- .getService(Components.interfaces.nsIWindowWatcher)
- .openWindow(null, 'chrome://zotero/content/integration/addCitationDialog.xhtml',
- '', 'chrome,centerscreen,resizable', io);
- newWindow.addEventListener("focus", function() {
- newWindow.removeEventListener("focus", arguments.callee, true);
- window.close();
- }, true);
- accepted = true;
- }
-
- /**
- * Show an item in the library it came from
- */
- this.showInLibrary = async function (itemID) {
- let citationItem = JSON.parse(panelRefersToBubble?.dataset.citationItem || "{}");
- var id = itemID || citationItem.id;
- Zotero.Utilities.Internal.showInLibrary(id);
- }
-
- /**
- * Resizes windows
- * @constructor
- */
- var Resizer = function(panel, targetWidth, targetHeight, pixelsPerStep, stepsPerSecond) {
- this.panel = panel;
- this.curWidth = panel.clientWidth;
- this.curHeight = panel.clientHeight;
- this.difX = (targetWidth ? targetWidth - this.curWidth : 0);
- this.difY = (targetHeight ? targetHeight - this.curHeight : 0);
- this.step = 0;
- this.steps = Math.ceil(Math.max(Math.abs(this.difX), Math.abs(this.difY))/pixelsPerStep);
- this.timeout = (1000/stepsPerSecond);
-
- var me = this;
- this._animateCallback = function() { me.animate() };
- };
-
- /**
- * Performs a step of the animation
- */
- Resizer.prototype.animate = function() {
- if(this.stopped) return;
- this.step++;
- this.panel.sizeTo(this.curWidth+Math.round(this.step*this.difX/this.steps),
- this.curHeight+Math.round(this.step*this.difY/this.steps));
- if(this.step !== this.steps) {
- window.setTimeout(this._animateCallback, this.timeout);
- }
- };
-
- /**
- * Halts resizing
- */
- Resizer.prototype.stop = function() {
- this.stopped = true;
- };
-}
-
-window.cancel = Zotero_QuickFormat.cancel;
-
-window.addEventListener("DOMContentLoaded", Zotero_QuickFormat.onDOMContentLoaded, false);
-window.addEventListener("load", Zotero_QuickFormat.onLoad, false);
diff --git a/chrome/content/zotero/integration/quickFormat.xhtml b/chrome/content/zotero/integration/quickFormat.xhtml
deleted file mode 100644
index c97ee78d30..0000000000
--- a/chrome/content/zotero/integration/quickFormat.xhtml
+++ /dev/null
@@ -1,124 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/chrome/content/zotero/xpcom/editorInstance.js b/chrome/content/zotero/xpcom/editorInstance.js
index 66c08fe80a..affd0253d2 100644
--- a/chrome/content/zotero/xpcom/editorInstance.js
+++ b/chrome/content/zotero/xpcom/editorInstance.js
@@ -66,7 +66,7 @@ class EditorInstance {
this._state = options.state;
this._disableSaving = false;
this._subscriptions = [];
- this._quickFormatWindow = null;
+ this._citationDialogWindow = null;
this._citationItemsList = [];
this._initPromise = new Promise((resolve, reject) => {
this._resolveInitPromise = resolve;
@@ -205,9 +205,9 @@ class EditorInstance {
async uninit() {
this._prefObserverIDs.forEach(id => Zotero.Prefs.unregisterObserver(id));
- if (this._quickFormatWindow) {
- this._quickFormatWindow.close();
- this._quickFormatWindow = null;
+ if (this._citationDialogWindow) {
+ this._citationDialogWindow.close();
+ this._citationDialogWindow = null;
}
this._iframeWindow.removeEventListener('message', this._messageHandler);
this.saveSync();
@@ -628,7 +628,7 @@ class EditorInstance {
}
}
let libraryID = this._item.libraryID;
- this._openQuickFormatDialog(nodeID, citation, [libraryID], openedEmpty);
+ this._openCitationDialog(nodeID, citation, [libraryID], openedEmpty);
return;
}
case 'importImages': {
@@ -1038,14 +1038,13 @@ class EditorInstance {
});
}
- // TODO: Allow only one quickFormat dialog
- async _openQuickFormatDialog(nodeID, citationData, filterLibraryIDs, openedEmpty) {
+ async _openCitationDialog(nodeID, citationData, filterLibraryIDs, openedEmpty) {
await Zotero.Styles.init();
let that = this;
let win;
/**
- * Citation editing functions and properties accessible to quickFormat.js and addCitationDialog.js
+ * Citation editing functions and properties accessible to citationDialog.js
*/
let CI = function (citation) {
this.citation = citation;
@@ -1059,10 +1058,10 @@ class EditorInstance {
CI.prototype = {
/**
- * 1) Provide `quickFormat` dialog with items created from
+ * 1) Provide citation dialog with items created from
* `itemData`, without dealing with `Zotero.Integration.sessions`
*
- * 2) Allow to pick already cited item from `quickFormat` dropdown
+ * 2) Allow to pick already cited item from citation dialog
*
* @param citationItem
* @returns {Zotero.Item|undefined}
@@ -1072,7 +1071,7 @@ class EditorInstance {
let citedItem = typeof citationItem.id === 'string'
&& this.citedItems[parseInt(citationItem.id.split('cited:')[1])];
- // Return cited item picked in `quickFormat` dropdown
+ // Return cited item picked in citation dialog
if (citedItem) {
return citedItem.item;
}
@@ -1179,7 +1178,7 @@ class EditorInstance {
let item = new Zotero.Item();
Zotero.Utilities.itemFromCSLJSON(item, citationItem.itemData);
// This is the only way to pass our custom id for already cited
- // items, without modifying `quickFormat` dialog too much.
+ // items, without modifying citationDialog.js too much.
// Must not contain `/`
item.cslItemID = 'cited:' + items.length;
items.push({ item, citationItem });
@@ -1244,9 +1243,9 @@ class EditorInstance {
}
};
- if (that._quickFormatWindow) {
- that._quickFormatWindow.close();
- that._quickFormatWindow = null;
+ if (that._citationDialogWindow) {
+ that._citationDialogWindow.close();
+ that._citationDialogWindow = null;
}
let citation = new Citation();
@@ -1267,7 +1266,7 @@ class EditorInstance {
mode += ",alwaysRaised";
}
- win = that._quickFormatWindow = Components.classes['@mozilla.org/embedcomp/window-watcher;1']
+ win = that._citationDialogWindow = Components.classes['@mozilla.org/embedcomp/window-watcher;1']
.getService(Components.interfaces.nsIWindowWatcher)
.openWindow(null, 'chrome://zotero/content/integration/citationDialog.xhtml', '', mode, {
wrappedJSObject: io
@@ -1630,7 +1629,7 @@ class EditorInstanceUtilities {
}
/**
- * Build citation item preview string (based on _buildBubbleString in quickFormat.js)
+ * Build citation item preview string (based on buildBubbleString in citationDialog/helpers.js)
* TODO: Try to avoid duplicating this code here and inside note-editor
*/
_formatCitationItemPreview(citationItem) {
diff --git a/chrome/content/zotero/xpcom/integration.js b/chrome/content/zotero/xpcom/integration.js
index 235ee6aa38..842c601267 100644
--- a/chrome/content/zotero/xpcom/integration.js
+++ b/chrome/content/zotero/xpcom/integration.js
@@ -1719,7 +1719,7 @@ Zotero.Integration.Session.prototype._insertItemsIntoDocument = async function (
};
/**
- * Citation editing functions and propertiesaccessible to quickFormat.js and addCitationDialog.js
+ * Citation editing functions and propertiesaccessible to citationDialog.js
*/
Zotero.Integration.CitationEditInterface = function(items, sortable, fieldIndexPromise,
citationsByItemIDPromise, previewFn){
@@ -1729,7 +1729,7 @@ Zotero.Integration.CitationEditInterface = function(items, sortable, fieldIndexP
this._fieldIndexPromise = fieldIndexPromise;
this._citationsByItemIDPromise = citationsByItemIDPromise;
- // Not available in quickFormat.js if this unspecified
+ // Not available in citationDialog.js if this unspecified
this.wrappedJSObject = this;
this._acceptDeferred = Zotero.Promise.defer();
diff --git a/chrome/locale/en-US/zotero/integration.ftl b/chrome/locale/en-US/zotero/integration.ftl
index 0ca32da38a..3ab18dd94e 100644
--- a/chrome/locale/en-US/zotero/integration.ftl
+++ b/chrome/locale/en-US/zotero/integration.ftl
@@ -18,8 +18,6 @@ integration-editBibliography-wrapper =
.aria-description = { -integration-editBibliography-include-uncited }
{ -integration-editBibliography-exclude-cited }
{ -integration-editBibliography-edit-reference }
-integration-quickFormatDialog-window =
- .title = { -app-name } - Quick Format Citation
integration-citationDialog = Citation Dialog
integration-citationDialog-section-open = Open Documents ({ $count })
integration-citationDialog-section-selected = Selected Items ({ $count }/{ $total })
diff --git a/chrome/locale/en-US/zotero/preferences.dtd b/chrome/locale/en-US/zotero/preferences.dtd
index 04d6536a81..bab94eac55 100644
--- a/chrome/locale/en-US/zotero/preferences.dtd
+++ b/chrome/locale/en-US/zotero/preferences.dtd
@@ -118,7 +118,6 @@
-
diff --git a/chrome/locale/en-US/zotero/zotero.dtd b/chrome/locale/en-US/zotero/zotero.dtd
index 8d4fdbade0..30ded46bf0 100644
--- a/chrome/locale/en-US/zotero/zotero.dtd
+++ b/chrome/locale/en-US/zotero/zotero.dtd
@@ -170,7 +170,6 @@
-
diff --git a/chrome/locale/en-US/zotero/zotero.ftl b/chrome/locale/en-US/zotero/zotero.ftl
index fa74e2a487..379922383f 100644
--- a/chrome/locale/en-US/zotero/zotero.ftl
+++ b/chrome/locale/en-US/zotero/zotero.ftl
@@ -585,25 +585,6 @@ toggle-preview =
*[unknown] Toggle
} Attachment Preview
-quickformat-general-instructions = Use Left/Right Arrow to navigate the items of this citation. {
- $dialogMenu ->
- [active] Press Shift-Tab to focus the dialog's menu.
- *[other] { "" }
-} Press { return-or-enter } to save edits to this citation. Press Escape to discard the changes and close the dialog.
-
-quickformat-aria-bubble = This item is included in the citation. Press space bar to customize the item. { quickformat-general-instructions }
-quickformat-aria-input = Type to search for an item to include in this citation. Press Tab to navigate the list of search results. { quickformat-general-instructions }
-quickformat-aria-item = Press { return-or-enter } to add this item to the citation. Press Tab to go back to the search field.
-quickformat-accept =
- .tooltiptext = Save edits to this citation
-quickformat-locator-type =
- .aria-label = Locator type
-quickformat-locator-value = Locator
-quickformat-citation-options =
- .tooltiptext = Show citation options
-
-insert-note-aria-input = Type to search for a note. Press Tab to navigate the list of results. Press Escape to close the dialog.
-insert-note-aria-item = Press { return-or-enter } to select this note. Press Tab to go back to the search field. Press Escape to close the dialog.
quicksearch-mode =
.aria-label = Quick Search mode
quicksearch-input =
@@ -667,12 +648,6 @@ architecture-warning-action = Download 64-bit { -app-name }
architecture-x64-on-arm64-message = { -app-name } is running in emulated mode. A native version of { -app-name } will run more efficiently.
architecture-x64-on-arm64-action = Download { -app-name } for ARM64
-first-run-guidance-quickFormat = Type a title, author, and/or year to search for a reference.
-
- After you’ve made your selection, click the bubble or select it via the keyboard and press ↓/Space to show citation options such as page number, prefix, and suffix.
-
- You can also add a page number directly by including it with your search terms or typing it after the bubble and pressing { return-or-enter }.
-
first-run-guidance-authorMenu = { -app-name } lets you specify editors and translators too. You can turn an author into an editor or translator by selecting from this menu.
advanced-search-remove-btn =
diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties
index a5e44cc602..7981a4bcad 100644
--- a/chrome/locale/en-US/zotero/zotero.properties
+++ b/chrome/locale/en-US/zotero/zotero.properties
@@ -1228,8 +1228,6 @@ standalone.updateMessage = A recommended update is available, but you do not h
connector.name = %S Connector
connector.error.title = Zotero Connector Error
-firstRunGuidance.quickFormat = Type a title or author to search for a reference.\n\nAfter you've made your selection, click the bubble or press Ctrl-\u2193 to add page numbers, prefixes, or suffixes. You can also include a page number along with your search terms to add it directly.\n\nYou can edit citations directly in the word processor document.
-firstRunGuidance.quickFormatMac = Type a title or author to search for a reference.\n\nAfter you've made your selection, click the bubble or press Cmd-\u2193 to add page numbers, prefixes, or suffixes. You can also include a page number along with your search terms to add it directly.\n\nYou can edit citations directly in the word processor document.
firstRunGuidance.toolbarButton.new = Click the ‘Z’ button to open Zotero, or use the %S keyboard shortcut.
firstRunGuidance.toolbarButton.upgrade = The Zotero icon can now be found in the Firefox toolbar. Click the icon to open Zotero, or use the %S keyboard shortcut.
firstRunGuidance.saveButton = Click this button to save any web page to your Zotero library. On some pages, Zotero will be able to save full details, including author and date.
diff --git a/test/tests/integrationTest.js b/test/tests/integrationTest.js
index 6bd4d22d90..fd9a0c4b17 100644
--- a/test/tests/integrationTest.js
+++ b/test/tests/integrationTest.js
@@ -485,7 +485,7 @@ describe("Zotero.Integration", function () {
displayAlertStub.resolves(0);
yield execCommand('addEditCitation', docID);
assert.isTrue(displayAlertStub.calledOnce);
- // Prefs to select a new style and quickFormat
+ // Prefs to select a new style
assert.isTrue(displayDialogStub.calledTwice);
assert.isNotOk(Zotero.Styles.get(style.styleID));
});