@@ -14,16 +14,18 @@ let $searchResultsContainer
1414let $searchOverlay
1515let $searchInput
1616
17+ // This is our default placeholder, but it can be localized with a <meta> tag
1718let placeholder = 'Search topics, products...'
1819let version
1920let language
2021
2122export default function search ( ) {
23+ // First, only initialize search if the elements are on the page
2224 $searchInputContainer = document . getElementById ( 'search-input-container' )
2325 $searchResultsContainer = document . getElementById ( 'search-results-container' )
24-
2526 if ( ! $searchInputContainer || ! $searchResultsContainer ) return
2627
28+ // This overlay exists so if you click off the search, it closes
2729 $searchOverlay = document . querySelector ( '.search-overlay-desktop' )
2830
2931 // There's an index for every version/language combination
@@ -36,15 +38,25 @@ export default function search () {
3638 placeholder = $placeholderMeta . content
3739 }
3840
41+ // Write the search form into its container
3942 $searchInputContainer . append ( tmplSearchInput ( ) )
4043 $searchInput = $searchInputContainer . querySelector ( 'input' )
4144
42- searchWithYourKeyboard ( '#search-input-container input' , '.ais-Hits-item' )
43- toggleSearchDisplay ( )
44-
45+ // Prevent 'enter' from refreshing the page
4546 $searchInputContainer . querySelector ( 'form' )
4647 . addEventListener ( 'submit' , evt => evt . preventDefault ( ) )
48+
49+ // Search when the user finished typing
4750 $searchInput . addEventListener ( 'keyup' , debounce ( onSearch ) )
51+
52+ // Adds ability to navigate search results with keyboard (up, down, enter, esc)
53+ searchWithYourKeyboard ( '#search-input-container input' , '.ais-Hits-item' )
54+
55+ // If the user already has a query in the URL, parse it and search away
56+ parseExistingSearch ( )
57+
58+ // If not on home page, decide if search panel should be open
59+ toggleSearchDisplay ( ) // must come after parseExistingSearch
4860}
4961
5062// The home page and 404 pages have a standalone search
@@ -64,43 +76,37 @@ function toggleSearchDisplay () {
6476 // If not on homepage...
6577 if ( hasStandaloneSearch ( ) ) return
6678
67- const $input = $searchInput
68-
69- // Open modal if input is clicked
70- $input . addEventListener ( 'focus' , ( ) => {
71- openSearch ( )
72- } )
79+ // Open panel if input is clicked
80+ $searchInput . addEventListener ( 'focus' , openSearch )
7381
74- // Close modal if overlay is clicked
82+ // Close panel if overlay is clicked
7583 if ( $searchOverlay ) {
76- $searchOverlay . addEventListener ( 'click' , ( ) => {
77- closeSearch ( )
78- } )
84+ $searchOverlay . addEventListener ( 'click' , closeSearch )
7985 }
8086
81- // Open modal if page loads with query in the params/input
82- if ( $input . value ) {
87+ // Open panel if page loads with query in the params/input
88+ if ( $searchInput . value ) {
8389 openSearch ( )
8490 }
8591}
8692
93+ // On most pages, opens the search panel
8794function openSearch ( ) {
8895 $searchInput . classList . add ( 'js-open' )
8996 $searchResultsContainer . classList . add ( 'js-open' )
9097 $searchOverlay . classList . add ( 'js-open' )
9198}
9299
100+ // Close panel if not on homepage
93101function closeSearch ( ) {
94- // Close modal if not on homepage
95102 if ( ! hasStandaloneSearch ( ) ) {
96103 $searchInput . classList . remove ( 'js-open' )
97104 $searchResultsContainer . classList . remove ( 'js-open' )
98105 $searchOverlay . classList . remove ( 'js-open' )
99106 }
100107
101- const $hits = $searchResultsContainer . querySelector ( '.ais-Hits' )
102- if ( $hits ) $hits . style . display = 'none'
103108 $searchInput . value = ''
109+ onSearch ( )
104110}
105111
106112function deriveLanguageCodeFromPath ( ) {
@@ -122,6 +128,7 @@ function deriveVersionFromPath () {
122128 : versionObject . miscBaseName
123129}
124130
131+ // Wait for the event to stop triggering for X milliseconds before responding
125132function debounce ( fn , delay = 300 ) {
126133 let timer
127134 return ( ...args ) => {
@@ -130,34 +137,47 @@ function debounce (fn, delay = 300) {
130137 }
131138}
132139
133- async function onSearch ( evt ) {
134- const query = evt . target . value
135-
136- const url = new URL ( location . origin )
137- url . pathname = '/search'
138- url . search = new URLSearchParams ( { query, version, language } ) . toString ( )
140+ // When the user finishes typing, update the results
141+ async function onSearch ( ) {
142+ const query = $searchInput . value
139143
140- const response = await fetch ( url , {
141- method : 'GET' ,
142- headers : {
143- 'Content-Type' : 'application/json'
144- }
145- } )
146- const results = response . ok ? await response . json ( ) : [ ]
144+ // Update the URL with the search parameters in the query string
145+ const pushUrl = new URL ( location )
146+ pushUrl . search = query ? new URLSearchParams ( { query } ) : ''
147+ history . pushState ( { } , '' , pushUrl )
148+
149+ // If there's a query, call the endpoint
150+ // Otherwise, there's no results by default
151+ let results = [ ]
152+ if ( query . trim ( ) ) {
153+ const endpointUrl = new URL ( location . origin )
154+ endpointUrl . pathname = '/search'
155+ endpointUrl . search = new URLSearchParams ( { language, version, query } )
156+
157+ const response = await fetch ( endpointUrl , {
158+ method : 'GET' ,
159+ headers : {
160+ 'Content-Type' : 'application/json'
161+ }
162+ } )
163+ results = response . ok ? await response . json ( ) : [ ]
164+ }
147165
166+ // Either way, update the display
148167 $searchResultsContainer . querySelectorAll ( '*' ) . forEach ( el => el . remove ( ) )
149168 $searchResultsContainer . append (
150169 tmplSearchResults ( results )
151170 )
152-
153171 toggleStandaloneSearch ( )
154172
155173 // Analytics tracking
156- sendEvent ( {
157- type : 'search' ,
158- search_query : query
159- // search_context
160- } )
174+ if ( query . trim ( ) ) {
175+ sendEvent ( {
176+ type : 'search' ,
177+ search_query : query
178+ // search_context
179+ } )
180+ }
161181}
162182
163183// If on homepage, toggle results container if query is present
@@ -189,6 +209,14 @@ function toggleStandaloneSearch () {
189209 if ( queryPresent && $results ) $results . style . display = 'block'
190210}
191211
212+ // If the user shows up with a query in the URL, go ahead and search for it
213+ function parseExistingSearch ( ) {
214+ const params = new URLSearchParams ( location . search )
215+ if ( ! params . has ( 'query' ) ) return
216+ $searchInput . value = params . get ( 'query' )
217+ onSearch ( )
218+ }
219+
192220/** * Template functions ***/
193221
194222function tmplSearchInput ( ) {
0 commit comments