I'm doing some work to make navigation fully accessible by mouse over, keyboard and click, depending on the resolution.
I am looking for that in mobile, only the click works. And hover, click, keyboard for higher resolutions.
Important edit :
It only works perfectly when I load the page at the correct resolution (low or high). BUT, if I resize live, the removeEventListener
doesn't work.
Plus : I don't know if my stopImmediatePropagation
is the better solution to avoid multiple functions.
Here is the idea of the code.
JS
window.addEventListener("DOMContentLoaded", onLoadFunction);
function onLoadFunction(e) {
menu_burger();
onResizeFunction(); //trigger resize function immediately
window.addEventListener("resize", onResizeFunction);
}
function onResizeFunction(e) {
if (window.innerWidth > 770) {
window.removeEventListener('resize', menu_onClick);
menu_onClick();
menu_mouseOver();
menu_onFocus();
menu_onFocusDetection();
} else {
window.removeEventListener('resize', menu_onClick);
window.removeEventListener('resize', menu_mouseOver);
window.removeEventListener('resize', menu_onFocusDetection);
window.removeEventListener('resize', menu_onFocus);
menu_onClick();
}
}
// FONCTIONS MENU
const focusDetectionEntry = document.querySelectorAll('.nav-list--focus-detection > li[aria-expanded] > button');
const focusEntry = document.querySelectorAll('.nav-list--focus > li[aria-expanded] > button');
const overEntry = document.querySelectorAll('.nav-list--over > li[aria-expanded] > button');
const clickEntry = document.querySelectorAll('.nav-list--click > li[aria-expanded] > button');
function menu_burger() {
document.querySelector('.menu-burger').addEventListener('click', function () {
this.classList.toggle('menu--open');
document.querySelector('.main-nav-list').classList.toggle('main-nav-list--open');
});
}
function menu_mouseOver() {
overEntry.forEach(sub => {
var subParent = sub.parentElement;
subParent.addEventListener('mouseover', function(e) {
subParent.setAttribute('aria-expanded', 'true');
console.log('OVER IN');
e.stopImmediatePropagation();
});
subParent.addEventListener('mouseout', function(e) {
subParent.setAttribute('aria-expanded', 'false');
console.log('OVER OUT');
e.stopImmediatePropagation();
});
})
}
function menu_onClick() {
clickEntry.forEach(sub => {
var subParent = sub.parentElement;
sub.addEventListener('click', function(e) {
let attrState = subParent.getAttribute('aria-expanded');
if (attrState === 'false') {
subParent.setAttribute('aria-expanded', 'true')
} else if (attrState === 'true') {
subParent.setAttribute('aria-expanded', 'false');
}
console.log('CLICK');
e.stopImmediatePropagation();
});
})
}
function menu_onFocus() {
focusEntry.forEach(sub => {
var subParent = sub.parentElement;
sub.addEventListener('keyup', (e) => {
console.log('TOUCHE');
if (e.keyCode === 27) {
console.log('ECHAP');
subParent.setAttribute('aria-expanded', 'false');
}
e.stopImmediatePropagation();
});
})
}
function menu_onFocusDetection() {
focusDetectionEntry.forEach(sub => {
var subParent = sub.parentElement;
sub.addEventListener('focus', function (e) {
subParent.setAttribute('aria-expanded', 'true');
console.log('FOCUS');
e.stopImmediatePropagation();
});
subParent.addEventListener('focusout', function (e) {
console.log('FOCUS OUT');
//console.log(e.relatedTarget); //target actuel
if (!subParent.contains(e.relatedTarget)) {
subParent.setAttribute('aria-expanded', 'false');
}
e.stopImmediatePropagation();
});
})
}
I tried something like that, but not successfull :
function menu_onFocusDetection() {
focusDetectionEntry.forEach(sub => {
var subParent = sub.parentElement;
// si focus sur le bouton, on modifie sont parent
function test(ev) {
subParent.setAttribute('aria-expanded', 'true');
console.log('FOCUS');
ev.stopImmediatePropagation();
}
// si le focus sort du li
function test2(ev2) {
// console.log(ev2.relatedTarget); //target actuel
console.log('FOCUS OUT');
if (!subParent.contains(ev2.relatedTarget)) {
subParent.setAttribute('aria-expanded', 'false');
}
ev2.stopImmediatePropagation();
}
if (window.innerWidth > 770) {
sub.addEventListener('focus', test);
sub.addEventListener('focusout', test2);
} else {
sub.removeEventListener('focus', test);
sub.removeEventListener('focusout', test2);
}
})
}
Ok, so here it is the answer :
I had to split my function and do the condition in each.
window.addEventListener("DOMContentLoaded", onLoadFunction);
function onLoadFunction(e) {
onResizeFunction(); //trigger resize function immediately
window.addEventListener("resize", onResizeFunction);
}
function onResizeFunction(e) {
menu_onFocusDetection();
}
function initEntries() {
focusDetectionEntry = document.querySelectorAll('.nav-list--focus-detection > li[aria-expanded] > button');
}
function focus(e) {
this.parentElement.setAttribute('aria-expanded', 'true');
e.stopImmediatePropagation();
}
function menu_onFocusDetection() {
focusDetectionEntry.forEach(sub => {
var subParent = sub.parentElement;
if (window.innerWidth > 770) {
sub.addEventListener('focus', focus);
subParent.addEventListener('focusout', focusOut);
} else {
sub.removeEventListener('focus', focus);
subParent.removeEventListener('focusout', focusOut);
}
});
}