diff --git a/chrome/content/zotero/editMenuOverlay.js b/chrome/content/zotero/editMenuOverlay.js
index 340f09fcf1..47a1ad53d6 100644
--- a/chrome/content/zotero/editMenuOverlay.js
+++ b/chrome/content/zotero/editMenuOverlay.js
@@ -101,16 +101,16 @@ function goBuildEditContextMenu() {
MozXULElement.parseXULToFragment(`
`)
diff --git a/chrome/content/zotero/elements/editableText.js b/chrome/content/zotero/elements/editableText.js
index 4ed10e0213..35f398c60a 100644
--- a/chrome/content/zotero/elements/editableText.js
+++ b/chrome/content/zotero/elements/editableText.js
@@ -224,12 +224,6 @@
event.preventDefault();
}
});
- input.addEventListener('contextmenu', (event) => {
- // Prevent the text editing context menu from opening when unfocused
- if (document.activeElement !== this._input) {
- event.preventDefault();
- }
- });
let focused = false;
let selectionStart = this._input?.selectionStart;
@@ -298,4 +292,33 @@
}
}
customElements.define("editable-text", EditableText);
+
+ document.addEventListener('contextmenu', (event) => {
+ if (event.defaultPrevented
+ || !event.target.closest('editable-text')
+ || document.activeElement && event.target.contains(document.activeElement)) {
+ return;
+ }
+
+ event.preventDefault();
+
+ let editableText = event.target.closest('editable-text');
+ let menupopup = document.getElementById('zotero-editable-text-menu');
+ if (!menupopup) {
+ menupopup = document.createXULElement('menupopup');
+ menupopup.id = 'zotero-editable-text-menu';
+
+ let popupset = document.querySelector('popupset');
+ if (!popupset) {
+ popupset = document.createXULElement('popupset');
+ document.documentElement.append(popupset);
+ }
+ popupset.append(menupopup);
+ }
+
+ menupopup.addEventListener('popupshowing', () => {
+ Zotero.Utilities.Internal.updateEditContextMenu(menupopup, editableText);
+ }, { once: true });
+ menupopup.openPopupAtScreen(event.screenX + 1, event.screenY + 1, true);
+ });
}
diff --git a/chrome/content/zotero/elements/itemBox.js b/chrome/content/zotero/elements/itemBox.js
index 1a0f61cb7d..d0f5ce2861 100644
--- a/chrome/content/zotero/elements/itemBox.js
+++ b/chrome/content/zotero/elements/itemBox.js
@@ -95,7 +95,7 @@
-
+
@@ -207,9 +207,24 @@
event => this.capitalizeCreatorName(event));
this._linkMenu.addEventListener('popupshowing', () => {
- let disabled = !this._linkMenu.dataset.link;
- this._id('zotero-link-menu-view-online').disabled = disabled;
- this._id('zotero-link-menu-copy').disabled = disabled;
+ let menu = this._linkMenu;
+ let link = menu.dataset.link;
+ let val = menu.dataset.val;
+
+ let viewOnline = this._id('zotero-link-menu-view-online');
+ let copy = this._id('zotero-link-menu-copy');
+
+ viewOnline.disabled = !link;
+ copy.disabled = !link;
+ copy.hidden = link === val;
+
+ let existingCopyMenuitem = menu.querySelector('menuitem[data-action="copy"]');
+ if (existingCopyMenuitem) {
+ existingCopyMenuitem.after(copy);
+ }
+ else {
+ menu.append(copy);
+ }
});
this._id('zotero-link-menu-view-online').addEventListener(
@@ -535,12 +550,11 @@
}
}
- for (let i = 0; i < fieldNames.length; i++) {
- var fieldName = fieldNames[i];
+ for (let fieldName of fieldNames) {
if (this._ignoreFields.includes(fieldName)) {
continue;
}
- var val = '';
+ let val = '';
if (fieldName) {
var fieldID = Zotero.ItemFields.getID(fieldName);
@@ -604,13 +618,13 @@
}
let openLinkButton;
let link = val;
- let addContextMenu = false;
+ let addLinkContextMenu = false;
// TEMP - NSF (homepage)
if ((fieldName == 'url' || fieldName == 'homepage')
// Only make plausible HTTP URLs clickable
&& Zotero.Utilities.isHTTPURL(val, true)) {
openLinkButton = this.createOpenLinkIcon(val);
- addContextMenu = true;
+ addLinkContextMenu = true;
}
else if (fieldName == 'DOI' && val && typeof val == 'string') {
// Pull out DOI, in case there's a prefix
@@ -625,7 +639,7 @@
.replace(/"/g, '%22');
openLinkButton = this.createOpenLinkIcon(doi);
link = doi;
- addContextMenu = true;
+ addLinkContextMenu = true;
}
}
let rowData = document.createElement('div');
@@ -634,9 +648,10 @@
if (openLinkButton) {
rowData.appendChild(openLinkButton);
}
- if (addContextMenu) {
+ if (addLinkContextMenu) {
rowData.oncontextmenu = (event) => {
this._linkMenu.dataset.link = link;
+ this._linkMenu.dataset.val = val;
document.popupNode = rowLabel.parentElement;
let menupopup = this._id('zotero-link-menu');
@@ -2405,7 +2420,9 @@
}
handlePopupOpening(event, popup) {
+ event.preventDefault();
event.stopPropagation();
+
let isRightClick = event.type == 'contextmenu';
if (!isRightClick) {
event.target.style.visibility = "visible";
diff --git a/chrome/content/zotero/xpcom/utilities_internal.js b/chrome/content/zotero/xpcom/utilities_internal.js
index c7ea5a7943..3dee2310a1 100644
--- a/chrome/content/zotero/xpcom/utilities_internal.js
+++ b/chrome/content/zotero/xpcom/utilities_internal.js
@@ -2334,10 +2334,9 @@ Zotero.Utilities.Internal = {
win.goUpdateGlobalEditMenuItems(true);
for (let menuitem of Array.from(menupopup.children)) {
- if (!menuitem.hasAttribute('data-edit-menu-item')) {
- break;
+ if (menuitem.hasAttribute('data-edit-menu-item')) {
+ menuitem.remove();
}
- menuitem.remove();
}
if (target && target.tagName === 'editable-text') {
@@ -2345,11 +2344,9 @@ Zotero.Utilities.Internal = {
}
let targetInput = target?.closest('input, textarea');
let showEdit = targetInput
- && !targetInput.readOnly
&& targetInput.ownerDocument.activeElement
&& targetInput.ownerDocument.activeElement === targetInput;
- let showCopyField = targetInput && !showEdit;
- let showPasteField = showCopyField && !targetInput.readOnly;
+ let disablePasteField = targetInput && targetInput.readOnly;
let editMenuItems = [];
if (showEdit) {
@@ -2360,29 +2357,34 @@ Zotero.Utilities.Internal = {
editMenuItems.push(menuitem);
}
}
- else {
- if (showCopyField) {
- let copyMenuitem = win.document.createXULElement('menuitem');
- copyMenuitem.setAttribute('data-l10n-id', 'text-action-copy');
- copyMenuitem.setAttribute('data-edit-menu-item', 'true');
- copyMenuitem.disabled = !targetInput.value;
- copyMenuitem.addEventListener('command', () => {
- Zotero.Utilities.Internal.copyTextToClipboard(targetInput.value);
- });
- editMenuItems.push(copyMenuitem);
- }
- if (showPasteField) {
- let pasteMenuitem = win.document.createXULElement('menuitem');
- pasteMenuitem.setAttribute('data-l10n-id', 'text-action-paste');
- pasteMenuitem.setAttribute('data-edit-menu-item', 'true');
- pasteMenuitem.disabled = win.document.getElementById('cmd_paste')?.disabled;
- pasteMenuitem.addEventListener('command', () => {
- targetInput.focus();
- targetInput.value = Zotero.Utilities.Internal.getClipboard('text/unicode') || '';
- targetInput.dispatchEvent(new Event('input'));
- });
- editMenuItems.push(pasteMenuitem);
- }
+ else if (targetInput) {
+ let targetInputWeak = new WeakRef(targetInput);
+
+ let copyMenuitem = win.document.createXULElement('menuitem');
+ copyMenuitem.setAttribute('data-l10n-id', 'text-action-copy');
+ copyMenuitem.setAttribute('data-edit-menu-item', 'true');
+ copyMenuitem.setAttribute('data-action', 'copy');
+ copyMenuitem.disabled = !targetInput.value;
+ copyMenuitem.addEventListener('command', () => {
+ let targetInput = targetInputWeak.deref();
+ if (!targetInput) return;
+ Zotero.Utilities.Internal.copyTextToClipboard(targetInput.value);
+ });
+ editMenuItems.push(copyMenuitem);
+
+ let pasteMenuitem = win.document.createXULElement('menuitem');
+ pasteMenuitem.setAttribute('data-l10n-id', 'text-action-paste');
+ pasteMenuitem.setAttribute('data-edit-menu-item', 'true');
+ pasteMenuitem.setAttribute('data-action', 'paste');
+ pasteMenuitem.disabled = disablePasteField || win.document.getElementById('cmd_paste')?.disabled;
+ pasteMenuitem.addEventListener('command', () => {
+ let targetInput = targetInputWeak.deref();
+ if (!targetInput) return;
+ targetInput.focus();
+ targetInput.value = Zotero.Utilities.Internal.getClipboard('text/unicode') || '';
+ targetInput.dispatchEvent(new Event('input'));
+ });
+ editMenuItems.push(pasteMenuitem);
}
if (editMenuItems.length) {
if (menupopup.childElementCount) {