editable-text: Make dropping text work when field is unfocused (#3730)

This commit is contained in:
Abe Jellinek 2024-03-12 01:38:00 -04:00 committed by GitHub
parent 5489b6cc4b
commit c31a40c749
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 52 additions and 8 deletions

View file

@ -114,9 +114,13 @@
let abstract = this.item.getField('abstractNote'); let abstract = this.item.getField('abstractNote');
this._section.summary = abstract; this._section.summary = abstract;
if (!this._abstractField.initialValue || this._abstractField.initialValue !== abstract) { // If focused, update the value that will be restored on Escape;
// otherwise, update the displayed value
if (this._abstractField.focused) {
this._abstractField.initialValue = abstract;
}
else {
this._abstractField.value = abstract; this._abstractField.value = abstract;
this._abstractField.initialValue = '';
} }
this._abstractField.readOnly = this._mode == 'view'; this._abstractField.readOnly = this._mode == 'view';
this._abstractField.setAttribute('aria-label', Zotero.ItemFields.getLocalizedString('abstractNote')); this._abstractField.setAttribute('aria-label', Zotero.ItemFields.getLocalizedString('abstractNote'));

View file

@ -109,11 +109,11 @@
} }
get initialValue() { get initialValue() {
return this._input?.dataset.initialValue || ''; return this._input?.dataset.initialValue ?? '';
} }
set initialValue(initialValue) { set initialValue(initialValue) {
this._input.dataset.initialValue = initialValue || ''; this._input.dataset.initialValue = initialValue ?? '';
} }
get autocomplete() { get autocomplete() {
@ -204,7 +204,7 @@
input.addEventListener('change', handleChange); input.addEventListener('change', handleChange);
input.addEventListener('focus', () => { input.addEventListener('focus', () => {
// If the last blur was ignored because it was caused by the window becoming inactive, // If the last blur was ignored because it was caused by the window becoming inactive,
// ignore this focus event as well, so we don't reset initialValue // ignore this focus event as well
if (this._ignoredWindowInactiveBlur) { if (this._ignoredWindowInactiveBlur) {
this._ignoredWindowInactiveBlur = false; this._ignoredWindowInactiveBlur = false;
return; return;
@ -216,7 +216,9 @@
if (!this.getAttribute("mousedown")) { if (!this.getAttribute("mousedown")) {
this._input.setSelectionRange(0, this._input.value.length, "backward"); this._input.setSelectionRange(0, this._input.value.length, "backward");
} }
this._input.dataset.initialValue = this._input.value; if (!('initialValue' in this._input.dataset)) {
this._input.dataset.initialValue = this._input.value;
}
}); });
input.addEventListener('blur', () => { input.addEventListener('blur', () => {
// Ignore this blur if it was caused by the window becoming inactive (see above) // Ignore this blur if it was caused by the window becoming inactive (see above)
@ -255,6 +257,31 @@
event.preventDefault(); event.preventDefault();
} }
}); });
input.addEventListener('dragover', (event) => {
// If the input is not focused, override the default drop behavior
if ((document.activeElement !== this._input || Services.focus.activeWindow !== window)
&& event.dataTransfer.getData('text/plain')) {
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
}
});
input.addEventListener('drop', (event) => {
let text = event.dataTransfer.getData('text/plain');
// If the input is not focused, replace its entire value with the dropped text
// Otherwise, the normal drop effect takes place and the text is inserted at the cursor
if ((document.activeElement !== this._input || Services.focus.activeWindow !== window)
&& text) {
event.preventDefault();
document.activeElement?.blur();
// Wait a tick to work around an apparent Firefox bug where the cursor stays inside the old
// input even though the new input becomes visually focused
setTimeout(() => {
this.focus();
this._input.value = text;
handleInput();
});
}
});
let focused = false; let focused = false;
let selectionStart = this._input?.selectionStart; let selectionStart = this._input?.selectionStart;
@ -340,12 +367,21 @@
} }
focus(options) { focus(options) {
// If the window isn't active, the focus event won't fire yet,
// so store the initial value now
if (this._input && Services.focus.activeWindow !== window && !('initialValue' in this._input.dataset)) {
this._input.dataset.initialValue = this._input.value;
}
this._input?.focus(options); this._input?.focus(options);
} }
blur() { blur() {
this._input?.blur(); this._input?.blur();
} }
get focused() {
return this._input && document.activeElement === this._input;
}
} }
customElements.define("editable-text", EditableText); customElements.define("editable-text", EditableText);

View file

@ -142,9 +142,13 @@
this._titleFieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(this.item.itemTypeID, 'title'); this._titleFieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(this.item.itemTypeID, 'title');
let title = this.item.getField(this._titleFieldID); let title = this.item.getField(this._titleFieldID);
if (!this.titleField.initialValue || this.titleField.initialValue !== title) { // If focused, update the value that will be restored on Escape;
// otherwise, update the displayed value
if (this.titleField.focused) {
this.titleField.initialValue = title;
}
else {
this.titleField.value = title; this.titleField.value = title;
this.titleField.initialValue = '';
} }
this.titleField.readOnly = this._mode == 'view'; this.titleField.readOnly = this._mode == 'view';
if (this._titleFieldID) { if (this._titleFieldID) {