fx-compat: Item box: Fix multiline fields & autocomplete

This commit is contained in:
Abe Jellinek 2022-05-24 15:42:54 -06:00
parent 02bcb1712c
commit fdd73d4ada
3 changed files with 131 additions and 59 deletions

View file

@ -26,6 +26,10 @@
"use strict"; "use strict";
{ {
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/shadowAutocompleteInput.js", this);
class ItemBox extends XULElement { class ItemBox extends XULElement {
constructor() { constructor() {
super(); super();
@ -1146,13 +1150,7 @@
} }
ensureElementIsVisible(elem) { ensureElementIsVisible(elem) {
try { elem.scrollIntoView();
var sbo = this.boxObject;
sbo.ensureElementIsVisible(elem);
}
catch (e) {
Zotero.logError(e);
}
} }
changeTypeTo(itemTypeID, menu) { changeTypeTo(itemTypeID, menu) {
@ -1441,7 +1439,7 @@
} }
showEditor(elem) { showEditor(elem) {
return (async function () { return (async () => {
Zotero.debug(`Showing editor for ${elem.getAttribute('fieldname')}`); Zotero.debug(`Showing editor for ${elem.getAttribute('fieldname')}`);
var label = elem.closest('tr').querySelector('th'); var label = elem.closest('tr').querySelector('th');
@ -1508,27 +1506,15 @@
} }
} }
var t = document.createElement("input"); var t;
t.setAttribute('id', `itembox-field-textbox-${fieldName}`);
t.setAttribute('value', value);
t.setAttribute('fieldname', fieldName);
t.setAttribute('ztabindex', tabindex);
t.setAttribute('flex', '1');
if (creatorField=='lastName') {
t.setAttribute('fieldMode', elem.getAttribute('fieldMode'));
t.setAttribute('newlines','pasteintact');
}
if (Zotero.ItemFields.isMultiline(fieldName) || Zotero.ItemFields.isLong(fieldName)) { if (Zotero.ItemFields.isMultiline(fieldName) || Zotero.ItemFields.isLong(fieldName)) {
t.setAttribute('multiline', true); t = document.createElement("textarea");
t.setAttribute('rows', 8); t.setAttribute('rows', 8);
} }
else {
// Add auto-complete for certain fields // Add auto-complete for certain fields
if (Zotero.ItemFields.isAutocompleteField(fieldName) else if (Zotero.ItemFields.isAutocompleteField(fieldName)
|| fieldName == 'creator') { || fieldName == 'creator') {
t.setAttribute('type', 'autocomplete'); t = document.createElement("input", { is: 'shadow-autocomplete-input' });
t.setAttribute('autocompletesearch', 'zotero'); t.setAttribute('autocompletesearch', 'zotero');
let params = { let params = {
@ -1551,18 +1537,36 @@
} }
// Return // Return
t.setAttribute('ontextentered', t.addEventListener('keydown', (event) => {
'this.handleCreatorAutoCompleteSelect(this, true)'); if (event.key == 'Enter') {
this.handleCreatorAutoCompleteSelect(t, true);
}
});
// Tab/Shift-Tab // Tab/Shift-Tab
t.setAttribute('onchange', t.setAttribute('onchange',
'this.handleCreatorAutoCompleteSelect(this)'); 'this.handleCreatorAutoCompleteSelect(this)');
};
if (creatorField == 'lastName') {
t.setAttribute('fieldMode', elem.getAttribute('fieldMode'));
}
}
t.setAttribute( t.setAttribute(
'autocompletesearchparam', JSON.stringify(params) 'autocompletesearchparam', JSON.stringify(params)
); );
t.setAttribute('completeselectedindex', true); t.setAttribute('completeselectedindex', true);
} }
if (!t) {
t = document.createElement("input");
} }
t.id = `itembox-field-textbox-${fieldName}`;
t.value = value;
t.dataset.originalValue = value;
t.style.mozBoxFlex = 1;
t.setAttribute('fieldname', fieldName);
t.setAttribute('ztabindex', tabindex);
var box = elem.parentNode; var box = elem.parentNode;
box.replaceChild(t, elem); box.replaceChild(t, elem);
@ -1597,7 +1601,7 @@
t.onkeypress = (event) => this.handleKeyPress(event); t.onkeypress = (event) => this.handleKeyPress(event);
return t; return t;
}.bind(this))(); })();
} }
@ -1701,7 +1705,7 @@
// Shift-enter adds new creator row // Shift-enter adds new creator row
if (fieldname.indexOf('creator-') == 0 && event.shiftKey) { if (fieldname.indexOf('creator-') == 0 && event.shiftKey) {
// Value hasn't changed // Value hasn't changed
if (target.getAttribute('value') == target.value) { if (target.dataset.originalValue == target.value) {
Zotero.debug("Value hasn't changed"); Zotero.debug("Value hasn't changed");
// If + button is disabled, just focus next creator row // If + button is disabled, just focus next creator row
if (target.closest('tr').lastChild.lastChild.disabled) { if (target.closest('tr').lastChild.lastChild.disabled) {
@ -1732,7 +1736,7 @@
case event.DOM_VK_ESCAPE: case event.DOM_VK_ESCAPE:
// Reset field to original value // Reset field to original value
target.value = target.getAttribute('value'); target.value = target.dataset.originalValue;
focused.blur(); focused.blur();

View file

@ -0,0 +1,60 @@
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2022 Corporation for Digital Scholarship
Vienna, Virginia, USA
https://www.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 <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
"use strict";
{
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
// Load specific element because customElements.js loads on element creation only
Services.scriptloader.loadSubScript("chrome://global/content/elements/autocomplete-input.js", this);
/**
* Extends AutocompleteInput to fix document.activeElement checks that
* don't work in a shadow DOM context.
*/
class ShadowAutocompleteInput extends customElements.get('autocomplete-input') {
get focused() {
// document.activeElement by itself doesn't traverse shadow DOMs; see
// https://www.abeautifulsite.net/posts/finding-the-active-element-in-a-shadow-root/
function activeElement(root) {
let activeHere = root.activeElement;
if (activeHere?.shadowRoot) {
return activeElement(activeHere.shadowRoot);
}
else {
return activeHere;
}
}
return this === activeElement(document);
}
}
customElements.define("shadow-autocomplete-input", ShadowAutocompleteInput, {
extends: "input",
});
}

View file

@ -25,6 +25,10 @@ td > [fieldname] {
width: 100%; width: 100%;
} }
.value.multiline {
white-space: pre-line;
}
/*td > vbox > description /*td > vbox > description
{ {
margin: 0 !important; margin: 0 !important;
@ -66,6 +70,10 @@ label[singleField=false]:after
margin: 0; margin: 0;
}*/ }*/
textarea {
font: inherit;
}
/* metadata field names */ /* metadata field names */
th, .creator-type-label { th, .creator-type-label {
font-weight: normal; font-weight: normal;