1(function () { 2 var activeAttribute = "data-sf-active"; 3 var dataSfItemAttribute = "data-sfitem"; 4 var activeClassElement = document.querySelector('[data-sf-active-class]'); 5 var activeClass = activeClassElement.dataset && isNotEmpty(activeClassElement.dataset.sfActiveClass) ? activeClassElement.dataset.sfActiveClass : null; 6 var activeClassProcessed = activeClass ? processCssClass(activeClass) : null; 7 var visibilityClassElement = document.querySelector('[data-sf-visibility-hidden]'); 8 var visibilityClassHidden = visibilityClassElement.dataset ? visibilityClassElement.dataset.sfVisibilityHidden : null; 9 var searchAutocompleteItemElement = document.querySelector('[data-sf-search-autocomplete-item-class]'); 10 var autocompleteItemClass = searchAutocompleteItemElement.dataset ? searchAutocompleteItemElement.dataset.sfSearchAutocompleteItemClass : null; 11 var autocompleteItemClassProcessed = autocompleteItemClass ? processCssClass(autocompleteItemClass) : null; 12 13 function processCssClass(str) { 14 var classList = str.split(" "); 15 return classList; 16 } 17 18 function isNotEmpty(attr) { 19 return (attr && attr !== ""); 20 } 21 22 function init(event) { 23 if (event && event.type === "widgetLoaded") { 24 var inputField = event.detail.element.querySelector("[data-sf-role='search-box']"); 25 var searchButton = event.detail.element.querySelector("[data-sf-role='search-button'"); 26 if (inputField) { 27 searchBox(inputField, searchButton); 28 } 29 } else { 30 document.querySelectorAll("[data-sf-role='search-box']").forEach(function (inputField) { 31 if (inputField) { 32 var searchButton = inputField.parentNode.querySelector("[data-sf-role='search-button'"); 33 searchBox(inputField, searchButton); 34 } 35 }); 36 } 37 } 38 39 function searchBox(inputField, searchButton) { 40 initSearchBox(inputField, searchButton); 41 42 var autocompleteDropdown = autocomplete(inputField); 43 44 function initSearchBox(input, button) { 45 if (input) { 46 input.addEventListener("keypress", function (ev) { 47 keypressHandler(ev); 48 }); 49 50 input.addEventListener("keyup", function (ev) { 51 keyupHandler(ev); 52 }); 53 } 54 55 if (button) { 56 button.addEventListener("click", function (ev) { 57 navigateToResults(input); 58 }); 59 } 60 } 61 62 63 function getSearchBoxParams(input) { 64 return { 65 resultsUrl: input.getAttribute("data-sf-results-url"), 66 catalogue: input.getAttribute("data-sf-search-catalogue"), 67 scoringSetting: input.getAttribute("data-sf-scoring-setting"), 68 minSuggestionLength: parseInt(input.getAttribute("data-sf-suggestions-length")), 69 siteId: input.getAttribute("data-sf-site-id"), 70 culture: input.getAttribute("data-sf-culture"), 71 suggestionFields: input.getAttribute("data-sf-suggestions-fields"), 72 servicePath: input.getAttribute("data-sf-service-path"), 73 orderBy: input.getAttribute("data-sf-sort"), 74 resultsForAllSites: input.getAttribute("data-sf-results-all"), 75 filterExpression: input.getAttribute("data-sf-filter-expression"), 76 }; 77 } 78 79 function keypressHandler(e) { 80 if (!e) { 81 e = window.event; 82 } 83 84 var keyCode = e.keyCode || e.charCode; 85 86 if (keyCode == 13) { 87 navigateToResults(e.target); 88 } 89 } 90 91 function keyupHandler(e) { 92 if (e.keyCode != 38 && // up arrow 93 e.keyCode != 40 && // down arrow 94 e.keyCode != 27) { // esc 95 96 var searchText = e.target.value.trim(); 97 var config = getSearchBoxParams(e.target); 98 99 if (config.minSuggestionLength && searchText.length >= config.minSuggestionLength) { 100 getSuggestions(e.target); 101 } else { 102 if (autocompleteDropdown) { 103 autocompleteDropdown.hide(); 104 } 105 } 106 } 107 108 if (e.keyCode == 40) { 109 autocompleteDropdown.focus(); 110 } else if (e.keyCode == 27) { 111 autocompleteDropdown.hide(); 112 } 113 } 114 115 function getSuggestions(input) { 116 var data = getSearchBoxParams(input); 117 var requestUrl = data.servicePath + 118 "/Default.GetSuggestions()" + 119 "?indexName=" + data.catalogue + 120 "&sf_culture=" + data.culture + 121 "&siteId=" + data.siteId + 122 "&scoringInfo=" + data.scoringSetting + 123 "&suggestionFields=" + data.suggestionFields + 124 "&searchQuery=" + input.value; 125 126 if (data.resultsForAllSites == 1) { 127 requestUrl += "&resultsForAllSites=True"; 128 } 129 else if (data.resultsForAllSites == 2) { 130 requestUrl += "&resultsForAllSites=False"; 131 } 132 133 if (data.filterExpression) { 134 requestUrl += "&filterExpression=" + data.filterExpression; 135 } 136 137 fetch(requestUrl).then(function (res) { 138 res.json().then(function (suggestions) { 139 autocompleteDropdown.source(suggestions.value); 140 }); 141 }).catch(function () { 142 autocompleteDropdown.hide(); 143 }); 144 } 145 146 function navigateToResults(input) { 147 if (!input.value) { 148 return; 149 } 150 151 if (window.DataIntelligenceSubmitScript) { 152 DataIntelligenceSubmitScript._client.fetchClient.sendInteraction({ 153 P: "Search for", 154 O: input.value.trim(), 155 OM: { 156 PageUrl: location.href 157 } 158 }); 159 } 160 161 var url = getSearchUrl(input); 162 window.location = url; 163 } 164 165 function getSearchUrl(input) { 166 const query = input.value.trim(); 167 let resultsUrl = input.getAttribute("data-sf-results-url"); 168 const params = {}; 169 170 const [baseUrl, queryStringPart] = resultsUrl.split("?"); 171 resultsUrl = baseUrl; 172 173 if (queryStringPart) { 174 queryStringPart.split("&").forEach(pair => { 175 const [key, value = ""] = pair.split("="); 176 params[key] = decodeURIComponent(value); 177 }); 178 } 179 180 params.indexCatalogue = input.getAttribute("data-sf-search-catalogue"); 181 params.searchQuery = query; 182 params.wordsMode = "AllWords"; 183 params.sf_culture = input.getAttribute("data-sf-culture"); 184 185 const scoringSetting = input.getAttribute("data-sf-scoring-setting"); 186 if (scoringSetting) { 187 params.scoringInfo = scoringSetting; 188 } 189 190 const sorting = input.getAttribute("data-sf-sort"); 191 if (sorting) { 192 params.orderBy = sorting; 193 } 194 195 const filterExpression = input.getAttribute("data-sf-filter-expression"); 196 if (filterExpression) { 197 params.filterExpression = filterExpression; 198 } 199 200 const resultsForAllSites = input.getAttribute("data-sf-results-all"); 201 if (resultsForAllSites == 1) { 202 params.resultsForAllSites = "True"; 203 } else if (resultsForAllSites == 2) { 204 params.resultsForAllSites = "False"; 205 } 206 207 const queryString = Object.entries(params) 208 .map(([key, value]) => `${key}=${encodeURIComponent(value ?? "")}`) 209 .join("&"); 210 211 return `${resultsUrl}?${queryString}`; 212 } 213 214 /** 215 * Autocomplete dropdown functionality 216 */ 217 function autocomplete(inputField) { 218 var suggestionsDropdown = inputField.parentNode.parentNode.querySelector("[data-sf-role='search-box-autocomplete']"); 219 var suggestions = []; 220 221 function setSource(items) { 222 items = Array.isArray(items) ? items : []; 223 suggestions = generateDropdownItems(items); 224 225 clearDropdown(); 226 227 for (var i = 0; i < suggestions.length; i++) { 228 if (suggestionsDropdown) { 229 suggestionsDropdown.appendChild(suggestions[i]); 230 } 231 } 232 233 if (suggestions.length) { 234 show(); 235 } 236 } 237 238 function clearDropdown() { 239 if (suggestionsDropdown) { 240 var child = suggestionsDropdown.lastElementChild; 241 while (child) { 242 suggestionsDropdown.removeChild(child); 243 child = suggestionsDropdown.lastElementChild; 244 } 245 } 246 } 247 248 function generateDropdownItems(suggestions) { 249 var dropDownItems = []; 250 251 if (Array.isArray(suggestions) && suggestions.length > 0) { 252 for (var i = 0; i < suggestions.length; i++) { 253 var dropdownItem = document.createElement("LI"); 254 dropdownItem.setAttribute("role", "option"); 255 var item = document.createElement("BUTTON"); 256 item.setAttribute("role", "presentation"); 257
258 if (autocompleteItemClassProcessed) { 259 item.classList.add(...autocompleteItemClassProcessed); 260 } 261 262 item.setAttribute(dataSfItemAttribute, ""); 263 item.innerText = suggestions[i]; 264 item.title = suggestions[i]; 265 item.tabIndex = -1; 266 dropdownItem.appendChild(item); 267 dropDownItems.push(dropdownItem); 268 } 269 } 270 271 return dropDownItems; 272 } 273 274 function suggestionsKeyupHandler(e) { 275 var key = e.keyCode; 276 var activeLinkSelector = `[${dataSfItemAttribute}][${activeAttribute}]`; 277 var activeLink = suggestionsDropdown.querySelector(activeLinkSelector); 278 if (!activeLink) { 279 return; 280 } 281 282 var previousParent = activeLink.parentElement.previousElementSibling; 283 var nextParent = activeLink.parentElement.nextElementSibling; 284 if (key == 38 && previousParent) { 285 focusItem(previousParent); 286 } else if (key == 40 && nextParent) { 287 focusItem(nextParent); 288 } else if (key == 13) { 289 inputField.value = currentNode.innerText; 290 navigateToResults(inputField); 291 hide(); 292 inputField.focus(); 293 } else if (key == 27) { 294 resetActiveClass(); 295 hide(false); 296 inputField.focus(); 297 } 298 } 299 300 function resetActiveClass() { 301 var activeLink = suggestionsDropdown.querySelector(`[${activeAttribute}]`); 302 303 if (activeLink && activeClassProcessed) { 304 activeLink.classList.remove(...activeClassProcessed); 305 activeLink.removeAttribute(activeAttribute); 306 } 307 } 308 309 function suggestionsClickHandler(e) { 310 var target = e.target; 311 var content = target.innerText; 312 inputField.value = content; 313 navigateToResults(inputField); 314 hide(); 315 } 316 317 function inputKeyupHandler(e) { 318 if (e.keyCode == 40 && suggestions.length) { 319 show(); 320 focusItem(suggestions[0]); 321 } 322 } 323 324 function show() { 325 setAutocompleteDropdownWidth(); 326 327 if (suggestionsDropdown) { 328 if (visibilityClassHidden) { 329 suggestionsDropdown.classList.remove(visibilityClassHidden); 330 } else { 331 suggestionsDropdown.style.display = ""; 332 } 333 } 334 } 335 336 function hide(clear) { 337 if (clear === undefined) { 338 clear = true; 339 } 340 341 if (clear) { 342 clearDropdown(); 343 } 344 clearAutocompleteDropdownWidth(); 345 346 if (suggestionsDropdown) { 347 348 if (visibilityClassHidden) { 349 suggestionsDropdown?.classList.add(visibilityClassHidden); 350 } else { 351 if (suggestionsDropdown != null) 352 suggestionsDropdown.style.display = "none"; 353 } 354 } 355 } 356 357 function dropdownFocusout(e) { 358 if (suggestionsDropdown != null && !suggestionsDropdown.contains(e.relatedTarget)) { 359 hide(false); 360 } 361 } 362 363 function focus() { 364 if (suggestionsDropdown && suggestionsDropdown.children.length) { 365 suggestionsDropdown.children[0].querySelector(`[${dataSfItemAttribute}]`).focus(); 366 } 367 } 368 369 function focusItem(item) { 370 resetActiveClass(); 371 372 var link = item.querySelector(`[${dataSfItemAttribute}]`); 373 374 if (link && activeClassProcessed) { 375 link.classList.add(...activeClassProcessed); 376 } 377 378 //set data attribute, to be used in queries instead of class 379 link.setAttribute(activeAttribute, ""); 380 381 link.focus(); 382 } 383 384 function setAutocompleteDropdownWidth() {
385 const inputWidth = inputField.clientWidth; 386 387 if (suggestionsDropdown) { 388 suggestionsDropdown.style.width = inputWidth + "px"; 389 } 390 } 391 392 function clearAutocompleteDropdownWidth() { 393 if (suggestionsDropdown != null) 394 suggestionsDropdown.style.width = ""; 395 } 396 397 inputField.addEventListener("keyup", inputKeyupHandler); 398 inputField.addEventListener("focusout", dropdownFocusout); 399 suggestionsDropdown?.addEventListener("focusout", dropdownFocusout); 400 suggestionsDropdown?.addEventListener("keyup", suggestionsKeyupHandler); 401 suggestionsDropdown?.addEventListener("click", suggestionsClickHandler); 402 403 return { 404 source: setSource, 405 show: show, 406 hide: hide, 407 clear: clearDropdown, 408 focus: focus 409 }; 410 } 411 } 412 413 document.addEventListener('widgetLoaded', init); 414 document.addEventListener("DOMContentLoaded", init) 415})();
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.