@@ -64,3 +64,87 @@ document.querySelector(".search-bar").addEventListener("input", (ev) => {
6464 wait ( ) ;
6565 worker . postMessage ( ev . target . value ) ;
6666} ) ;
67+
68+
69+ /** Navigation */
70+
71+ let search_result_elt = document . querySelector ( ".search-result" )
72+
73+ function search_results ( ) {
74+ return search_result_elt . children ;
75+ }
76+
77+ function enter_search ( ) {
78+ document . querySelector ( ".search-bar" ) . focus ( ) ;
79+ }
80+
81+ function escape_search ( ) {
82+ document . activeElement . blur ( )
83+ }
84+
85+ function focus_previous_result ( ) {
86+ let results = Array . from ( search_results ( ) ) ;
87+ let current_focus = results . findIndex ( ( elt ) => ( document . activeElement === elt ) ) ;
88+ if ( current_focus === - 1 )
89+ return ;
90+ else if ( current_focus === 0 )
91+ enter_search ( ) ;
92+ else
93+ results [ current_focus - 1 ] . focus ( ) ;
94+ }
95+
96+ function focus_next_result ( ) {
97+ let results = Array . from ( search_results ( ) ) ;
98+ if ( results . length === 0 ) return ;
99+ let current_focus = results . findIndex ( ( elt ) => ( document . activeElement === elt ) ) ;
100+ if ( current_focus === - 1 )
101+ results [ 0 ] . focus ( ) ;
102+ else if ( current_focus + 1 === results . length )
103+ return ;
104+ else
105+ results [ current_focus + 1 ] . focus ( ) ;
106+ }
107+
108+
109+ function is_searching ( ) {
110+ return ( document . querySelectorAll ( ".odoc-search:focus-within" ) . length > 0 ) ;
111+ }
112+
113+ function is_typing ( ) {
114+ return ( document . activeElement === document . querySelector ( ".search-bar" ) ) ;
115+ }
116+
117+ function handle_key_down ( event ) {
118+ if ( is_searching ( ) ) {
119+ if ( event . key === "ArrowUp" ) {
120+ event . preventDefault ( ) ;
121+ focus_previous_result ( ) ;
122+ }
123+ if ( event . key === "ArrowDown" ) {
124+ event . preventDefault ( ) ;
125+ focus_next_result ( ) ;
126+ }
127+ if ( event . key === "Escape" ) {
128+ event . preventDefault ( ) ;
129+ escape_search ( ) ;
130+ }
131+ }
132+ if ( ! ( is_typing ( ) ) ) {
133+ let ascii = event . key . charCodeAt ( 0 ) ;
134+ if ( event . key === "/" ) {
135+ event . preventDefault ( ) ;
136+ enter_search ( ) ;
137+ }
138+ else if ( is_searching ( )
139+ && event . key . length === 1
140+ && ( ( ascii >= 65 && ascii <= 90 ) // lowercase letter
141+ || ( ascii >= 97 && ascii <= 122 ) // uppercase letter
142+ || ( ascii >= 48 && ascii <= 57 ) // numbers
143+ || ( ascii >= 32 && ascii <= 46 ) // ` ` to `.`
144+ || ( ascii >= 58 && ascii <= 64 ) ) // `:` to `@`
145+ )
146+ // We do not prevent default because we want the char to be added to the input
147+ enter_search ( ) ;
148+ }
149+ }
150+ document . addEventListener ( "keydown" , handle_key_down ) ;
0 commit comments