{"version":3,"file":"js/frontend-lib/quicksearch.b3aa649a.js","mappings":"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","sources":["webpack://BSUwp/./assets/src/js/frontend/modules/utilities.js","webpack://BSUwp/./assets/src/js/frontend/lib/quicksearch.js"],"sourcesContent":["/*\n * ***\n * Begin BSU Javascript Utilities\n * ***\n */\n\n/**\n * Function to extract the hash value from a file path.\n * @param {string} filePath - The path to the file with the content hash in the path.\n * @return {string} The extracted hash value.\n */\nexport function getContentHashFromPath(filePath) {\n\tlet hash;\n\tconst regex = /\\/[^/]+\\.([a-f0-9]+)\\.[^/]+$/;\n\tconst match = filePath.match(regex);\n\n\tif (match) {\n\t\thash = match[1];\n\t}\n\treturn hash;\n}\n\n/**\n * Function to save data in the local storage.\n * @param {string} key - The key under which the data will be stored in local storage.\n * @param {any} data - The data to be saved.\n */\nexport function saveLocalStorage(key, data) {\n\tlocalStorage.setItem(key, data);\n}\n\n/**\n * Function to retrieve data from local storage.\n * @param {string} key - The key associated with the data in local storage.\n * @return {any} The data retrieved from local storage, or null if not found.\n */\nexport function getLocalStorage(key) {\n\tconst localStorageData = localStorage.getItem(key);\n\treturn localStorageData ? JSON.parse(localStorageData) : null;\n}\n\n/**\n * Validates the dataToValidate against the value stored in local storage with the provided localStorageKey.\n * @param {string} dataToValidate - The data to be validated.\n * @param {string} localStorageKey - The key associated with the value in local storage to validate against.\n * @return {boolean} true if the data matches what is stored in local storage, false otherwise.\n */\nexport function validateLocalStorage(dataToValidate, localStorageKey) {\n\tconst localStorageData = localStorage.getItem(localStorageKey);\n\n\tif (localStorageData === dataToValidate) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/*\n * ***\n * End BSU Javascript Utilities\n * ***\n */\n","/*\n * *\n * Import internal dependencies\n * *\n */\n\nimport {\n\tgetContentHashFromPath,\n\tsaveLocalStorage,\n\tgetLocalStorage,\n\tvalidateLocalStorage,\n} from '../modules/utilities';\n\n/*\n * ***\n * Begin Quick Search Class\n * ***\n */\nexport class QuickSearch {\n\t/*\n\t * Class constructor function.\n\t */\n\tconstructor(options) {\n\t\t/* Define this.options */\n\t\tthis.options = options;\n\n\t\t/*\n\t\t * Check for require class options\n\t\t */\n\t\tif (!this.options || !this.options.searchInput) {\n\t\t\tthrow new Error(\n\t\t\t\t`Error: Required options not set:\\n ${JSON.stringify(\n\t\t\t\t\tthis.options\n\t\t\t\t)}`\n\t\t\t);\n\t\t}\n\n\t\t/*\n\t\t * Define this.options.quickSearchDataUrlAttribute with a default value if needed.\n\t\t */\n\t\tthis.options.quickSearchDataUrlAttribute =\n\t\t\tthis.options.quickSearchDataUrlAttribute || 'data-bsu-quicksearch';\n\n\t\t/*\n\t\t * Define this.options.parentContainer with a default value if needed.\n\t\t */\n\t\tthis.options.parentContainer =\n\t\t\tthis.options.parentContainer || '.bsu-search';\n\n\t\t/*\n\t\t * Define this.options.resultsContainer\n\t\t * Assign a default value if needed.\n\t\t */\n\t\tthis.options.resultsContainer =\n\t\t\tthis.options.resultsContainer || 'bsu-quicksearch-results';\n\n\t\t/*\n\t\t * Define this.searchInput\n\t\t * The search input element.\n\t\t */\n\t\tthis.searchInput = this.options.searchInput;\n\n\t\t/*\n\t\t * Find the closest ancestor with the class 'collapse'.\n\t\t * Returns null if not found.\n\t\t */\n\t\tthis.collapsingContainer = this.findParentWithClass(\n\t\t\tthis.searchInput,\n\t\t\t'collapse'\n\t\t);\n\n\t\t/*\n\t\t * Define this.parentContainerElement\n\t\t * parentContainer element from the DOM.\n\t\t */\n\t\tthis.parentContainerElement = this.searchInput.closest(\n\t\t\tthis.options.parentContainer\n\t\t);\n\n\t\t/*\n\t\t * Define resultsContainerElement.\n\t\t */\n\t\tthis.resultsContainerElement =\n\t\t\tthis.parentContainerElement.querySelector(\n\t\t\t\t'.' + this.options.resultsContainer\n\t\t\t);\n\n\t\t/*\n\t\t * Define quickSearchDataUrl\n\t\t * The file to load the quichSearch data from.\n\t\t */\n\t\tconst quickSearchDataUrl = this.searchInput.getAttribute(\n\t\t\tthis.options.quickSearchDataUrlAttribute\n\t\t);\n\n\t\t/*\n\t\t * Add passive resize eventListener\n\t\t * Adjust the dimensions of the quicksearch container when the window is resized.\n\t\t * Bind this instance of the class to the function.\n\t\t */\n\t\twindow.addEventListener(\n\t\t\t'resize',\n\t\t\tfunction () {\n\t\t\t\tthis.setQuickSearchResultsDimensions();\n\t\t\t}.bind(this),\n\t\t\t{ passive: true }\n\t\t);\n\n\t\t/*\n\t\t * Add passive scroll eventListener\n\t\t * Adjust the dimensions of the quicksearch container when the window is resized.\n\t\t * Bind this instance of the class to the function.\n\t\t */\n\t\twindow.addEventListener(\n\t\t\t'scroll',\n\t\t\tfunction () {\n\t\t\t\tthis.setQuickSearchResultsDimensions();\n\t\t\t}.bind(this),\n\t\t\t{ passive: true }\n\t\t);\n\n\t\t/*\n\t\t * Define quickSearchHash\n\t\t * The Quicksearch hash value from the quickSearchDataUrl.\n\t\t */\n\t\tconst quickSearchHash = getContentHashFromPath(quickSearchDataUrl);\n\n\t\t/* Define quickSearchData\n\t\t * The Quicksearch data.\n\t\t */\n\t\tlet quickSearchData;\n\n\t\t/*\n\t\t * Check if the quickSearchHash is valid.\n\t\t * If it is not, get the new data and store it locally.\n\t\t * If it is use, the local data.\n\t\t */\n\t\tif (!validateLocalStorage(quickSearchHash, 'quicksearchHash')) {\n\t\t\tfetch(quickSearchDataUrl)\n\t\t\t\t.then((response) => {\n\t\t\t\t\t/* Check of the network response failed and throw a new error to the console and exit the script. */\n\t\t\t\t\tif (!response.ok) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t// eslint-disable-next-line no-undef\n\t\t\t\t\t\t\t`Quicksearch - Network response failed for the following element:\\nsearchInput Element: ${this.searchInput.outerHTML}\\n${error}`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn response.json();\n\t\t\t\t})\n\t\t\t\t.then((data) => {\n\t\t\t\t\t/*\n\t\t\t\t\t * Update quickSearchData with the fetch response data so it can be used later.\n\t\t\t\t\t */\n\t\t\t\t\tquickSearchData = data;\n\n\t\t\t\t\t/*\n\t\t\t\t\t * Get the quickSearchData and save it and the current quicksearchHash to local storage.\n\t\t\t\t\t */\n\t\t\t\t\tsaveLocalStorage(\n\t\t\t\t\t\t'quickSearchData',\n\t\t\t\t\t\tJSON.stringify(quickSearchData)\n\t\t\t\t\t);\n\t\t\t\t\tsaveLocalStorage('quicksearchHash', quickSearchHash);\n\n\t\t\t\t\t/*\n\t\t\t\t\t * Call addSearchEventListener to setup the search.\n\t\t\t\t\t */\n\t\t\t\t\tthis.addSearchEventListener(quickSearchData);\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\t/* Throw a new error to the console and exit the script. */\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Quicksearch - Unable to retrieve the data from the quicksearch.json defined in the following element:\\nsearchInput Element: ${this.searchInput.outerHTML}\\n${error}`\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t} else {\n\t\t\t/*\n\t\t\t * QuickSearch Cache is valid, so use local storage quickSearchData.\n\t\t\t */\n\t\t\tquickSearchData = getLocalStorage('quickSearchData');\n\n\t\t\t/*\n\t\t\t * Call addSearchEventListener to setup the search.\n\t\t\t */\n\t\t\tthis.addSearchEventListener(quickSearchData);\n\t\t}\n\n\t\t/* Check if this.collapsingContainer was found */\n\t\tif (this.collapsingContainer) {\n\t\t\t/*\n\t\t\t * Create a Mutation Observer instance to look for the collapse/opening of the container\n\t\t\t * via the class 'show'.\n\t\t\t */\n\t\t\t// eslint-disable-next-line no-shadow, no-unused-vars\n\t\t\tconst observer = new MutationObserver((mutationsList, observer) => {\n\t\t\t\tmutationsList.forEach((mutation) => {\n\t\t\t\t\t/* Check if the 'show' class has been added or removed */\n\t\t\t\t\tif (mutation.attributeName === 'class') {\n\t\t\t\t\t\tconst classList = mutation.target.classList;\n\n\t\t\t\t\t\t/* Check if the 'show' class is present, indicating the collapse is done */\n\t\t\t\t\t\tif (classList.contains('show')) {\n\t\t\t\t\t\t\t/* Set focus on the searchInput field */\n\t\t\t\t\t\t\tthis.searchInput.focus();\n\t\t\t\t\t\t} else if (!classList.contains('show')) {\n\t\t\t\t\t\t\t/* Remove focus on the searchInput field */\n\t\t\t\t\t\t\tthis.searchInput.blur();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\n\t\t\t/*\n\t\t\t * Define the collapsingToggle for this collapsingContainer\n\t\t\t */\n\t\t\tthis.collapsingToggle = document.querySelector(\n\t\t\t\t`[data-mdb-target=\"#${this.collapsingContainer.id}\"]`\n\t\t\t);\n\n\t\t\t/*\n\t\t\t * Configure and start observing the target node for changes in attributes\n\t\t\t */\n\t\t\tconst config = { attributes: true };\n\t\t\tobserver.observe(this.collapsingContainer, config);\n\t\t}\n\t}\n\n\t/**\n\t * Sets up and adds the event listeners for the quicksearch functionality.\n\t *\n\t * @param {Array} quickSearchData - The data used for performing quick searches.\n\t */\n\taddSearchEventListener(quickSearchData) {\n\t\t/*\n\t\t * Define searchResults array\n\t\t */\n\t\tlet searchResults = [];\n\n\t\t/*\n\t\t * Define selectedIndex\n\t\t * The selcted index of the li elements of the search results.\n\t\t */\n\t\tlet selectedIndex = -1;\n\n\t\t/*\n\t\t * Define liElements.\n\t\t * The list items of the search results.\n\t\t */\n\t\tlet liElements;\n\n\t\t/*\n\t\t * Hides the results container by setting its display style to 'none'.\n\t\t */\n\t\tconst hideResults = () => {\n\t\t\tthis.resultsContainerElement.style.display = 'none';\n\t\t};\n\n\t\t/*\n\t\t * Shows the results container by setting its display style to 'block'.\n\t\t */\n\t\tconst showResults = () => {\n\t\t\t/* Resets the arrow key selections when the results are shown. */\n\t\t\tselectedIndex = -1;\n\n\t\t\t/* Show the results. */\n\t\t\tthis.resultsContainerElement.style.display = 'block';\n\n\t\t\t/*\n\t\t\t * Set the dimensions of the results container.\n\t\t\t * Based on the size of the search container and viewport height.\n\t\t\t */\n\t\t\tthis.setQuickSearchResultsDimensions();\n\t\t};\n\n\t\t/*\n\t\t * Displays a \"Press Enter to search\" message within the results container.\n\t\t */\n\t\tconst showPressEnterMessage = () => {\n\t\t\tshowResults();\n\t\t\tthis.resultsContainerElement.innerHTML =\n\t\t\t\t'
';\n\t\t};\n\n\t\t/**\n\t\t * Handles keydown events for quick search results selection interaction.\n\t\t *\n\t\t * This function responds to specific keydown events, updating the highlighting\n\t\t * of search results and enabling navigation when the Enter key is pressed.\n\t\t *\n\t\t * @param {KeyboardEvent} event - The keydown event object.\n\t\t */\n\t\tconst quickSearchKeyDownEventListener = (event) => {\n\t\t\t/*\n\t\t\t * Define resultsContainerComputedStyle\n\t\t\t * Gets the computed styles so the display status of the element can be checked.\n\t\t\t */\n\t\t\tconst resultsContainerComputedStyle = window.getComputedStyle(\n\t\t\t\tthis.resultsContainerElement\n\t\t\t);\n\n\t\t\t/*\n\t\t\t * Limit the keydown event checking to only when the searchresults are showing.\n\t\t\t */\n\t\t\tif (\n\t\t\t\tresultsContainerComputedStyle.getPropertyValue('display') ===\n\t\t\t\t'block'\n\t\t\t) {\n\t\t\t\tliElements =\n\t\t\t\t\tthis.resultsContainerElement.querySelectorAll('li');\n\n\t\t\t\t/**\n\t\t\t\t * Updates the selection of a list item based on the provided index and key.\n\t\t\t\t *\n\t\t\t\t * @param {number} index - The index of the list item to be selected.\n\t\t\t\t * @param {string} keyPressed - The key representing the direction of selection ('ArrowUp' or 'ArrowDown').\n\t\t\t\t */\n\t\t\t\tfunction selectListItem(index, keyPressed) {\n\t\t\t\t\t/* Remove the previous selectedIndex highlight. */\n\t\t\t\t\tif (selectedIndex >= 0 && liElements[selectedIndex]) {\n\t\t\t\t\t\tliElements[selectedIndex].classList.remove(\n\t\t\t\t\t\t\t'bsu-quicksearch-selected'\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t/*\n\t\t\t\t\t * Check which direction the user wants to go in the list with the arrow keys, and make the appropriate adjustments.\n\t\t\t\t\t */\n\t\t\t\t\tif (selectedIndex === -1 && keyPressed === 'ArrowUp') {\n\t\t\t\t\t\tselectedIndex = index = liElements.length - 1;\n\t\t\t\t\t\tliElements[index].classList.add(\n\t\t\t\t\t\t\t'bsu-quicksearch-selected'\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (\n\t\t\t\t\t\tselectedIndex === -1 &&\n\t\t\t\t\t\tkeyPressed === 'ArrowDown'\n\t\t\t\t\t) {\n\t\t\t\t\t\tselectedIndex = index = 0;\n\t\t\t\t\t\tliElements[index].classList.add(\n\t\t\t\t\t\t\t'bsu-quicksearch-selected'\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (\n\t\t\t\t\t\tselectedIndex === liElements.length - 1 &&\n\t\t\t\t\t\tkeyPressed === 'ArrowDown'\n\t\t\t\t\t) {\n\t\t\t\t\t\tselectedIndex = index = 0;\n\t\t\t\t\t\tliElements[index].classList.add(\n\t\t\t\t\t\t\t'bsu-quicksearch-selected'\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (\n\t\t\t\t\t\tselectedIndex === 0 &&\n\t\t\t\t\t\tkeyPressed === 'ArrowUp'\n\t\t\t\t\t) {\n\t\t\t\t\t\tselectedIndex = index = liElements.length - 1;\n\t\t\t\t\t\tliElements[index].classList.add(\n\t\t\t\t\t\t\t'bsu-quicksearch-selected'\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tselectedIndex = index;\n\t\t\t\t\t\tliElements[index].classList.add(\n\t\t\t\t\t\t\t'bsu-quicksearch-selected'\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\t * Handle the 4 keydown events we want:\n\t\t\t\t * ArrowDown\n\t\t\t\t * ArrowUp\n\t\t\t\t * Enter\n\t\t\t\t * Escape\n\t\t\t\t */\n\t\t\t\tif (event.key === 'ArrowDown') {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tselectListItem(selectedIndex + 1, 'ArrowDown');\n\t\t\t\t} else if (event.key === 'ArrowUp') {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tselectListItem(selectedIndex - 1, 'ArrowUp');\n\t\t\t\t} else if (event.key === 'Enter') {\n\t\t\t\t\tif (selectedIndex >= 0) {\n\t\t\t\t\t\tevent.preventDefault();\n\n\t\t\t\t\t\tconst link =\n\t\t\t\t\t\t\tliElements[selectedIndex].querySelector('a');\n\t\t\t\t\t\tif (link) {\n\t\t\t\t\t\t\twindow.location.href = link.getAttribute('href');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (event.key === 'Escape') {\n\t\t\t\t\thideResults();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t/*\n\t\t * Manages the keydown event listeners for search results.\n\t\t */\n\t\tconst manageSearchResultsKeydownEventListeners = () => {\n\t\t\t/* Set the selectedIndex to -1 so that no results are selected to start with */\n\t\t\tselectedIndex = -1;\n\n\t\t\t/* Remove the old event listener */\n\t\t\tdocument.removeEventListener(\n\t\t\t\t'keydown',\n\t\t\t\tquickSearchKeyDownEventListener\n\t\t\t);\n\n\t\t\t/* Add a new event listener with the updated content */\n\t\t\tdocument.addEventListener(\n\t\t\t\t'keydown',\n\t\t\t\tquickSearchKeyDownEventListener\n\t\t\t);\n\t\t};\n\n\t\t/*\n\t\t * Handles user input in the search input field, performs search, and displays results.\n\t\t */\n\t\tconst handleInput = () => {\n\t\t\t/*\n\t\t\t * Get the search term.\n\t\t\t */\n\t\t\tthis.searchTerm = this.searchInput.value.toLowerCase().trim();\n\n\t\t\t/* Only Seach if this.searchTerm has enough characters. */\n\t\t\tif (this.searchTerm.length >= 2) {\n\t\t\t\t/*\n\t\t\t\t * Set the searchResults.\n\t\t\t\t */\n\t\t\t\tsearchResults = this.searchInData(\n\t\t\t\t\tquickSearchData,\n\t\t\t\t\tthis.searchTerm\n\t\t\t\t);\n\n\t\t\t\t/*\n\t\t\t\t * If there are searchResults\n\t\t\t\t */\n\t\t\t\tif (searchResults.length > 0) {\n\t\t\t\t\t/* Build the results to be displayed from the searchResults data */\n\t\t\t\t\tthis.buildResults(searchResults);\n\n\t\t\t\t\t/*\n\t\t\t\t\t * Show the searchResults.\n\t\t\t\t\t */\n\t\t\t\t\tshowResults();\n\t\t\t\t\tmanageSearchResultsKeydownEventListeners();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t/*\n\t\t\t\t * Hide the searchResults.\n\t\t\t\t */\n\t\t\t\thideResults();\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Show the \"Press Enter to search\" message.\n\t\t\t */\n\t\t\tif (searchResults.length === 0 && this.searchTerm.length >= 2) {\n\t\t\t\tshowPressEnterMessage();\n\t\t\t}\n\t\t};\n\n\t\t/*\n\t\t * Add the this.searchInput 'input' addEventListener\n\t\t */\n\t\tthis.searchInput.addEventListener('input', () => handleInput());\n\n\t\t/*\n\t\t * Add the this.searchInput 'focusout' addEventListener.\n\t\t * Only calls hideResults if the event.relatedTarget is not a child/grandchild of the this.resultsContainerElement.\n\t\t */\n\t\tthis.searchInput.addEventListener('focusout', (event) => {\n\t\t\tconst focusoutElement = event.relatedTarget;\n\t\t\tif (!this.resultsContainerElement.contains(focusoutElement)) {\n\t\t\t\thideResults();\n\t\t\t}\n\t\t});\n\n\t\t/*\n\t\t * Add the this.searchInput 'focus' addEventListener.\n\t\t */\n\t\tthis.searchInput.addEventListener('focus', () => handleInput());\n\t}\n\n\t/**\n\t * Finds and returns the closest parent element with a specified class name.\n\t *\n\t * @param {Element} element - The starting element to search from.\n\t * @param {string} className - The class name to search for in the parent elements.\n\t *\n\t * @return {Element|null} - The closest parent element with the specified class name, or null if not found.\n\t */\n\tfindParentWithClass(element, className) {\n\t\t/* Start from the current element */\n\t\tlet currentElement = element;\n\n\t\t/*\n\t\t * Loop until we reach the top of the DOM (document body).\n\t\t */\n\t\twhile (\n\t\t\tcurrentElement &&\n\t\t\t!currentElement.classList.contains(className)\n\t\t) {\n\t\t\t/*\n\t\t\t * Move up to the parent element\n\t\t\t */\n\t\t\tcurrentElement = currentElement.parentElement;\n\t\t}\n\n\t\t/*\n\t\t * Return the found element (or null if not found)\n\t\t */\n\t\treturn currentElement;\n\t}\n\n\t/* eslint-disable */\n\t/**\n\t * Function to build search results in the specified container\n\t * @param {Array} results - An array of search results.\n\t *\n\t * results example format:\n\t *\n\t * [\n\t * {\n\t * \"title\": \"Category Title\",\n\t * \"items\": [\n\t * {\n\t * \"title\": \"Item Title\",\n\t * \"url\": \"https://url/of/the/item/\",\n\t * \"keywords\": \"comma,seperated,list,of,keywords\",\n\t * \"score\": int(item weight score within it's category)\n\t * },\n\t * ...\n\t * ]\n\t * },\n\t * ...\n\t * ]\n\t *\n\t * @returns {void}\n\t */\n\t/* eslint-enable */\n\n\tbuildResults(results) {\n\t\t/*\n\t\t * Remove any existing results content.\n\t\t */\n\t\tthis.resultsContainerElement.innerHTML = '';\n\n\t\t/*\n\t\t * Loop through the results.\n\t\t */\n\t\tresults.forEach((category) => {\n\t\t\t/*\n\t\t\t * Build the Category Title if there is one and append it to the resultsContainerElement.\n\t\t\t */\n\t\t\tif (category.title) {\n\t\t\t\tconst categoryTitle = document.createElement('h2');\n\t\t\t\tcategoryTitle.textContent = category.title;\n\t\t\t\tcategoryTitle.classList.add(\n\t\t\t\t\t'bsu-quicksearch-category-title',\n\t\t\t\t\t'text-white',\n\t\t\t\t\t'fs-5',\n\t\t\t\t\t'ff-sans',\n\t\t\t\t\t'fw-bolder',\n\t\t\t\t\t'border-bottom',\n\t\t\t\t\t'border-light',\n\t\t\t\t\t'mt-0',\n\t\t\t\t\t'mb-1'\n\t\t\t\t);\n\t\t\t\tthis.resultsContainerElement.appendChild(categoryTitle);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Build the list, looping through the items.\n\t\t\t * Add the list item mouseover/mouseout events.\n\t\t\t * Append it to the resultsContainerElement.\n\t\t\t */\n\t\t\tconst list = document.createElement('ul');\n\n\t\t\tlist.classList.add('list-unstyled');\n\n\t\t\tcategory.items.forEach((result) => {\n\t\t\t\tconst listItem = document.createElement('li');\n\t\t\t\tlistItem.classList.add('ps-0', 'ps-md-3');\n\t\t\t\tlistItem.innerHTML = `${result.title}`;\n\t\t\t\tlist.appendChild(listItem);\n\n\t\t\t\t/*\n\t\t\t\t * Add mouseover eventlistener to add the class bsu-quicksearch-selected.\n\t\t\t\t */\n\t\t\t\tlistItem.addEventListener('mouseover', function () {\n\t\t\t\t\tthis.classList.add('bsu-quicksearch-selected');\n\t\t\t\t});\n\n\t\t\t\t/*\n\t\t\t\t * Add mouseout eventlistener to remove the class bsu-quicksearch-selected.\n\t\t\t\t */\n\t\t\t\tlistItem.addEventListener('mouseout', function () {\n\t\t\t\t\tthis.classList.remove('bsu-quicksearch-selected');\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tthis.resultsContainerElement.appendChild(list);\n\t\t});\n\t}\n\n\t/**\n\t * Function to search the data for the given term\n\t * @param {Object} data - The data to search in.\n\t * @param {string} terms - The search terms.\n\t *\n\t * @return {Array} - An array of search results.\n\t */\n\tsearchInData(data, terms) {\n\t\tconst results = [];\n\n\t\t/*\n\t\t * Split the search term into an array of individual terms.\n\t\t */\n\t\tconst searchTerms = terms.toLowerCase().split(' ');\n\n\t\tfor (const category in data) {\n\t\t\tconst categoryData = data[category].data;\n\t\t\tconst categoryTitle = data[category].title || '';\n\t\t\tconst categoryResults = categoryData\n\t\t\t\t.map((item) => {\n\t\t\t\t\tconst title = item.title.toLowerCase();\n\t\t\t\t\tconst keywords = (item.keywords || '').toLowerCase();\n\n\t\t\t\t\t/*\n\t\t\t\t\t * Define matchScore\n\t\t\t\t\t * Check if any of the search terms are found in the title or keywords\n\t\t\t\t\t */\n\t\t\t\t\tconst matchScore = searchTerms.reduce((score, term) => {\n\t\t\t\t\t\tif (title.includes(term)) {\n\t\t\t\t\t\t\t/* Increase the score for a match in title */\n\t\t\t\t\t\t\tscore += 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (keywords.includes(term)) {\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t * Increase the score for a match in keywords.\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tscore += 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn score;\n\t\t\t\t\t}, 0);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttitle: item.title,\n\t\t\t\t\t\turl: item.url,\n\t\t\t\t\t\tkeywords: item.keywords,\n\t\t\t\t\t\tscore: matchScore,\n\t\t\t\t\t};\n\t\t\t\t})\n\t\t\t\t.filter(\n\t\t\t\t\t(result) => result.score > 0\n\t\t\t\t); /* Filter out items with no match */\n\n\t\t\tif (categoryResults.length > 0) {\n\t\t\t\t/* Sort items within each category */\n\t\t\t\tcategoryResults.sort((a, b) => {\n\t\t\t\t\t/* Sort based on the item score (descending order) */\n\t\t\t\t\tif (b.score !== a.score) {\n\t\t\t\t\t\treturn b.score - a.score;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* Secondary sort based on the item title (ascending order) */\n\t\t\t\t\treturn a.title.localeCompare(b.title);\n\t\t\t\t});\n\n\t\t\t\tresults.push({\n\t\t\t\t\ttitle: categoryTitle,\n\t\t\t\t\titems: categoryResults,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t * Return the serch results.\n\t\t */\n\t\treturn results;\n\t}\n\n\t/*\n\t * Set the dimensions of the resultsContainerElement.\n\t * Based on the size of the parentContainer and viewport height.\n\t */\n\tsetQuickSearchResultsDimensions() {\n\t\t/*\n\t\t * Reset the height of this.resultsContainerElement.\n\t\t * This allows for the calculations of the height to be based of the height\n\t\t * of the content inside.\n\t\t */\n\t\tthis.resultsContainerElement.style.height = 'auto';\n\n\t\t/*\n\t\t * Define the viewportHeight\n\t\t */\n\t\tconst viewportHeight =\n\t\t\twindow.innerHeight || document.documentElement.clientHeight;\n\n\t\t/*\n\t\t * Define searchWrapperWidth\n\t\t */\n\t\tconst searchWrapperWidth = this.parentContainerElement.clientWidth;\n\n\t\t/*\n\t\t * Define searchInputElementSizePosition\n\t\t */\n\t\tconst searchInputElementSizePosition =\n\t\t\tthis.searchInput.getBoundingClientRect();\n\n\t\t/*\n\t\t * Define positionFromTop - position of this.searchInput from the top of the viewport\n\t\t */\n\t\tconst positionFromTop = searchInputElementSizePosition.top;\n\n\t\t/*\n\t\t * Define updatedResultsContainerElementHeight\n\t\t */\n\t\tconst updatedResultsContainerElementHeight =\n\t\t\tviewportHeight -\n\t\t\tpositionFromTop -\n\t\t\tthis.searchInput.clientHeight * 2;\n\n\t\t/*\n\t\t * Check if the height of this.resultsContainerElement needs to be changed\n\t\t */\n\t\tif (\n\t\t\tparseInt(this.resultsContainerElement.clientHeight) >\n\t\t\tparseInt(updatedResultsContainerElementHeight)\n\t\t) {\n\t\t\t/* Set this.resultsContainerElement height */\n\t\t\tthis.resultsContainerElement.style.height =\n\t\t\t\tupdatedResultsContainerElementHeight + 'px';\n\t\t}\n\t\t/*\n\t\t * Set the width of the resultsContainerElement\n\t\t */\n\t\tthis.resultsContainerElement.style.width = searchWrapperWidth + 'px';\n\t}\n}\n\n/*\n * ***\n * End Quick Search\n * ***\n */\n\n/*\n * Add the eventlistener for the browser.\n * Checking for process.env.NODE_ENV prevents instantiating the class during unit testing.\n */\nif (process.env.NODE_ENV !== 'test') {\n\tdocument.addEventListener('DOMContentLoaded', function () {\n\t\t/*\n\t\t * Get all the elements with the class 'bsu-quicksearch'.\n\t\t */\n\t\tconst quickSearch = document.querySelectorAll('.bsu-quicksearch');\n\n\t\tquickSearch.forEach(function (element) {\n\t\t\t/*\n\t\t\t * Instantiate QuickSearch.\n\t\t\t */\n\t\t\t// eslint-disable-next-line no-unused-vars\n\t\t\tconst headerSearch = new QuickSearch({\n\t\t\t\tsearchInput: element,\n\t\t\t});\n\t\t});\n\t});\n}\n"],"names":["saveLocalStorage","key","data","localStorage","setItem","QuickSearch","constructor","options","this","searchInput","Error","JSON","stringify","quickSearchDataUrlAttribute","parentContainer","resultsContainer","collapsingContainer","findParentWithClass","parentContainerElement","closest","resultsContainerElement","querySelector","quickSearchDataUrl","getAttribute","window","addEventListener","setQuickSearchResultsDimensions","bind","passive","quickSearchHash","getContentHashFromPath","filePath","hash","match","quickSearchData","validateLocalStorage","dataToValidate","localStorageKey","getItem","fetch","then","response","ok","outerHTML","error","json","addSearchEventListener","catch","getLocalStorage","localStorageData","parse","observer","MutationObserver","mutationsList","forEach","mutation","attributeName","classList","target","contains","focus","blur","collapsingToggle","document","id","config","attributes","observe","liElements","searchResults","selectedIndex","hideResults","style","display","showResults","showPressEnterMessage","innerHTML","quickSearchKeyDownEventListener","event","getComputedStyle","getPropertyValue","selectListItem","index","keyPressed","remove","length","add","querySelectorAll","preventDefault","link","location","href","handleInput","searchTerm","value","toLowerCase","trim","searchInData","buildResults","removeEventListener","focusoutElement","relatedTarget","element","className","currentElement","parentElement","results","category","title","categoryTitle","createElement","textContent","appendChild","list","items","result","listItem","url","terms","searchTerms","split","categoryData","categoryResults","map","item","keywords","matchScore","reduce","score","term","includes","filter","sort","a","b","localeCompare","push","height","viewportHeight","innerHeight","documentElement","clientHeight","searchWrapperWidth","clientWidth","updatedResultsContainerElementHeight","getBoundingClientRect","top","parseInt","width"],"sourceRoot":""}