1
- const updateMenuPositionForSubMenu = ( currentMenuSupplier ) => {
2
- const currentMenu = currentMenuSupplier ( ) ;
1
+ const updateMenuPositionForSubMenu = ( ) => {
2
+ const currentMenu = document . querySelector ( ".nav-container details[open]" ) ;
3
3
const subMenu = currentMenu ?. getElementsByClassName ( 'pure-menu-children' ) ?. [ 0 ] ;
4
4
5
5
subMenu ?. style . setProperty ( '--menu-x' , `${ currentMenu . getBoundingClientRect ( ) . x } px` ) ;
6
6
}
7
7
8
8
// Allow menus to be open and used by keyboard.
9
9
( function ( ) {
10
- var currentMenu ;
11
- var backdrop = document . createElement ( "div" ) ;
12
- backdrop . style = "display:none;position:fixed;width:100%;height:100%;z-index:1" ;
13
- document . documentElement . insertBefore ( backdrop , document . querySelector ( "body" ) ) ;
14
-
15
- addEventListener ( 'resize' , ( ) => updateMenuPositionForSubMenu ( ( ) => currentMenu ) ) ;
10
+ addEventListener ( 'resize' , updateMenuPositionForSubMenu ) ;
16
11
17
12
function previous ( allItems , item ) {
18
13
var i = 1 ;
@@ -37,216 +32,33 @@ const updateMenuPositionForSubMenu = (currentMenuSupplier) => {
37
32
function last ( allItems ) {
38
33
return allItems [ allItems . length - 1 ] ;
39
34
}
40
- function closeMenu ( ) {
41
- if ( this === backdrop ) {
42
- document . documentElement . focus ( ) ;
43
- } else if ( currentMenu . querySelector ( ".pure-menu-link:focus" ) ) {
44
- currentMenu . firstElementChild . focus ( ) ;
35
+ function closeMenu ( ignore ) {
36
+ const menus = Array . prototype . slice . call (
37
+ document . querySelectorAll ( ".nav-container details[open]" ) ) ;
38
+ for ( const menu of menus ) {
39
+ if ( menu !== ignore ) {
40
+ menu . open = false ;
41
+ }
45
42
}
46
- currentMenu . className = currentMenu . className . replace ( "pure-menu-active" , "" ) ;
47
43
currentMenu = null ;
48
- backdrop . style . display = "none" ;
49
- }
50
- backdrop . onclick = closeMenu ;
51
- function openMenu ( newMenu ) {
52
- updateMenuPositionForSubMenu ( ( ) => newMenu ) ;
53
- currentMenu = newMenu ;
54
- newMenu . className += " pure-menu-active" ;
55
- backdrop . style . display = "block" ;
56
44
}
57
45
function menuOnClick ( e ) {
58
- if ( this . getAttribute ( "href" ) != "#" ) {
59
- return ;
60
- }
61
- if ( this . parentNode === currentMenu ) {
62
- closeMenu ( ) ;
63
- this . blur ( ) ;
46
+ if ( ! this . open ) {
47
+ this . focus ( ) ;
64
48
} else {
65
- if ( currentMenu ) closeMenu ( ) ;
66
-
67
- openMenu ( this . parentNode ) ;
49
+ closeMenu ( this ) ;
50
+ updateMenuPositionForSubMenu ( ) ;
68
51
}
69
- e . preventDefault ( ) ;
70
- e . stopPropagation ( ) ;
71
52
} ;
72
- function menuKeyDown ( e ) {
73
- if ( currentMenu ) {
74
- var children = currentMenu . querySelector ( ".pure-menu-children" ) ;
75
- var currentLink = children . querySelector ( ".pure-menu-link:focus" ) ;
76
- var currentItem ;
77
- if ( currentLink && currentLink . parentNode . className . indexOf ( "pure-menu-item" ) !== - 1 ) {
78
- currentItem = currentLink . parentNode ;
79
- }
80
- var allItems = [ ] ;
81
- if ( children ) {
82
- allItems = children . querySelectorAll ( ".pure-menu-item .pure-menu-link" ) ;
83
- }
84
- var switchTo = null ;
85
- switch ( e . key . toLowerCase ( ) ) {
86
- case "escape" :
87
- case "esc" :
88
- closeMenu ( ) ;
89
- e . preventDefault ( ) ;
90
- e . stopPropagation ( ) ;
91
- return ;
92
- case "arrowdown" :
93
- case "down" :
94
- if ( currentLink ) {
95
- // Arrow down when an item other than the last is focused: focus next item.
96
- // Arrow down when the last item is focused: jump to top.
97
- switchTo = ( next ( allItems , currentLink ) || allItems [ 0 ] ) ;
98
- } else {
99
- // Arrow down when a menu is open and nothing is focused: focus first item.
100
- switchTo = allItems [ 0 ] ;
101
- }
102
- break ;
103
- case "arrowup" :
104
- case "up" :
105
- if ( currentLink ) {
106
- // Arrow up when an item other than the first is focused: focus previous item.
107
- // Arrow up when the first item is focused: jump to bottom.
108
- switchTo = ( previous ( allItems , currentLink ) || last ( allItems ) ) ;
109
- } else {
110
- // Arrow up when a menu is open and nothing is focused: focus last item.
111
- switchTo = last ( allItems ) ;
112
- }
113
- break ;
114
- case "tab" :
115
- if ( ! currentLink ) {
116
- // if the menu is open, we should focus trap into it
117
- // this is the behavior of the WAI example
118
- // it is not the same as GitHub, but GitHub allows you to tab yourself out
119
- // of the menu without closing it (which is horrible behavior)
120
- switchTo = e . shiftKey ? last ( allItems ) : allItems [ 0 ] ;
121
- } else if ( e . shiftKey && currentLink === allItems [ 0 ] ) {
122
- // if you tab your way out of the menu, close it
123
- // this is neither what GitHub nor the WAI example do,
124
- // but is a rationalization of GitHub's behavior: we don't want users who know how to
125
- // use tab and enter, but don't know that they can close menus with Escape,
126
- // to find themselves completely trapped in the menu
127
- closeMenu ( ) ;
128
- e . preventDefault ( ) ;
129
- e . stopPropagation ( ) ;
130
- } else if ( ! e . shiftKey && currentLink === last ( allItems ) ) {
131
- // same as above.
132
- // if you tab your way out of the menu, close it
133
- closeMenu ( ) ;
134
- }
135
- break ;
136
- case "enter" :
137
- case "return" :
138
- // enter and return have the default browser behavior,
139
- // but they also close the menu
140
- // this behavior is identical between both the WAI example, and GitHub's
141
- setTimeout ( function ( ) {
142
- closeMenu ( ) ;
143
- } , 100 ) ;
144
- break ;
145
- case "space" :
146
- case " " :
147
- // space closes the menu, and activates the current link
148
- // this behavior is identical between both the WAI example, and GitHub's
149
- if ( document . activeElement instanceof HTMLAnchorElement && ! document . activeElement . hasAttribute ( "aria-haspopup" ) ) {
150
- // It's supposed to copy the behaviour of the WAI Menu Bar
151
- // page, and of GitHub's menus. I've been using these two
152
- // sources to judge what is basically "industry standard"
153
- // behaviour for menu keyboard activity on the web.
154
- //
155
- // On GitHub, here's what I notice:
156
- //
157
- // 1 If you click open a menu, the menu button remains
158
- // focused. If, in this stage, I press space, the menu will
159
- // close.
160
- //
161
- // 2 If I use the arrow keys to focus a menu item, and then
162
- // press space, the menu item will be activated. For
163
- // example, clicking "+", then pressing down, then pressing
164
- // space will open the New Repository page.
165
- //
166
- // Behaviour 1 is why the
167
- // `!document.activeElement.hasAttribute("aria-haspopup")`
168
- // condition is there. It's to make sure the menu-link on
169
- // things like the About dropdown don't get activated.
170
- // Behaviour 2 is why this code is required at all; I want to
171
- // activate the currently highlighted menu item.
172
- document . activeElement . click ( ) ;
173
- }
174
- setTimeout ( function ( ) {
175
- closeMenu ( ) ;
176
- } , 100 ) ;
177
- e . preventDefault ( ) ;
178
- e . stopPropagation ( ) ;
179
- break ;
180
- case "home" :
181
- // home: focus first menu item.
182
- // This is the behavior of WAI, while GitHub scrolls,
183
- // but it's unlikely that a user will try to scroll the page while the menu is open,
184
- // so they won't do it on accident.
185
- switchTo = allItems [ 0 ] ;
186
- break ;
187
- case "end" :
188
- // end: focus last menu item.
189
- // This is the behavior of WAI, while GitHub scrolls,
190
- // but it's unlikely that a user will try to scroll the page while the menu is open,
191
- // so they won't do it on accident.
192
- switchTo = last ( allItems ) ;
193
- break ;
194
- case "pageup" :
195
- // page up: jump five items up, stopping at the top
196
- // the number 5 is used so that we go one page in the
197
- // inner-scrolled Dependencies and Versions fields
198
- switchTo = currentItem || allItems [ 0 ] ;
199
- for ( var n = 0 ; n < 5 ; ++ n ) {
200
- if ( switchTo . previousElementSibling && switchTo . previousElementSibling . className == 'pure-menu-item' ) {
201
- switchTo = switchTo . previousElementSibling ;
202
- }
203
- }
204
- break ;
205
- case "pagedown" :
206
- // page down: jump five items down, stopping at the bottom
207
- // the number 5 is used so that we go one page in the
208
- // inner-scrolled Dependencies and Versions fields
209
- switchTo = currentItem || last ( allItems ) ;
210
- for ( var n = 0 ; n < 5 ; ++ n ) {
211
- if ( switchTo . nextElementSibling && switchTo . nextElementSibling . className == 'pure-menu-item' ) {
212
- switchTo = switchTo . nextElementSibling ;
213
- }
214
- }
215
- break ;
216
- }
217
- if ( switchTo ) {
218
- var switchToLink = switchTo . querySelector ( "a" ) ;
219
- if ( switchToLink ) {
220
- switchToLink . focus ( ) ;
221
- } else {
222
- switchTo . focus ( ) ;
223
- }
224
- e . preventDefault ( ) ;
225
- e . stopPropagation ( ) ;
226
- }
227
- } else if ( e . target . parentNode . className && e . target . parentNode . className . indexOf ( "pure-menu-has-children" ) !== - 1 ) {
228
- switch ( e . key . toLowerCase ( ) ) {
229
- case "arrowdown" :
230
- case "down" :
231
- case "space" :
232
- case " " :
233
- openMenu ( e . target . parentNode ) ;
234
- e . preventDefault ( ) ;
235
- e . stopPropagation ( ) ;
236
- break ;
237
- }
53
+
54
+ const setEvents = ( menus ) => {
55
+ menus = Array . prototype . slice . call ( menus ) ;
56
+ for ( const menu of menus ) {
57
+ menu . addEventListener ( "toggle" , menuOnClick ) ;
238
58
}
239
59
} ;
240
- var menus = Array . prototype . slice . call ( document . querySelectorAll ( ".pure-menu-has-children" ) ) ;
241
- var menusLength = menus . length ;
242
- var menu ;
243
- for ( var i = 0 ; i < menusLength ; ++ i ) {
244
- menu = menus [ i ] ;
245
- menu . firstElementChild . setAttribute ( "aria-haspopup" , "menu" ) ;
246
- menu . firstElementChild . nextElementSibling . setAttribute ( "role" , "menu" ) ;
247
- menu . firstElementChild . addEventListener ( "click" , menuOnClick ) ;
248
- }
249
- document . documentElement . addEventListener ( "keydown" , menuKeyDown ) ;
60
+ setEvents ( document . querySelectorAll ( ".nav-container details" ) ) ;
61
+
250
62
document . documentElement . addEventListener ( "keydown" , function ( ev ) {
251
63
if ( ev . key == "y" && ev . target . tagName != "INPUT" ) {
252
64
let permalink = document . getElementById ( "permalink" ) ;
0 commit comments