Make existing edit context menus more context-aware

- Don't show the default text editing context menu when right-clicking
  an unfocused editable-text
- In item box/header context menus, only show Copy and Paste (plus
  field-specific transform options) when unfocused

Fixes #3619
This commit is contained in:
Abe Jellinek 2024-01-29 13:15:23 -05:00 committed by Dan Stillman
parent a33603d496
commit fa6e6f9458
5 changed files with 77 additions and 33 deletions

View file

@ -218,6 +218,18 @@
this._input.blur();
}
});
input.addEventListener('mousedown', (event) => {
// Prevent a right-click from focusing the input when unfocused
if (event.button === 2 && document.activeElement !== this._input) {
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;

View file

@ -628,7 +628,7 @@
document.popupNode = rowLabel.parentElement;
let menupopup = this._id('zotero-link-menu');
Zotero.Utilities.Internal.updateEditContextMenu(menupopup, !event.target.closest('input'));
Zotero.Utilities.Internal.updateEditContextMenu(menupopup, event.target.closest('input'));
this.handlePopupOpening(event, menupopup);
};
}
@ -648,9 +648,8 @@
optionsButton.setAttribute('data-l10n-id', "itembox-button-options");
// eslint-disable-next-line no-loop-func
let triggerPopup = (e) => {
let oldValue = valueElement.value;
let menupopup = ZoteroItemPane.buildFieldTransformMenu({
value: oldValue,
target: valueElement,
onTransform: (newValue) => {
this._setFieldTransformedValue(valueElement, newValue);
}
@ -1071,8 +1070,7 @@
document.popupNode = firstlast;
let menupopup = this._id('zotero-creator-transform-menu');
let hideEditMenuItems = !e.target.closest('input');
Zotero.Utilities.Internal.updateEditContextMenu(menupopup, hideEditMenuItems);
Zotero.Utilities.Internal.updateEditContextMenu(menupopup, e.target.closest('input'));
this._id('creator-transform-swap-names').hidden = fieldMode > 0;
this._id('creator-transform-capitalize').disabled = !this.canCapitalizeCreatorName(rowData.parentNode);

View file

@ -85,13 +85,11 @@
if (!this._item) return;
event.preventDefault();
let oldValue = this.titleField.value;
let menupopup = ZoteroItemPane.buildFieldTransformMenu({
value: oldValue,
target: this.titleField,
onTransform: (newValue) => {
this._setTransformedValue(oldValue, newValue);
this._setTransformedValue(newValue);
},
includeEditMenuOptions: true
});
this.ownerDocument.querySelector('popupset').append(menupopup);
menupopup.addEventListener('popuphidden', () => menupopup.remove());
@ -111,7 +109,7 @@
}
}
async _setTransformedValue(oldValue, newValue) {
async _setTransformedValue(newValue) {
await this.blurOpenField();
this._item.setField(this._titleFieldID, newValue);
let shortTitleVal = this._item.getField('shortTitle');

View file

@ -325,15 +325,12 @@ var ZoteroItemPane = new function() {
};
this.buildFieldTransformMenu = function ({ value, onTransform, includeEditMenuOptions = false }) {
this.buildFieldTransformMenu = function ({ target, onTransform }) {
let value = target.value;
let valueTitleCased = Zotero.Utilities.capitalizeTitle(value.toLowerCase(), true);
let valueSentenceCased = Zotero.Utilities.sentenceCase(value);
let menupopup = document.createXULElement('menupopup');
if (includeEditMenuOptions) {
Zotero.Utilities.Internal.updateEditContextMenu(menupopup);
menupopup.append(document.createXULElement('menuseparator'));
}
let titleCase = document.createXULElement('menuitem');
titleCase.setAttribute('label', Zotero.getString('zotero.item.textTransform.titlecase'));
@ -351,6 +348,8 @@ var ZoteroItemPane = new function() {
sentenceCase.disabled = valueSentenceCased == value;
menupopup.append(sentenceCase);
Zotero.Utilities.Internal.updateEditContextMenu(menupopup, target);
return menupopup;
};
};

View file

@ -2329,7 +2329,10 @@ Zotero.Utilities.Internal = {
return scrollbarWidth;
},
updateEditContextMenu(menupopup, hideEditMenuItems = false) {
updateEditContextMenu(menupopup, target = null) {
let win = menupopup.ownerDocument.defaultView;
win.goUpdateGlobalEditMenuItems(true);
for (let menuitem of Array.from(menupopup.children)) {
if (!menuitem.hasAttribute('data-edit-menu-item')) {
break;
@ -2337,24 +2340,58 @@ Zotero.Utilities.Internal = {
menuitem.remove();
}
let win = menupopup.ownerDocument.defaultView;
let editPopup = win.goBuildEditContextMenu();
let editMenuItems = Array.from(editPopup.children).map((menuitem) => {
menuitem = menuitem.cloneNode(true);
menuitem.setAttribute('data-edit-menu-item', 'true');
if (hideEditMenuItems) {
menuitem.hidden = true;
}
return menuitem;
});
if (!hideEditMenuItems && menupopup.childElementCount) {
let separator = win.document.createXULElement('menuseparator');
separator.setAttribute('data-edit-menu-item', 'true');
editMenuItems.push(separator);
if (target && target.tagName === 'editable-text') {
target = target.ref;
}
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 editMenuItems = [];
if (showEdit) {
let editPopup = win.goBuildEditContextMenu();
for (let menuitem of editPopup.children) {
menuitem = menuitem.cloneNode(true);
menuitem.setAttribute('data-edit-menu-item', 'true');
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);
}
}
if (editMenuItems.length) {
if (menupopup.childElementCount) {
let separator = win.document.createXULElement('menuseparator');
separator.setAttribute('data-edit-menu-item', 'true');
menupopup.prepend(separator);
}
menupopup.prepend(...editMenuItems);
}
menupopup.prepend(...editMenuItems);
win.goUpdateGlobalEditMenuItems(true);
}
};