From 23ffcc72f23c0bc681f94d729b36903840acda5a Mon Sep 17 00:00:00 2001 From: Anneke Sinnema Date: Sat, 26 Oct 2024 11:41:18 +0200 Subject: [PATCH 1/3] Fix broken item in English navigation #437 Signed-off-by: Anneke Sinnema --- src/_data/navigation.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/_data/navigation.js b/src/_data/navigation.js index c90769e8..877c0fc5 100644 --- a/src/_data/navigation.js +++ b/src/_data/navigation.js @@ -239,7 +239,6 @@ module.exports = { url: "/en/jobs/post-job-opening/", title: "Post a job opening", }, - , { url: "/en/jobs/post-job-opening/toc", title: "Job bank terms", From fb9b0d130df7cb3fbf29cc0be8a1c200f4c4fd31 Mon Sep 17 00:00:00 2001 From: Anneke Sinnema Date: Sat, 26 Oct 2024 12:14:45 +0200 Subject: [PATCH 2/3] Add keyboard navigation (on desktop) Signed-off-by: Anneke Sinnema --- src/_assets/css/elements/page-navigation.css | 2 +- src/_assets/js/page-navigation.js | 206 ++++++++++++++----- 2 files changed, 159 insertions(+), 49 deletions(-) diff --git a/src/_assets/css/elements/page-navigation.css b/src/_assets/css/elements/page-navigation.css index 3642f2e1..ee6a1a81 100644 --- a/src/_assets/css/elements/page-navigation.css +++ b/src/_assets/css/elements/page-navigation.css @@ -66,7 +66,7 @@ a[aria-current='page'] { .navigation-list--sublevel :is(a:hover, a:active, a:focus, button:hover, button:active, button:focus) { background-color: unset; - color: var(--yellow); + outline-color: var(--yellow); outline-offset: -2px; } diff --git a/src/_assets/js/page-navigation.js b/src/_assets/js/page-navigation.js index dfc6a7f1..e806a672 100644 --- a/src/_assets/js/page-navigation.js +++ b/src/_assets/js/page-navigation.js @@ -63,63 +63,173 @@ document.addEventListener('DOMContentLoaded', function() { navToggle.addEventListener('click', handleInteraction); } - // Allow users to open submenu items - const submenuToggle = document.querySelectorAll('.navigation-submenu-toggle'); - const navigation = document.querySelector('.page-navigation'); + const submenuToggle = document.querySelectorAll('.navigation-submenu-toggle'); + const toplevelLinks = document.querySelectorAll('.navigation-list-item--toplevel > a'); + const navigation = document.querySelector('.page-navigation'); + + // Function to handle wide screen behavior + function handleWideScreens() { + if (window.innerWidth > 961) { + // Set tabindex to -1 for all submenu toggles + submenuToggle.forEach(function (toggle) { + toggle.setAttribute('tabindex', '-1'); + }); + + // Add keyboard navigation with arrow keys on top-level links + toplevelLinks.forEach(function (link, index) { + link.addEventListener('keydown', function (event) { + const parentLi = link.parentElement; + const toggleButton = parentLi.querySelector('.navigation-submenu-toggle'); + + if (event.key === 'ArrowDown') { + event.preventDefault(); + closeAllSubmenus(); - submenuToggle.forEach(function (toggle) { - toggle.addEventListener('click', function (event) { - const parentLi = toggle.parentElement; - const submenuIsExpanded = toggle.getAttribute('aria-expanded') === 'true'; - - // Close all other open submenus before opening a new one - submenuToggle.forEach(function (otherToggle) { - const otherParentLi = otherToggle.parentElement; - - // If it's not the clicked submenu, close it - if (otherToggle !== toggle) { - otherToggle.setAttribute('aria-expanded', 'false'); - otherToggle.setAttribute('aria-labelledby', 'openSubmenuLabel'); - otherParentLi.classList.remove('open'); - } - }); - - // Toggle the clicked submenu - if (submenuIsExpanded) { - toggle.setAttribute('aria-expanded', 'false'); - toggle.setAttribute('aria-labelledby', 'openSubmenuLabel'); - parentLi.classList.remove('open'); - } else { - toggle.setAttribute('aria-expanded', 'true'); - parentLi.classList.add('open'); - toggle.setAttribute('aria-labelledby', 'closeSubmenuLabel'); - trapFocus(parentLi, toggle); + // Open submenu if it has one + if (toggleButton && !parentLi.classList.contains('open')) { + toggleButton.setAttribute('aria-expanded', 'true'); + parentLi.classList.add('open'); + const firstSubmenuItem = parentLi.querySelector('.navigation-list-item--sublevel a'); + if (firstSubmenuItem) { + firstSubmenuItem.focus(); + } + } + } else if (event.key === 'ArrowLeft') { + event.preventDefault(); + if (index > 0) { + // Move focus to the previous top-level link and open its submenu + toplevelLinks[index - 1].focus(); + openSubmenu(toplevelLinks[index - 1]); + } + } else if (event.key === 'ArrowRight') { + event.preventDefault(); + if (index < toplevelLinks.length - 1) { + // Move focus to the next top-level link and open its submenu + toplevelLinks[index + 1].focus(); + openSubmenu(toplevelLinks[index + 1]); } + } }); - }); - - // Function to close all submenus - function closeAllSubmenus() { - submenuToggle.forEach(function (toggle) { - const parentLi = toggle.parentElement; - toggle.setAttribute('aria-expanded', 'false'); - toggle.setAttribute('aria-labelledby', 'openSubmenuLabel'); - parentLi.classList.remove('open'); + }); + + // Add navigation with up and down arrow keys inside submenu + const sublevelLinks = document.querySelectorAll('.navigation-list-item--sublevel > a'); + sublevelLinks.forEach(function (subLink) { + subLink.addEventListener('keydown', function (event) { + const subMenuItems = Array.from(subLink.closest('ul').querySelectorAll('a')); + const currentIndex = subMenuItems.indexOf(subLink); + + if (event.key === 'ArrowDown') { + event.preventDefault(); + const nextIndex = (currentIndex + 1) % subMenuItems.length; + subMenuItems[nextIndex].focus(); + } else if (event.key === 'ArrowUp') { + event.preventDefault(); + const prevIndex = (currentIndex - 1 + subMenuItems.length) % subMenuItems.length; + subMenuItems[prevIndex].focus(); + } else if (event.key === 'ArrowLeft') { + event.preventDefault(); + const parentLi = subLink.closest('.navigation-list-item--toplevel'); + const currentTopLevelIndex = Array.from(toplevelLinks).indexOf(parentLi.querySelector('a')); + if (currentTopLevelIndex > 0) { + toplevelLinks[currentTopLevelIndex - 1].focus(); + openSubmenu(toplevelLinks[currentTopLevelIndex - 1]); + } + } else if (event.key === 'ArrowRight') { + event.preventDefault(); + const parentLi = subLink.closest('.navigation-list-item--toplevel'); + const currentTopLevelIndex = Array.from(toplevelLinks).indexOf(parentLi.querySelector('a')); + if (currentTopLevelIndex < toplevelLinks.length - 1) { + toplevelLinks[currentTopLevelIndex + 1].focus(); + openSubmenu(toplevelLinks[currentTopLevelIndex + 1]); + } + } }); + }); + + } else { + // Make sure submenu toggles are tabbable again for mobile + submenuToggle.forEach(function (toggle) { + toggle.removeAttribute('tabindex'); + }); } + } - // Close submenus when clicking outside the navigation - document.addEventListener('click', function (event) { - if (!navigation.contains(event.target)) { - closeAllSubmenus(); + // Helper function to open submenu for a given top-level link + function openSubmenu(toplevelLink) { + const parentLi = toplevelLink.parentElement; + const toggleButton = parentLi.querySelector('.navigation-submenu-toggle'); + + if (toggleButton && !parentLi.classList.contains('open')) { + closeAllSubmenus(); // Close any other open submenus + toggleButton.setAttribute('aria-expanded', 'true'); + parentLi.classList.add('open'); + const firstSubmenuItem = parentLi.querySelector('.navigation-list-item--sublevel a'); + if (firstSubmenuItem) { + firstSubmenuItem.focus(); + } + } + } + + // Call the function on page load + handleWideScreens(); + + // Re-run when window is resized + window.addEventListener('resize', handleWideScreens); + + // Existing click toggle logic (no changes needed here) + submenuToggle.forEach(function (toggle) { + toggle.addEventListener('click', function (event) { + const parentLi = toggle.parentElement; + const submenuIsExpanded = toggle.getAttribute('aria-expanded') === 'true'; + + // Close all other open submenus before opening a new one + submenuToggle.forEach(function (otherToggle) { + const otherParentLi = otherToggle.parentElement; + + // If it's not the clicked submenu, close it + if (otherToggle !== toggle) { + otherToggle.setAttribute('aria-expanded', 'false'); + otherParentLi.classList.remove('open'); } - }); + }); - // Close submenus when pressing the Escape key - document.addEventListener('keydown', function (event) { - if (event.key === 'Escape') { - closeAllSubmenus(); + // Toggle the clicked submenu + if (submenuIsExpanded) { + toggle.setAttribute('aria-expanded', 'false'); + parentLi.classList.remove('open'); + } else { + toggle.setAttribute('aria-expanded', 'true'); + parentLi.classList.add('open'); + const firstSubmenuItem = parentLi.querySelector('.navigation-list-item--sublevel a'); + if (firstSubmenuItem) { + firstSubmenuItem.focus(); } + } }); + }); + // Function to close all submenus + function closeAllSubmenus() { + submenuToggle.forEach(function (toggle) { + const parentLi = toggle.parentElement; + toggle.setAttribute('aria-expanded', 'false'); + parentLi.classList.remove('open'); + }); + } + + // Close submenus when clicking outside the navigation + document.addEventListener('click', function (event) { + if (!navigation.contains(event.target)) { + closeAllSubmenus(); + } + }); + + // Close submenus when pressing the Escape key + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + closeAllSubmenus(); + } + }); }); + From d691055604f1c523c8cec20da963e6762cff6ac2 Mon Sep 17 00:00:00 2001 From: Anneke Sinnema Date: Sat, 26 Oct 2024 12:20:21 +0200 Subject: [PATCH 3/3] Tweak position of turned upside-down arrow Signed-off-by: Anneke Sinnema --- src/_includes/partials/page-header/navigation-triggers.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/_includes/partials/page-header/navigation-triggers.css b/src/_includes/partials/page-header/navigation-triggers.css index 9f0d1271..9bd3ef30 100644 --- a/src/_includes/partials/page-header/navigation-triggers.css +++ b/src/_includes/partials/page-header/navigation-triggers.css @@ -96,6 +96,10 @@ display: none; } +.navigation-list-item--toplevel.open svg { + transform: translateY(0px); +} + @media all and (min-width: 60.125em) { .navigation-submenu-toggle { padding: 0; @@ -107,6 +111,6 @@ } .navigation-list-item--toplevel.open svg { - transform: translateY(0); + transform: translateY(-3px); } }