luci-base: ui.js: further keyboard navigation improvements for dropdowns

- Ensure that pressing escape within the custom choice input closes the
   dropdown list but not the parent modal dialog

 - Ensure that added custom choice elements are tabbable

 - Retain focus on dropdown when closing dropdown

 - Consistently focus input textarea when tabbing into custom choice item

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2024-02-21 15:30:16 +01:00
parent 42bd2af3fe
commit 317ed4a043

View file

@ -1458,7 +1458,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
li.setAttribute('display', 0); li.setAttribute('display', 0);
li.setAttribute('selected', ''); li.setAttribute('selected', '');
this.closeDropdown(sb, true); this.closeDropdown(sb);
} }
this.saveValues(sb, ul); this.saveValues(sb, ul);
@ -1605,6 +1605,9 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
if (this.options.multiple) if (this.options.multiple)
this.transformItem(sb, new_item); this.transformItem(sb, new_item);
if (!new_item.hasAttribute('unselectable'))
new_item.setAttribute('tabindex', 0);
return new_item; return new_item;
}, },
@ -1814,7 +1817,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
var li = active.nextElementSibling; var li = active.nextElementSibling;
this.setFocus(sb, li); this.setFocus(sb, li);
if (this.options.create && li == li.parentNode.lastElementChild) { if (this.options.create && li == li.parentNode.lastElementChild) {
var input = li.querySelector('input'); var input = li.querySelector('input:not([type="hidden"]):not([type="checkbox"]');
if (input) input.focus(); if (input) input.focus();
} }
ev.preventDefault(); ev.preventDefault();
@ -1875,9 +1878,16 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
if (input.classList.contains('cbi-input-invalid')) if (input.classList.contains('cbi-input-invalid'))
return; return;
this.handleCreateBlur(ev);
this.createItems(sb, input.value); this.createItems(sb, input.value);
input.value = ''; input.value = '';
input.blur(); break;
case 27:
this.handleCreateBlur(ev);
this.closeDropdown(sb);
ev.stopPropagation();
input.value = '';
break; break;
case 38: case 38: