luci-base: ui.js: further keyboard navigation improvements for dropdowns
authorJo-Philipp Wich <jo@mein.io>
Wed, 21 Feb 2024 14:30:16 +0000 (15:30 +0100)
committerJo-Philipp Wich <jo@mein.io>
Wed, 21 Feb 2024 14:33:08 +0000 (15:33 +0100)
 - 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>
modules/luci-base/htdocs/luci-static/resources/ui.js

index 9470130998df6bc3b303e0d9da1f4965ec71addf..d266fc73ceaf4210b2367a9f0784e7b427c4c334 100644 (file)
@@ -1458,7 +1458,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
                        li.setAttribute('display', 0);
                        li.setAttribute('selected', '');
 
-                       this.closeDropdown(sb, true);
+                       this.closeDropdown(sb);
                }
 
                this.saveValues(sb, ul);
@@ -1605,6 +1605,9 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
                if (this.options.multiple)
                        this.transformItem(sb, new_item);
 
+               if (!new_item.hasAttribute('unselectable'))
+                       new_item.setAttribute('tabindex', 0);
+
                return new_item;
        },
 
@@ -1814,7 +1817,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
                                        var li = active.nextElementSibling;
                                        this.setFocus(sb, li);
                                        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();
                                        }
                                        ev.preventDefault();
@@ -1875,9 +1878,16 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
                        if (input.classList.contains('cbi-input-invalid'))
                                return;
 
+                       this.handleCreateBlur(ev);
                        this.createItems(sb, input.value);
                        input.value = '';
-                       input.blur();
+                       break;
+
+               case 27:
+                       this.handleCreateBlur(ev);
+                       this.closeDropdown(sb);
+                       ev.stopPropagation();
+                       input.value = '';
                        break;
 
                case 38: