Merge branch 'main' into summary-review-sharing
This commit is contained in:
@ -51,6 +51,12 @@ let BookWyrm = new class {
|
||||
'click',
|
||||
this.duplicateInput.bind(this)
|
||||
|
||||
))
|
||||
document.querySelectorAll('details.dropdown')
|
||||
.forEach(node => node.addEventListener(
|
||||
'toggle',
|
||||
this.handleDetailsDropdown.bind(this)
|
||||
|
||||
))
|
||||
}
|
||||
|
||||
@ -480,4 +486,101 @@ let BookWyrm = new class {
|
||||
|
||||
textareaEl.parentNode.appendChild(copyButtonEl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the details dropdown component.
|
||||
*
|
||||
* @param {Event} event - Event fired by a `details` element
|
||||
* with the `dropdown` class name, on toggle.
|
||||
* @return {undefined}
|
||||
*/
|
||||
handleDetailsDropdown(event) {
|
||||
const detailsElement = event.target;
|
||||
const summaryElement = detailsElement.querySelector('summary');
|
||||
const menuElement = detailsElement.querySelector('.dropdown-menu');
|
||||
const htmlElement = document.querySelector('html');
|
||||
|
||||
if (detailsElement.open) {
|
||||
// Focus first menu element
|
||||
menuElement.querySelectorAll(
|
||||
'a[href]:not([disabled]), button:not([disabled])'
|
||||
)[0].focus();
|
||||
|
||||
// Enable focus trap
|
||||
menuElement.addEventListener('keydown', this.handleFocusTrap);
|
||||
|
||||
// Close on Esc
|
||||
detailsElement.addEventListener('keydown', handleEscKey);
|
||||
|
||||
// Clip page if Mobile
|
||||
if (this.isMobile()) {
|
||||
htmlElement.classList.add('is-clipped');
|
||||
}
|
||||
} else {
|
||||
summaryElement.focus();
|
||||
|
||||
// Disable focus trap
|
||||
menuElement.removeEventListener('keydown', this.handleFocusTrap);
|
||||
|
||||
// Unclip page
|
||||
if (this.isMobile()) {
|
||||
htmlElement.classList.remove('is-clipped');
|
||||
}
|
||||
}
|
||||
|
||||
function handleEscKey(event) {
|
||||
if (event.key !== 'Escape') {
|
||||
return;
|
||||
}
|
||||
|
||||
summaryElement.click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if windows matches mobile media query.
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isMobile() {
|
||||
return window.matchMedia("(max-width: 768px)").matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus trap handler
|
||||
*
|
||||
* @param {Event} event - Keydown event.
|
||||
* @return {undefined}
|
||||
*/
|
||||
handleFocusTrap(event) {
|
||||
if (event.key !== 'Tab') {
|
||||
return;
|
||||
}
|
||||
|
||||
const focusableEls = event.currentTarget.querySelectorAll(
|
||||
[
|
||||
'a[href]:not([disabled])',
|
||||
'button:not([disabled])',
|
||||
'textarea:not([disabled])',
|
||||
'input:not([type="hidden"]):not([disabled])',
|
||||
'select:not([disabled])',
|
||||
'details:not([disabled])',
|
||||
'[tabindex]:not([tabindex="-1"]):not([disabled])'
|
||||
].join(',')
|
||||
);
|
||||
const firstFocusableEl = focusableEls[0];
|
||||
const lastFocusableEl = focusableEls[focusableEls.length - 1];
|
||||
|
||||
if (event.shiftKey ) /* Shift + tab */ {
|
||||
if (document.activeElement === firstFocusableEl) {
|
||||
lastFocusableEl.focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
} else /* Tab */ {
|
||||
if (document.activeElement === lastFocusableEl) {
|
||||
firstFocusableEl.focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
@ -1,34 +0,0 @@
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Toggle all descendant checkboxes of a target.
|
||||
*
|
||||
* Use `data-target="ID_OF_TARGET"` on the node on which the event is listened
|
||||
* to (checkbox, button, link…), where_ID_OF_TARGET_ should be the ID of an
|
||||
* ancestor for the checkboxes.
|
||||
*
|
||||
* @example
|
||||
* <input
|
||||
* type="checkbox"
|
||||
* data-action="toggle-all"
|
||||
* data-target="failed-imports"
|
||||
* >
|
||||
* @param {Event} event
|
||||
* @return {undefined}
|
||||
*/
|
||||
function toggleAllCheckboxes(event) {
|
||||
const mainCheckbox = event.target;
|
||||
|
||||
document
|
||||
.querySelectorAll(`#${mainCheckbox.dataset.target} [type="checkbox"]`)
|
||||
.forEach(checkbox => checkbox.checked = mainCheckbox.checked);
|
||||
}
|
||||
|
||||
document
|
||||
.querySelectorAll('[data-action="toggle-all"]')
|
||||
.forEach(input => {
|
||||
input.addEventListener('change', toggleAllCheckboxes);
|
||||
});
|
||||
})();
|
Reference in New Issue
Block a user