1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-08-11 17:51:01 +00:00

refactor(js): improve menu handlers

This commit is contained in:
Frédéric Guillot 2025-08-02 13:05:20 -07:00
parent 62410659d5
commit 07246e2b59
2 changed files with 67 additions and 63 deletions

View file

@ -270,7 +270,7 @@ function goToListItem(offset) {
if (items[i].classList.contains("current-item")) { if (items[i].classList.contains("current-item")) {
items[i].classList.remove("current-item"); items[i].classList.remove("current-item");
// By default adjust selection by offset // By default adjust selection to the next item
let itemOffset = (i + offset + items.length) % items.length; let itemOffset = (i + offset + items.length) % items.length;
// Allow jumping to top or bottom // Allow jumping to top or bottom
if (offset === TOP) { if (offset === TOP) {
@ -338,73 +338,85 @@ async function triggerWebShare(title, url) {
window.location.reload(); window.location.reload();
} }
// make logo element as button on mobile layout /**
function checkMenuToggleModeByLayout() { * Toggle the ARIA attributes on the main menu based on the viewport width.
*/
function toggleAriaAttributesOnMainMenu() {
const logoElement = document.querySelector(".logo"); const logoElement = document.querySelector(".logo");
if (!logoElement) return;
const homePageLinkElement = document.querySelector(".logo > a"); const homePageLinkElement = document.querySelector(".logo > a");
if (document.documentElement.clientWidth < 620) { if (!logoElement || !homePageLinkElement) return;
const isMobile = document.documentElement.clientWidth < 650;
if (isMobile) {
const navMenuElement = document.getElementById("header-menu"); const navMenuElement = document.getElementById("header-menu");
const navMenuElementIsExpanded = navMenuElement.classList.contains("js-menu-show"); const isExpanded = navMenuElement?.classList.contains("js-menu-show") ?? false;
const logoToggleButtonLabel = logoElement.getAttribute("data-toggle-button-label"); const toggleButtonLabel = logoElement.getAttribute("data-toggle-button-label");
logoElement.setAttribute("role", "button");
logoElement.setAttribute("tabindex", "0"); // Set mobile menu button attributes
logoElement.setAttribute("aria-label", logoToggleButtonLabel); Object.assign(logoElement, {
logoElement.setAttribute("aria-expanded", navMenuElementIsExpanded?"true":"false"); role: "button",
homePageLinkElement.setAttribute("tabindex", "-1"); tabIndex: 0,
ariaLabel: toggleButtonLabel,
ariaExpanded: isExpanded.toString()
});
homePageLinkElement.tabIndex = -1;
} else { } else {
logoElement.removeAttribute("role"); // Remove mobile menu button attributes
logoElement.removeAttribute("tabindex"); ["role", "tabindex", "aria-expanded", "aria-label"].forEach(attr =>
logoElement.removeAttribute("aria-expanded"); logoElement.removeAttribute(attr)
logoElement.removeAttribute("aria-label"); );
homePageLinkElement.removeAttribute("tabindex"); homePageLinkElement.removeAttribute("tabindex");
} }
} }
function fixVoiceOverDetailsSummaryBug() { /**
document.querySelectorAll("details").forEach((details) => { * Toggle the main menu dropdown.
const summaryElement = details.querySelector("summary"); *
summaryElement.setAttribute("role", "button"); * @param {Event} event - The event object.
summaryElement.setAttribute("aria-expanded", details.open? "true": "false"); */
function toggleMainMenuDropdown(event) {
details.addEventListener("toggle", () => { // Only handle Enter, Space, or click events
summaryElement.setAttribute("aria-expanded", details.open? "true": "false"); if (event.type === "keydown" && !["Enter", " "].includes(event.key)) {
});
});
}
// Show and hide the main menu on mobile devices.
function toggleMainMenu(event) {
if (event.type === "keydown" && !(event.key === "Enter" || event.key === " ")) {
return; return;
} }
// Prevent default only if element has role attribute (mobile menu button)
if (event.currentTarget.getAttribute("role")) { if (event.currentTarget.getAttribute("role")) {
event.preventDefault(); event.preventDefault();
} }
const menu = document.querySelector(".header nav ul"); const navigationMenu = document.querySelector(".header nav ul");
const menuToggleButton = document.querySelector(".logo"); const menuToggleButton = document.querySelector(".logo");
if (menu.classList.contains("js-menu-show")) {
menuToggleButton.setAttribute("aria-expanded", "false"); if (!navigationMenu || !menuToggleButton) {
} else { return;
menuToggleButton.setAttribute("aria-expanded", "true");
} }
menu.classList.toggle("js-menu-show");
const isShowing = navigationMenu.classList.toggle("js-menu-show");
menuToggleButton.setAttribute("aria-expanded", isShowing.toString());
} }
// Handle click events for the main menu (<li> and <a>). /**
function onClickMainMenuListItem(event) { * Initialize the main menu handlers.
const element = event.target; */
function initializeMainMenuHandlers() {
toggleAriaAttributesOnMainMenu();
window.addEventListener("resize", toggleAriaAttributesOnMainMenu, { passive: true });
if (element.tagName === "A") { const logoElement = document.querySelector(".logo");
window.location.href = element.getAttribute("href"); if (logoElement) {
} else { logoElement.addEventListener("click", toggleMainMenuDropdown);
const linkElement = element.querySelector("a") || element.closest("a"); logoElement.addEventListener("keydown", toggleMainMenuDropdown);
window.location.href = linkElement.getAttribute("href");
} }
onClick(".header nav li", (event) => {
const linkElement = event.target.closest("a") || event.target.querySelector("a");
if (linkElement) {
window.location.href = linkElement.getAttribute("href");
}
});
} }
/** /**
@ -412,7 +424,7 @@ function onClickMainMenuListItem(event) {
* *
* @returns {void} * @returns {void}
*/ */
function disableSubmitButtonsOnFormSubmit() { function initializeFormHandlers() {
document.querySelectorAll("form").forEach((element) => { document.querySelectorAll("form").forEach((element) => {
element.onsubmit = () => { element.onsubmit = () => {
const buttons = element.querySelectorAll("button[type=submit]"); const buttons = element.querySelectorAll("button[type=submit]");
@ -426,13 +438,17 @@ function disableSubmitButtonsOnFormSubmit() {
}); });
} }
// Show modal dialog with the list of keyboard shortcuts. /**
* Show the keyboard shortcuts modal.
*/
function showKeyboardShortcuts() { function showKeyboardShortcuts() {
const template = document.getElementById("keyboard-shortcuts"); const template = document.getElementById("keyboard-shortcuts");
ModalHandler.open(template.content, "dialog-title"); ModalHandler.open(template.content, "dialog-title");
} }
// Mark as read visible items of the current page. /**
* Mark all visible entries on the current page as read.
*/
function markPageAsRead() { function markPageAsRead() {
const items = getVisibleEntries(); const items = getVisibleEntries();
const entryIDs = []; const entryIDs = [];

View file

@ -1,4 +1,5 @@
disableSubmitButtonsOnFormSubmit(); initializeMainMenuHandlers();
initializeFormHandlers();
initializeMediaPlayerHandlers(); initializeMediaPlayerHandlers();
// Initialize the keyboard shortcuts if enabled. // Initialize the keyboard shortcuts if enabled.
@ -85,19 +86,6 @@ onAuxClick("a[data-original-link='true']", (event) => {
} }
}, true); }, true);
checkMenuToggleModeByLayout();
window.addEventListener("resize", checkMenuToggleModeByLayout, { passive: true });
fixVoiceOverDetailsSummaryBug();
const logoElement = document.querySelector(".logo");
if (logoElement) {
logoElement.addEventListener("click", toggleMainMenu);
logoElement.addEventListener("keydown", toggleMainMenu);
}
onClick(".header nav li", (event) => onClickMainMenuListItem(event));
// Register the service worker if supported. // Register the service worker if supported.
if ("serviceWorker" in navigator) { if ("serviceWorker" in navigator) {
const serviceWorkerURL = document.body.dataset.serviceWorkerUrl; const serviceWorkerURL = document.body.dataset.serviceWorkerUrl;