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:
parent
a33603d496
commit
fa6e6f9458
5 changed files with 77 additions and 33 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue