1(function ($) { 2 $.fn.homelocalExplorerRelevanceSearch = function ( 3 rootApp, 4 options, 5 settings, 6 ) { 7 const debounce = (func, timeout = 300) => { 8 let timer; 9 return (...args) => { 10 clearTimeout(timer); 11 timer = setTimeout(() => { 12 func.apply(this, args); 13 }, timeout); 14 }; 15 }; 16 17 const $container = $(this); 18 19 const selector = { 20 form: ".hfse-relevance-form", 21 input: ".relevance_search_input", 22 searchId: ".relevance_search_id", 23 recentSearchContainer: ".relevance_recent_search", 24 recentSearchItem: ".relevance_recent_search_item", 25 clearHistoryBtn: ".relevance_search_clear_history_btn", 26 loaderModal: "#hfse-relevance-search-loader-modal", 27 }; 28 29 let showingRecentSearches = false; 30 let aiRequest; 31 32 const app = { 33 init: () => { 34 // ai search 35 $container.on("submit", selector.form, app.onAiSearchFormSubmit); 36 37 $container.on( 38 "input", 39 selector.input, 40 debounce(app.onAiSearchInputChange, 300), 41 ); 42 43 // hfse-relevance-search-abort-btn 44 $(selector.loaderModal).on( 45 "click", 46 ".hfse-relevance-search-abort-btn", 47 app.abortyAiSearch, 48 ); 49 50 if (options.hide_relevance_search_history !== "1") { 51 app.initSearchHistory(); 52 } 53 54 app.onAiSearchInputChange(); 55 56 $container.on("reset", function () { 57 $container.find(selector.input).val(""); 58 $container.find(selector.searchId).val(""); 59 app.onAiSearchInputChange(); 60 }); 61 }, 62 63 initSearchHistory: () => { 64 $container.on("focus", selector.input, app.showRecentSearches); 65 66 // $container.on("blur", selector.input, app.hideRecentSearches); 67 $(document).on("click", function (event) { 68 if ( 69 showingRecentSearches && 70 !$(event.target).closest($container.find(selector.input)).length && 71 !$(event.target).closest( 72 $container.find(selector.recentSearchContainer), 73 ).length 74 ) { 75 app.hideRecentSearches(); 76 } 77 }); 78 79 $container.on( 80 "click", 81 selector.recentSearchItem, 82 app.onAiSearchLinkClick, 83 ); 84 85 $container.on( 86 "click", 87 selector.clearHistoryBtn, 88 app.clearRecentSearches, 89 ); 90 }, 91 92 clearRecentSearches: (e) => { 93 e.preventDefault(); 94 95 localStorage.removeItem("recentAiSearches"); 96 97 app.hideRecentSearches(); 98 99 return false; 100 }, 101 102 getRecentSearches: () => { 103 let recentSearches = localStorage.getItem("recentAiSearches"); 104 if (recentSearches) { 105 recentSearches = JSON.parse(recentSearches); 106 return recentSearches; 107 } 108 109 return []; 110 }, 111 112 addRecentSearch: (query, query_hash) => { 113 let recentSearches = app.getRecentSearches(); 114 115 // check if query already exists 116 for (let i = 0; i < recentSearches.length; i++) { 117 if (recentSearches[i].query === query) { 118 return; 119 } 120 } 121 122 recentSearches.unshift({ 123 query: query, 124 query_hash: query_hash, 125 }); 126 127 localStorage.setItem( 128 "recentAiSearches", 129 JSON.stringify(recentSearches), 130 ); 131 }, 132 133 showRecentSearches: () => { 134 const $target = $container.find(selector.recentSearchContainer); 135 const recentSearches = app.getRecentSearches(); 136 137 $target.empty(); 138 139 if (recentSearches.length > 0) { 140 const itemsLimit = Math.min( 141 recentSearches.length, 142 parseInt(settings.relevance_search_history_limit, 10), 143 ); 144 145 showingRecentSearches = true; 146 147 $target.append(` 148 <div class="relevance_recent_search_items"></div> 149 <div class="hk-margin-small hk-flex hk-flex-right"> 150 <button class="hk-button hk-button-link hk-button-small relevance_search_clear_history_btn">${settings.relevance_search_clear_history}</button> 151 </div> 152 `); 153 154 const $items = $target.find(".relevance_recent_search_items"); 155 156 for (let i = 0; i < itemsLimit; i++) { 157 const $item = $(` 158 <button class="relevance_recent_search_item" data-query="${recentSearches[i].query}" data-query-hash="${recentSearches[i].query_hash}">${recentSearches[i].query}</button> 159 `); 160 161 $items.append($item); 162 } 163 164 $target.show(); 165 } 166 }, 167 168 hideRecentSearches: () => { 169 showingRecentSearches = false;
170 $container.find(selector.recentSearchContainer).hide(); 171 }, 172 173 onAiSearchLinkClick: (e) => { 174 e.preventDefault(); 175 176 $container.find(selector.recentSearchContainer).hide(); 177 178 const query = $(e.target).data("query"); 179 const query_hash = $(e.target).data("query-hash"); 180 181 $container.find(selector.input).val(query); 182 $container.find(selector.searchId).val(query_hash); 183 184 app.onAiSearchInputChange(); 185 186 app.onAiSearchFormSubmit(); 187 }, 188 189 onAiSearchInputChange: () => { 190 const $btn = $container.find(".relevance_search_submit"); 191 const value = $container.find(selector.input).val(); 192 193 if (value.length > 0) { 194 $btn.prop("disabled", false); 195 } else { 196 $btn.prop("disabled", true); 197 } 198 }, 199 200 abortyAiSearch: () => { 201 if (aiRequest && aiRequest.readyState !== 4) { 202 aiRequest.abort(); 203 // $container.removeClass("loading"); 204 hkUIkit.modal(selector.loaderModal).hide(); 205 } 206 }, 207 208 onAiSearchFormSubmit: () => { 209 // $container.addClass("loading"); 210 211 hkUIkit.modal(selector.loaderModal).show(); 212 213 // $container 214 // .find(".hfse-properties .property-item") 215 // .not(".property-loading") 216 // .remove(); 217 218 // add property loading skeleton. 219 // for (let i = 0; i < options.per_page; i++) { 220 // $container 221 // .find(".hfse-properties") 222 // .append(rootApp.getPropertyLoadingHtml()); 223 // } 224 225 aiRequest = $.ajax({ 226 type: "POST", 227 url: settings.api_url + "homelocal/v1/relevance-search/process-query", 228 data: { 229 query: $container.find(selector.input).val(), 230 }, 231 }) 232 .done((response) => { 233 if (response.query_hash) { 234 app.addRecentSearch(response.query, response.query_hash); 235 236 $container.find(selector.searchId).val(response.query_hash); 237 238 if (options.grid === "0") { 239 // build url params. 240 241 let params = { 242 relevance_search_id: response.query_hash, 243 }; 244 245 if (response.response.checkin && response.response.checkout) { 246 params.checkin = response.response.checkin; 247 params.checkout = response.response.checkout; 248 } 249 250 if (response.response.bedrooms) { 251 params.bedrooms = response.response.bedrooms; 252 } 253 if (response.response.bathrooms) { 254 params.bathrooms = response.response.bathrooms; 255 } 256 if (response.response.amenities) { 257 params.amenity = response.response.amenities.join(","); 258 } 259 260 if (response.response.adults) { 261 params.adults = response.response.adults; 262 } 263 if (response.response.children) { 264 params.children = response.response.children; 265 } 266 params.pets = response.response.pets ? "yes" : "no"; 267 268 if (response.response.groups) { 269 params.group = response.response.groups.join(","); 270 } 271 if (response.response.cities) { 272 params.city = response.response.cities.join(","); 273 } 274 if (response.response.types) { 275 params.type = response.response.types.join(","); 276 } 277 if (response.response.locations) { 278 params.location = response.response.locations.join(","); 279 } 280 281 let redirectUrl = 282 $container.find(selector.form).attr("action") + 283 "?" + 284 $.param(params); 285 286 window.location.href = redirectUrl; 287 return false; 288 } 289 290 rootApp.setExplorerParams(response.response); 291 rootApp.clearFilterChangeTimer(); 292 rootApp.performFilter(); 293 294 return false;
295 } 296 }) 297 .fail((response) => { 298 if (response.statusText === "abort") { 299 console.debug("Request was aborted"); 300 } else if (response.responseJSON && response.responseJSON.message) { 301 alert(response.responseJSON.message); 302 } else { 303 alert(settings.relevance_search_failed_message); 304 } 305 }) 306 .always(() => { 307 // $container.removeClass("loading"); 308 hkUIkit.modal(selector.loaderModal).hide(); 309 }); 310 311 return false; 312 }, 313 }; 314 315 return app; 316 }; 317})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.