drupal/core/misc/field-list-keyboard-navigat...

70 lines
2.3 KiB
JavaScript

/**
* @file
* Attaches behaviors for Drupal's field list keyboard navigation.
*/
(function (Drupal, { isFocusable }) {
/**
* Attaches the focus shifting functionality.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches behaviors.
*/
Drupal.behaviors.fieldListKeyboardNavigation = {
attach() {
once(
'keyboardNavigation',
'input[type="text"], input[type="number"]',
document.querySelector('[data-field-list-table]'),
).forEach((element) =>
element.addEventListener('keypress', (event) => {
if (event.key !== 'Enter') {
return;
}
event.preventDefault();
const currentElement = event.target;
// Function to find the next focusable element.
const findNextFocusableElement = (element) => {
const currentRow = element.closest('tr');
const inputElements = currentRow.querySelectorAll(
'input[type="text"], input[type="number"]',
);
const afterIndex = [...inputElements].indexOf(element) + 1;
// eslint-disable-next-line no-restricted-syntax
for (const inputElement of [...inputElements].slice(afterIndex)) {
if (isFocusable(inputElement)) {
return inputElement;
}
}
const nextRow = currentRow.nextElementSibling;
if (nextRow) {
return findNextFocusableElement(nextRow);
}
return null;
};
const nextFocusableElement = findNextFocusableElement(currentElement);
// If a focusable element is found, move focus there.
if (nextFocusableElement) {
nextFocusableElement.focus();
// Move cursor to the end of the input.
const value = nextFocusableElement.value;
nextFocusableElement.value = '';
nextFocusableElement.value = value;
return;
}
// If no focusable element is found, add another item to the list.
event.target
.closest('[data-field-list-table]')
.parentNode.querySelector('[data-field-list-button]')
.dispatchEvent(new Event('mousedown'));
}),
);
},
};
})(Drupal, window.tabbable);