Fix issue where enter key wasn’t setting focus correctly
This commit is contained in:
parent
4ea458e1a3
commit
0bc6b1f1b3
46
src/js/controls.js
vendored
46
src/js/controls.js
vendored
@ -381,7 +381,7 @@ const controls = {
|
|||||||
// We have to bind to keyup otherwise Firefox triggers a click when a keydown event handler shifts focus
|
// We have to bind to keyup otherwise Firefox triggers a click when a keydown event handler shifts focus
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1220143
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1220143
|
||||||
bindMenuItemShortcuts(menuItem, type) {
|
bindMenuItemShortcuts(menuItem, type) {
|
||||||
// Handle space or -> to open menu
|
// Navigate through menus via arrow keys and space
|
||||||
on(
|
on(
|
||||||
menuItem,
|
menuItem,
|
||||||
'keydown keyup',
|
'keydown keyup',
|
||||||
@ -429,6 +429,16 @@ const controls = {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Enter will fire a `click` event but we still need to manage focus
|
||||||
|
// So we bind to keyup which fires after and set focus here
|
||||||
|
on(menuItem, 'keyup', event => {
|
||||||
|
if (event.which !== 13) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.focusFirstMenuItem.call(this, null, true);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Create a settings menu item
|
// Create a settings menu item
|
||||||
@ -1074,6 +1084,23 @@ const controls = {
|
|||||||
toggleHidden(this.elements.settings.menu, !visible);
|
toggleHidden(this.elements.settings.menu, !visible);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Focus the first menu item in a given (or visible) menu
|
||||||
|
focusFirstMenuItem(pane, tabFocus = false) {
|
||||||
|
if (this.elements.settings.popup.hidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = pane;
|
||||||
|
|
||||||
|
if (!is.element(target)) {
|
||||||
|
target = Object.values(this.elements.settings.panels).find(pane => !pane.hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstItem = target.querySelector('[role^="menuitem"]');
|
||||||
|
|
||||||
|
setFocus.call(this, firstItem, tabFocus);
|
||||||
|
},
|
||||||
|
|
||||||
// Show/hide menu
|
// Show/hide menu
|
||||||
toggleMenu(input) {
|
toggleMenu(input) {
|
||||||
const { popup } = this.elements.settings;
|
const { popup } = this.elements.settings;
|
||||||
@ -1085,7 +1112,7 @@ const controls = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// True toggle by default
|
// True toggle by default
|
||||||
const hidden = popup.hasAttribute('hidden');
|
const { hidden } = popup;
|
||||||
let show = hidden;
|
let show = hidden;
|
||||||
|
|
||||||
if (is.boolean(input)) {
|
if (is.boolean(input)) {
|
||||||
@ -1094,19 +1121,13 @@ const controls = {
|
|||||||
show = false;
|
show = false;
|
||||||
} else if (is.event(input)) {
|
} else if (is.event(input)) {
|
||||||
const isMenuItem = popup.contains(input.target);
|
const isMenuItem = popup.contains(input.target);
|
||||||
const isButton = input.target === button;
|
|
||||||
|
|
||||||
// If the click was inside the menu or if the click
|
// If the click was inside the menu or if the click
|
||||||
// wasn't the button or menu item and we're trying to
|
// wasn't the button or menu item and we're trying to
|
||||||
// show the menu (a doc click shouldn't show the menu)
|
// show the menu (a doc click shouldn't show the menu)
|
||||||
if (isMenuItem || (!isMenuItem && !isButton && show)) {
|
if (isMenuItem || (!isMenuItem && input.target !== button && show)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent the toggle being caught by the doc listener
|
|
||||||
if (isButton) {
|
|
||||||
input.stopPropagation();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set button attributes
|
// Set button attributes
|
||||||
@ -1120,9 +1141,7 @@ const controls = {
|
|||||||
|
|
||||||
// Focus the first item if key interaction
|
// Focus the first item if key interaction
|
||||||
if (show && is.keyboardEvent(input)) {
|
if (show && is.keyboardEvent(input)) {
|
||||||
const pane = Object.values(this.elements.settings.panels).find(pane => !pane.hidden);
|
controls.focusFirstMenuItem.call(this, null, true);
|
||||||
const firstItem = pane.querySelector('[role^="menuitem"]');
|
|
||||||
setFocus.call(this, firstItem, true);
|
|
||||||
}
|
}
|
||||||
// If closing, re-focus the button
|
// If closing, re-focus the button
|
||||||
else if (!show && !hidden) {
|
else if (!show && !hidden) {
|
||||||
@ -1205,8 +1224,7 @@ const controls = {
|
|||||||
toggleHidden(target, false);
|
toggleHidden(target, false);
|
||||||
|
|
||||||
// Focus the first item
|
// Focus the first item
|
||||||
const firstItem = target.querySelector('[role^="menuitem"]');
|
controls.focusFirstMenuItem.call(this, target, tabFocus);
|
||||||
setFocus.call(this, firstItem, tabFocus);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Build the default HTML
|
// Build the default HTML
|
||||||
|
@ -553,6 +553,9 @@ class Listeners {
|
|||||||
|
|
||||||
// Settings menu - click toggle
|
// Settings menu - click toggle
|
||||||
this.bind(elements.buttons.settings, 'click', event => {
|
this.bind(elements.buttons.settings, 'click', event => {
|
||||||
|
// Prevent the document click listener closing the menu
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
controls.toggleMenu.call(player, event);
|
controls.toggleMenu.call(player, event);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -563,8 +566,16 @@ class Listeners {
|
|||||||
elements.buttons.settings,
|
elements.buttons.settings,
|
||||||
'keyup',
|
'keyup',
|
||||||
event => {
|
event => {
|
||||||
|
const code = event.which;
|
||||||
|
|
||||||
// We only care about space and return
|
// We only care about space and return
|
||||||
if (event.which !== 32 && event.which !== 13) {
|
if (![13, 32].includes(code)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because return triggers a click anyway, all we need to do is set focus
|
||||||
|
if (code === 13) {
|
||||||
|
controls.focusFirstMenuItem.call(player, null, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,15 +583,13 @@ class Listeners {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
// Prevent playing video (Firefox)
|
// Prevent playing video (Firefox)
|
||||||
if (event.which === 32) {
|
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
|
||||||
|
|
||||||
// Toggle menu
|
// Toggle menu
|
||||||
controls.toggleMenu.call(player, event);
|
controls.toggleMenu.call(player, event);
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
false,
|
false, // Can't be passive as we're preventing default
|
||||||
);
|
);
|
||||||
|
|
||||||
// Escape closes menu
|
// Escape closes menu
|
||||||
|
@ -116,11 +116,7 @@ export function emptyElement(element) {
|
|||||||
|
|
||||||
// Replace element
|
// Replace element
|
||||||
export function replaceElement(newChild, oldChild) {
|
export function replaceElement(newChild, oldChild) {
|
||||||
if (
|
if (!is.element(oldChild) || !is.element(oldChild.parentNode) || !is.element(newChild)) {
|
||||||
!is.element(oldChild) ||
|
|
||||||
!is.element(oldChild.parentNode) ||
|
|
||||||
!is.element(newChild)
|
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +191,7 @@ export function toggleHidden(element, hidden) {
|
|||||||
let hide = hidden;
|
let hide = hidden;
|
||||||
|
|
||||||
if (!is.boolean(hide)) {
|
if (!is.boolean(hide)) {
|
||||||
hide = !element.hasAttribute('hidden');
|
hide = !element.hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hide) {
|
if (hide) {
|
||||||
@ -263,10 +259,7 @@ export function trapFocus(element = null, toggle = false) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const focusable = getElements.call(
|
const focusable = getElements.call(this, 'button:not(:disabled), input:not(:disabled), [tabindex]');
|
||||||
this,
|
|
||||||
'button:not(:disabled), input:not(:disabled), [tabindex]',
|
|
||||||
);
|
|
||||||
const first = focusable[0];
|
const first = focusable[0];
|
||||||
const last = focusable[focusable.length - 1];
|
const last = focusable[focusable.length - 1];
|
||||||
|
|
||||||
@ -290,14 +283,7 @@ export function trapFocus(element = null, toggle = false) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleListener.call(
|
toggleListener.call(this, this.elements.container, 'keydown', trap, toggle, false);
|
||||||
this,
|
|
||||||
this.elements.container,
|
|
||||||
'keydown',
|
|
||||||
trap,
|
|
||||||
toggle,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set focus and tab focus class
|
// Set focus and tab focus class
|
||||||
|
Loading…
x
Reference in New Issue
Block a user