/
menu.es6.js
143 lines (133 loc) · 4.46 KB
/
menu.es6.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/**
* @copyright Copyright (C) 2005 - 2018 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
function topLevelMouseOver(el, settings) {
const ulChild = el.querySelector('ul');
if (ulChild) {
ulChild.setAttribute('aria-hidden', 'false');
ulChild.classList.add(settings.menuHoverClass);
}
}
function topLevelMouseOut(el, settings) {
const ulChild = el.querySelector('ul');
if (ulChild) {
ulChild.setAttribute('aria-hidden', 'true');
ulChild.classList.remove(settings.menuHoverClass);
}
}
function setupNavigation(nav) {
const settings = { menuHoverClass: 'show-menu', dir: 'ltr' };
const topLevelChilds = nav.querySelectorAll(':scope > li');
// Set tabIndex to -1 so that top_level_childs can't receive focus until menu is open
topLevelChilds.forEach((topLevelEl) => {
const linkEl = topLevelEl.querySelector('a');
if (linkEl) {
linkEl.tabIndex = '0';
linkEl.addEventListener('mouseover', topLevelMouseOver(topLevelEl, settings));
linkEl.addEventListener('mouseout', topLevelMouseOut(topLevelEl, settings));
}
const spanEl = topLevelEl.querySelector('span');
if (spanEl) {
spanEl.tabIndex = '0';
spanEl.addEventListener('mouseover', topLevelMouseOver(topLevelEl, settings));
spanEl.addEventListener('mouseout', topLevelMouseOut(topLevelEl, settings));
}
topLevelEl.addEventListener('mouseover', (event) => {
const curEl = event.target;
const ulChild = curEl.querySelector('ul');
if (ulChild) {
ulChild.setAttribute('aria-hidden', 'false');
ulChild.classList.add(settings.menuHoverClass);
}
});
topLevelEl.addEventListener('mouseout', (event) => {
const curEl = event.target;
const ulChild = curEl.querySelector('ul');
if (ulChild) {
ulChild.setAttribute('aria-hidden', 'true');
ulChild.classList.remove(settings.menuHoverClass);
}
});
topLevelEl.addEventListener('focus', (event) => {
const curEl = event.target;
const ulChild = curEl.querySelector('ul');
if (ulChild) {
ulChild.setAttribute('aria-hidden', 'true');
ulChild.classList.add(settings.menuHoverClass);
}
});
topLevelEl.addEventListener('blur', (event) => {
const curEl = event.target;
const ulChild = curEl.querySelector('ul');
if (ulChild) {
ulChild.setAttribute('aria-hidden', 'false');
ulChild.classList.remove(settings.menuHoverClass);
}
});
topLevelEl.addEventListener('keydown', (event) => {
const keyName = event.key;
const curEl = event.target;
const curLiEl = curEl.parentElement;
const curUlEl = curLiEl.parentElement;
let prevLiEl = curLiEl.previousElementSibling;
let nextLiEl = curLiEl.nextElementSibling;
if (!prevLiEl) {
prevLiEl = curUlEl.children[curUlEl.children.length - 1];
}
if (!nextLiEl) {
[nextLiEl] = curUlEl.children;
}
switch (keyName) {
case 'ArrowLeft':
event.preventDefault();
if (settings.dir === 'rtl') {
nextLiEl.children[0].focus();
} else {
prevLiEl.children[0].focus();
}
break;
case 'ArrowRight':
event.preventDefault();
if (settings.dir === 'rtl') {
prevLiEl.children[0].focus();
} else {
nextLiEl.children[0].focus();
}
break;
case 'ArrowUp': {
event.preventDefault();
const parent = curLiEl.parentElement.parentElement;
if (parent.nodeName === 'LI') {
parent.children[0].focus();
} else {
prevLiEl.children[0].focus();
}
break;
}
case 'ArrowDown':
event.preventDefault();
if (curLiEl.classList.contains('parent')) {
const child = curLiEl.querySelector('ul');
if (child != null) {
const childLi = child.querySelector('li');
childLi.children[0].focus();
} else {
nextLiEl.children[0].focus();
}
} else {
nextLiEl.children[0].focus();
}
break;
default:
break;
}
});
});
}
document.addEventListener('DOMContentLoaded', () => {
const navs = document.querySelectorAll('.nav');
[].forEach.call(navs, (nav) => {
setupNavigation(nav);
});
});