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>
This commit is contained in:
parent
c13ef9406c
commit
8db3e0e70f
1 changed files with 42 additions and 19 deletions
|
@ -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'))
|
||||
return;
|
||||
|
||||
document.querySelectorAll('.focus').forEach(function(e) {
|
||||
if (!matchesElem(e, 'input')) {
|
||||
sb.querySelectorAll('.focus').forEach(function(e) {
|
||||
e.classList.remove('focus');
|
||||
e.blur();
|
||||
}
|
||||
});
|
||||
|
||||
if (elem) {
|
||||
elem.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;
|
||||
|
||||
sb.querySelectorAll('.focus').forEach(function(e) {
|
||||
e.classList.remove('focus');
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue