22//
33// SPDX-License-Identifier: GPL-3.0-or-later
44
5- $ ( document ) . ready ( ( ) => {
5+ document . addEventListener ( "DOMContentLoaded" , ( ) => {
66 searchPreview ( "#replace" , "#id_replace_q" ) ;
77 searchPreview ( "#bulk-edit" , "#id_bulk_q" ) ;
88 searchPreview ( "#addon-form" , "#id_bulk_q" ) ;
@@ -15,20 +15,27 @@ $(document).ready(() => {
1515 *
1616 */
1717 function searchPreview ( searchForm , searchElement ) {
18- const $searchForm = $ ( searchForm ) ;
19- const $searchElement = $searchForm . find ( searchElement ) ;
18+ const form = document . querySelector ( searchForm ) ;
19+ const searchInput = form ?. querySelector ( searchElement ) ;
20+
21+ if ( ! form || ! searchInput ) {
22+ return ;
23+ }
2024
2125 // Create the preview element
22- const $searchPreview = $ ( '<div id="search-preview"></div>' ) ;
23- $searchElement . parent ( ) . parent ( ) . parent ( ) . after ( $searchPreview ) ;
26+ const searchPreview = document . createElement ( "div" ) ;
27+ searchPreview . id = "search-preview" ;
28+ searchInput . parentElement ?. parentElement ?. parentElement ?. after (
29+ searchPreview ,
30+ ) ;
2431
2532 let debounceTimeout = null ;
2633
2734 // Update the preview while typing with a debounce of 300ms
28- $searchElement . on ( "input" , ( ) => {
29- $ searchPreview. show ( ) ;
30- const userSearchInput = $searchElement . val ( ) ;
31- const searchQuery = buildSearchQuery ( $searchElement ) ;
35+ searchInput . addEventListener ( "input" , ( ) => {
36+ searchPreview . style . display = "block" ;
37+ const userSearchInput = searchInput . value ;
38+ const searchQuery = buildSearchQuery ( searchInput ) ;
3239
3340 // Clear the previous timeout to prevent the previous
3441 // request since the user is still typing
@@ -37,56 +44,72 @@ $(document).ready(() => {
3744 // fetch search results but not too often
3845 debounceTimeout = setTimeout ( ( ) => {
3946 if ( userSearchInput ) {
40- $ . ajax ( {
41- url : "/api/units/" ,
42- method : "GET" ,
43- data : { q : searchQuery } ,
44- success : ( response ) => {
47+ const url = `/api/units/?${ new URLSearchParams ( {
48+ q : searchQuery ,
49+ } ) . toString ( ) } `;
50+ fetch ( url , {
51+ headers : {
52+ Accept : "application/json" ,
53+ "X-Requested-With" : "XMLHttpRequest" ,
54+ } ,
55+ } )
56+ . then ( ( response ) => {
57+ if ( ! response . ok ) {
58+ return null ;
59+ }
60+ return response . json ( ) ;
61+ } )
62+ . then ( ( response ) => {
63+ if ( response === null ) {
64+ return ;
65+ }
4566 // Clear previous search results
46- $ searchPreview. html ( "" ) ;
47- $ ( "#results-num" ) . remove ( ) ;
67+ searchPreview . replaceChildren ( ) ;
68+ searchPreview . querySelector ( "#results-num" ) ? .remove ( ) ;
4869 const results = response . results ;
4970 if ( ! results || results . length === 0 ) {
50- $ searchPreview. text ( gettext ( "No results found" ) ) ;
71+ searchPreview . textContent = gettext ( "No results found" ) ;
5172 } else {
5273 showResults ( results , response . count , searchQuery ) ;
5374 }
54- } ,
55- } ) ;
75+ } ) ;
5676 }
5777 } , 300 ) ; // If the user stops typing for 300ms, the search results will be fetched
5878 } ) ;
5979
6080 // Show the preview on focus
61- $searchElement . on ( "focus" , ( ) => {
62- if ( $searchElement . val ( ) !== "" && $searchPreview . html ( ) !== "" ) {
63- $searchPreview . show ( ) ;
64- $ ( "#results-num" ) . show ( ) ;
81+ searchInput . addEventListener ( "focus" , ( ) => {
82+ if ( searchInput . value !== "" && searchPreview . innerHTML !== "" ) {
83+ searchPreview . style . display = "block" ;
84+ const resultsNumber = searchPreview . querySelector ( "#results-num" ) ;
85+ if ( resultsNumber ) {
86+ resultsNumber . style . display = "" ;
87+ }
6588 }
6689 } ) ;
6790
6891 // Close the preview on form submit, form reset, and form clear
6992 // or if there is no search query
70- $searchForm . on ( "input" , ( ) => {
71- if ( $searchElement . val ( ) === "" ) {
72- $ searchPreview. hide ( ) ;
73- $ ( "#results-num" ) . remove ( ) ;
93+ form . addEventListener ( "input" , ( ) => {
94+ if ( searchInput . value === "" ) {
95+ searchPreview . style . display = "none" ;
96+ searchPreview . querySelector ( "#results-num" ) ? .remove ( ) ;
7497 }
7598 } ) ;
76- $searchForm . on ( "submit" , ( ) => {
77- $ searchPreview. html ( "" ) ;
78- $ searchPreview. hide ( ) ;
79- $ ( "#results-num" ) . remove ( ) ;
99+ form . addEventListener ( "submit" , ( ) => {
100+ searchPreview . replaceChildren ( ) ;
101+ searchPreview . style . display = "none" ;
102+ searchPreview . querySelector ( "#results-num" ) ? .remove ( ) ;
80103 } ) ;
81- $searchForm . on ( "reset" , ( ) => {
82- $ searchPreview. html ( "" ) ;
83- $ searchPreview. hide ( ) ;
84- $ ( "#results-num" ) . remove ( ) ;
104+ form . addEventListener ( "reset" , ( ) => {
105+ searchPreview . replaceChildren ( ) ;
106+ searchPreview . style . display = "none" ;
107+ searchPreview . querySelector ( "#results-num" ) ? .remove ( ) ;
85108 } ) ;
86- $searchForm . on ( "clear" , ( ) => {
87- $ searchPreview. html ( "" ) ;
88- $ ( "#results-num" ) . remove ( ) ;
89- $ searchPreview. hide ( ) ;
109+ form . addEventListener ( "clear" , ( ) => {
110+ searchPreview . replaceChildren ( ) ;
111+ searchPreview . querySelector ( "#results-num" ) ? .remove ( ) ;
112+ searchPreview . style . display = "none" ;
90113 } ) ;
91114
92115 /**
@@ -103,30 +126,44 @@ $(document).ready(() => {
103126 ngettext ( "%s matching string" , "%s matching strings" , count ) ,
104127 [ count ] ,
105128 ) ;
106- const searchUrl = `/search/?q=${ encodeURI ( searchQuery ) } ` ;
107- const resultsNumber = `<a href="${ searchUrl } " target="_blank" rel="noopener noreferrer" id="results-num">${ t } </a>` ;
108- $searchPreview . append ( resultsNumber ) ;
129+ const searchUrl = `/search/?${ new URLSearchParams ( {
130+ q : searchQuery ,
131+ } ) . toString ( ) } `;
132+ const resultsNumber = document . createElement ( "a" ) ;
133+ resultsNumber . setAttribute ( "href" , searchUrl ) ;
134+ resultsNumber . target = "_blank" ;
135+ resultsNumber . rel = "noopener noreferrer" ;
136+ resultsNumber . id = "results-num" ;
137+ resultsNumber . textContent = t ;
138+ searchPreview . append ( resultsNumber ) ;
109139 } else {
110- $ ( "#results-num" ) . remove ( ) ;
140+ searchPreview . querySelector ( "#results-num" ) ? .remove ( ) ;
111141 }
112142
113143 for ( const result of results ) {
114144 const key = result . context ;
115145 const source = result . source ;
146+ const url = WLT . URLs . getLocalPath ( result . web_url ) ;
147+
148+ if ( url === null ) {
149+ continue ;
150+ }
151+
152+ const resultElement = document . createElement ( "a" ) ;
153+ resultElement . setAttribute ( "href" , url ) ;
154+ resultElement . target = "_blank" ;
155+ resultElement . className = "search-result" ;
156+ resultElement . rel = "noopener noreferrer" ;
157+
158+ const keyElement = document . createElement ( "small" ) ;
159+ keyElement . textContent = String ( key ) ;
160+ resultElement . append ( keyElement ) ;
161+
162+ const sourceElement = document . createElement ( "div" ) ;
163+ sourceElement . textContent = String ( source ) ;
164+ resultElement . append ( sourceElement ) ;
116165
117- // Make the URL relative
118- // TODO: is this regexp really needed?
119- const url = result . web_url . replace ( / ^ [ a - z A - Z ] + : \/ \/ [ ^ / ] + \/ / , "/" ) ;
120- const resultHtml = `
121- <a href="${ url } " target="_blank" id="search-result" rel="noopener noreferrer">
122- <small>${ key } </small>
123- <div>
124- ${ source . toString ( ) }
125- </div>
126- </a>
127- ` ;
128-
129- $searchPreview . append ( resultHtml ) ;
166+ searchPreview . append ( resultElement ) ;
130167 }
131168 }
132169 }
@@ -137,24 +174,23 @@ $(document).ready(() => {
137174 * The path lookup is also added to the search query.
138175 * Built in the following format: `path:proj/comp filters`.
139176 *
140- * @param {jQuery } $ searchElement - The user input.
177+ * @param {HTMLInputElement|HTMLTextAreaElement } searchElement - The user input.
141178 * @returns {string } - The built search query string.
142179 *
143180 * */
144- function buildSearchQuery ( $ searchElement) {
181+ function buildSearchQuery ( searchElement ) {
145182 let builtSearchQuery = "" ;
146183
147184 // Add path lookup to the search query
148- const projectPath = $ searchElement
185+ const projectPath = searchElement
149186 . closest ( "form" )
150- . find ( "input[name=path]" )
151- . val ( ) ;
187+ ?. querySelector ( "input[name=path]" ) ?. value ;
152188 if ( projectPath ) {
153189 builtSearchQuery = `path:${ projectPath } ` ;
154190 }
155191
156192 // Add filters to the search query
157- const filters = $ searchElement. val ( ) ;
193+ const filters = searchElement . value ;
158194 if ( filters ) {
159195 builtSearchQuery = `${ builtSearchQuery } ${ filters } ` ;
160196 }
0 commit comments