diff options
author | Jo-Philipp Wich <jo@mein.io> | 2023-02-05 19:39:13 +0100 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2023-02-05 19:39:13 +0100 |
commit | 8db3e0e70fe0986a7c4c60f998c583e28bd0e2f0 (patch) | |
tree | 891e843cdd165627777a6acf52a2b9279a5e9058 /modules/luci-base/htdocs | |
parent | c13ef9406c9c2e12c28d2065b342444af5e27c0b (diff) |
luci-base: ui.js: improve ui.Dropdown event handling
Improve overall event and focus handling, avoid registering a global
mouseover event listener, stop propagating escape keypress on closing
dropdown and avoid `Element.blur()` to prevent de-focusing open modals.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'modules/luci-base/htdocs')
-rw-r--r-- | modules/luci-base/htdocs/luci-static/resources/ui.js | 59 |
1 files changed, 41 insertions, 18 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/ui.js b/modules/luci-base/htdocs/luci-static/resources/ui.js index c7b7ccd773..450cb655c6 100644 --- a/modules/luci-base/htdocs/luci-static/resources/ui.js +++ b/modules/luci-base/htdocs/luci-static/resources/ui.js @@ -1050,7 +1050,8 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { 'class': 'cbi-dropdown', 'multiple': this.options.multiple ? '' : null, 'optional': this.options.optional ? '' : null, - 'disabled': this.options.disabled ? '' : null + 'disabled': this.options.disabled ? '' : null, + 'tabindex': -1 }, E('ul')); var keys = Object.keys(this.choices); @@ -1186,11 +1187,11 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { } else { sb.addEventListener('mouseover', this.handleMouseover.bind(this)); + sb.addEventListener('mouseout', this.handleMouseout.bind(this)); sb.addEventListener('focus', this.handleFocus.bind(this)); canary.addEventListener('focus', this.handleCanaryFocus.bind(this)); - window.addEventListener('mouseover', this.setFocus); window.addEventListener('click', this.closeAllDropdowns); } @@ -1343,7 +1344,12 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { sb.lastElementChild.setAttribute('tabindex', 0); - this.setFocus(sb, sel || li[0], true); + var focusFn = L.bind(function(el) { + this.setFocus(sb, el, true); + ul.removeEventListener('transitionend', focusFn); + }, this, sel || li[0]); + + ul.addEventListener('transitionend', focusFn); }, /** @private */ @@ -1559,26 +1565,33 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { /** @private */ setFocus: function(sb, elem, scroll) { - if (sb && sb.hasAttribute && sb.hasAttribute('locked-in')) + if (sb.hasAttribute('locked-in')) return; - if (sb.target && findParent(sb.target, 'ul.dropdown')) + sb.querySelectorAll('.focus').forEach(function(e) { + e.classList.remove('focus'); + }); + + elem.classList.add('focus'); + + if (scroll) + elem.parentNode.scrollTop = elem.offsetTop - elem.parentNode.offsetTop; + + elem.focus(); + }, + + /** @private */ + handleMouseout: function(ev) { + var sb = ev.currentTarget; + + if (!sb.hasAttribute('open')) return; - document.querySelectorAll('.focus').forEach(function(e) { - if (!matchesElem(e, 'input')) { - e.classList.remove('focus'); - e.blur(); - } + sb.querySelectorAll('.focus').forEach(function(e) { + e.classList.remove('focus'); }); - if (elem) { - elem.focus(); - elem.classList.add('focus'); - - if (scroll) - elem.parentNode.scrollTop = elem.offsetTop - elem.parentNode.offsetTop; - } + sb.querySelector('ul.dropdown').focus(); }, /** @private */ @@ -1758,7 +1771,8 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { /** @private */ handleKeydown: function(ev) { - var sb = ev.currentTarget; + var sb = ev.currentTarget, + ul = sb.querySelector('ul.dropdown'); if (matchesElem(ev.target, 'input')) return; @@ -1779,6 +1793,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { switch (ev.keyCode) { case 27: this.closeDropdown(sb); + ev.stopPropagation(); break; case 13: @@ -1802,6 +1817,10 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { this.setFocus(sb, active.previousElementSibling); ev.preventDefault(); } + else if (document.activeElement === ul) { + this.setFocus(sb, ul.lastElementChild); + ev.preventDefault(); + } break; case 40: @@ -1809,6 +1828,10 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { this.setFocus(sb, active.nextElementSibling); ev.preventDefault(); } + else if (document.activeElement === ul) { + this.setFocus(sb, ul.firstElementChild); + ev.preventDefault(); + } break; } } |