@@ -41,13 +41,36 @@ function fetchSearchResults(query) {
4141}
4242
4343/**
44- * Removes any current search results from the display.
45- * @returns {void }
44+ * Clears the search results from the display.
45+ * If the removeEventListener flag is true, removes the click event listener from the document.
46+ * @param {boolean } [removeEventListener=false] - Optional flag to indicate if the click event listener should be removed. Default is false.
47+ * @returns {void } - This function doesn't return anything.
4648 */
47- function clearSearchResults ( ) {
48- while ( resultsElement . firstChild ) {
49- resultsElement . removeChild ( resultsElement . firstChild ) ;
49+ function clearSearchResults ( removeEventListener = false ) {
50+ resultsElement . innerHTML = "" ;
51+ if ( removeEventListener && document . clickEventAdded ) {
52+ document . removeEventListener ( 'click' , handleDocumentClick ) ;
53+ document . clickEventAdded = false ;
5054 }
55+ }
56+
57+ /**
58+ * Displays a "No results found" message in both the live region and results display area.
59+ * This is typically used when no matching results are found in the search.
60+ * @returns {void } - This function doesn't return anything.
61+ */
62+ function showNoResults ( ) {
63+ resultsLiveRegion . innerHTML = "No results found." ;
64+ resultsElement . innerHTML = "No results found." ;
65+ resultsElement . setAttribute ( 'data-results' , 'false' ) ;
66+ }
67+
68+ /**
69+ * Clears any "No results found" message from the live region and results display area.
70+ * @returns {void } - This function doesn't return anything.
71+ */
72+ function clearNoResults ( ) {
73+ resultsLiveRegion . innerHTML = "" ;
5174 resultsElement . innerHTML = "" ;
5275}
5376
@@ -81,9 +104,7 @@ function displaySearchResults(results) {
81104 }
82105
83106 } else {
84- resultsLiveRegion . innerHTML = "No results found." ;
85- resultsElement . innerHTML = "No results found." ;
86- resultsElement . setAttribute ( 'data-results' , 'false' ) ;
107+ showNoResults ( ) ;
87108 }
88109
89110}
@@ -125,12 +146,33 @@ function debounce(callback, delay) {
125146 }
126147}
127148
149+ /**
150+ * Debounced function to fetch search results after 300ms of inactivity.
151+ * Calls `fetchSearchResults` to retrieve data and `displaySearchResults` to show them.
152+ * If an error occurs, clears the search results.
153+ * @param {string } query - The search query.
154+ * @returns {void } - No return value.
155+ * @see debounce - Limits the number of requests during rapid typing.
156+ */
128157const debouncedFetchSearchResults = debounce ( ( query ) => {
129158 fetchSearchResults ( query )
130159 . then ( displaySearchResults )
131- . catch ( clearSearchResults ) ;
160+ . catch ( ( ) => { clearSearchResults ( true ) } ) ;
132161} , 300 ) ;
133162
163+
164+ /**
165+ * Handles the document click event to clear search results if the user clicks outside of the search input or results element.
166+ * @param {MouseEvent } e - The event object representing the click event.
167+ * @returns {void } - This function does not return any value. It directly interacts with the UI by clearing search results.
168+ */
169+ const handleDocumentClick = ( e ) => {
170+ if ( e . target !== resultsElement && e . target !== searchInput ) {
171+ clearSearchResults ( true ) ;
172+ }
173+ }
174+
175+
134176//-----------------------------------------------------------------------------
135177// Event Handlers
136178//-----------------------------------------------------------------------------
@@ -146,14 +188,13 @@ if (searchInput)
146188 else searchClearBtn . setAttribute ( 'hidden' , '' ) ;
147189
148190 if ( query . length > 2 ) {
149-
150191 debouncedFetchSearchResults ( query ) ;
151-
152- document . addEventListener ( 'click' , function ( e ) {
153- if ( e . target !== resultsElement ) clearSearchResults ( ) ;
154- } ) ;
192+ if ( ! document . clickEventAdded ) {
193+ document . addEventListener (
67ED
'click' , handleDocumentClick ) ;
194+ document . clickEventAdded = true ;
195+ }
155196 } else {
156- clearSearchResults ( ) ;
197+ clearSearchResults ( true ) ;
157198 }
158199
159200 searchQuery = query
@@ -165,19 +206,24 @@ if (searchClearBtn)
165206 searchClearBtn . addEventListener ( 'click' , function ( e ) {
166207 searchInput . value = '' ;
167208 searchInput . focus ( ) ;
168- clearSearchResults ( ) ;
209+ clearSearchResults ( true ) ;
169210 searchClearBtn . setAttribute ( 'hidden' , '' ) ;
170211 } ) ;
171212
172213document . addEventListener ( 'keydown' , function ( e ) {
173214
174215 const searchResults = Array . from ( document . querySelectorAll ( '.search-results__item' ) ) ;
175216
176- if ( e . key === ' Escape' ) {
217+ if ( e . key === " Escape" ) {
177218 e . preventDefault ( ) ;
178219 if ( searchResults . length ) {
179- clearSearchResults ( ) ;
220+ clearSearchResults ( true ) ;
180221 searchInput . focus ( ) ;
222+ } else if (
223+ document . activeElement === searchInput
224+ ) {
225+ clearNoResults ( ) ;
226+ searchInput . blur ( ) ;
181227 }
182228 }
183229
0 commit comments