44// Local js definitions: 
55/* global addClass, getCurrentValue, hasClass */ 
66/* global onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */ 
7+ /* global hideThemeButtonState, showThemeButtonState */ 
78
89if  ( ! String . prototype . startsWith )  { 
910 String . prototype . startsWith  =  function ( searchString ,  position )  { 
@@ -47,6 +48,14 @@ function getSearchElement() {
4748 return  document . getElementById ( "search" ) ; 
4849} 
4950
51+ function  getThemesElement ( )  { 
52+  return  document . getElementById ( "theme-choices" ) ; 
53+ } 
54+ 
55+ function  getThemePickerElement ( )  { 
56+  return  document . getElementById ( "theme-picker" ) ; 
57+ } 
58+ 
5059// Sets the focus on the search bar at the top of the page 
5160function  focusSearchBar ( )  { 
5261 getSearchInput ( ) . focus ( ) ; 
@@ -137,10 +146,6 @@ function defocusSearchBar() {
137146 sidebar . appendChild ( div ) ; 
138147 } 
139148 } 
140-  var  themePickers  =  document . getElementsByClassName ( "theme-picker" ) ; 
141-  if  ( themePickers  &&  themePickers . length  >  0 )  { 
142-  themePickers [ 0 ] . style . display  =  "none" ; 
143-  } 
144149 } 
145150
146151 function  hideSidebar ( )  { 
@@ -155,10 +160,6 @@ function defocusSearchBar() {
155160 filler . remove ( ) ; 
156161 } 
157162 document . getElementsByTagName ( "body" ) [ 0 ] . style . marginTop  =  "" ; 
158-  var  themePickers  =  document . getElementsByClassName ( "theme-picker" ) ; 
159-  if  ( themePickers  &&  themePickers . length  >  0 )  { 
160-  themePickers [ 0 ] . style . display  =  null ; 
161-  } 
162163 } 
163164
164165 function  showSearchResults ( search )  { 
@@ -376,6 +377,7 @@ function defocusSearchBar() {
376377 document . title  =  titleBeforeSearch ; 
377378 } 
378379 defocusSearchBar ( ) ; 
380+  hideThemeButtonState ( ) ; 
379381 } 
380382
381383 function  handleShortcut ( ev )  { 
@@ -412,7 +414,57 @@ function defocusSearchBar() {
412414 case  "?" :
413415 displayHelp ( true ,  ev ) ; 
414416 break ; 
417+ 
418+  default :
419+  var  themePicker  =  getThemePickerElement ( ) ; 
420+  if  ( themePicker . parentNode . contains ( ev . target ) )  { 
421+  handleThemeKeyDown ( ev ) ; 
422+  } 
423+  } 
424+  } 
425+  } 
426+ 
427+  function  handleThemeKeyDown ( ev )  { 
428+  var  active  =  document . activeElement ; 
429+  var  themes  =  getThemesElement ( ) ; 
430+  switch  ( getVirtualKey ( ev ) )  { 
431+  case  "ArrowUp" :
432+  ev . preventDefault ( ) ; 
433+  if  ( active . previousElementSibling  &&  ev . target . id  !==  "theme-picker" )  { 
434+  active . previousElementSibling . focus ( ) ; 
435+  }  else  { 
436+  showThemeButtonState ( ) ; 
437+  themes . lastElementChild . focus ( ) ; 
438+  } 
439+  break ; 
440+  case  "ArrowDown" :
441+  ev . preventDefault ( ) ; 
442+  if  ( active . nextElementSibling  &&  ev . target . id  !==  "theme-picker" )  { 
443+  active . nextElementSibling . focus ( ) ; 
444+  }  else  { 
445+  showThemeButtonState ( ) ; 
446+  themes . firstElementChild . focus ( ) ; 
447+  } 
448+  break ; 
449+  case  "Enter" :
450+  case  "Return" :
451+  case  "Space" :
452+  if  ( ev . target . id  ===  "theme-picker"  &&  themes . style . display  ===  "none" )  { 
453+  ev . preventDefault ( ) ; 
454+  showThemeButtonState ( ) ; 
455+  themes . firstElementChild . focus ( ) ; 
415456 } 
457+  break ; 
458+  case  "Home" :
459+  ev . preventDefault ( ) ; 
460+  themes . firstElementChild . focus ( ) ; 
461+  break ; 
462+  case  "End" :
463+  ev . preventDefault ( ) ; 
464+  themes . lastElementChild . focus ( ) ; 
465+  break ; 
466+  // The escape key is handled in handleEscape, not here, 
467+  // so that pressing escape will close the menu even if it isn't focused 
416468 } 
417469 } 
418470
0 commit comments