{"version":3,"file":"form-autocomplete.min.js","sources":["https:\/\/www.alsg.org\/home\/lib\/amd\/src\/form-autocomplete.js"],"sourcesContent":["\/\/ This file is part of Moodle - http:\/\/moodle.org\/\n\/\/\n\/\/ Moodle is free software: you can redistribute it and\/or modify\n\/\/ it under the terms of the GNU General Public License as published by\n\/\/ the Free Software Foundation, either version 3 of the License, or\n\/\/ (at your option) any later version.\n\/\/\n\/\/ Moodle is distributed in the hope that it will be useful,\n\/\/ but WITHOUT ANY WARRANTY; without even the implied warranty of\n\/\/ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\/\/ GNU General Public License for more details.\n\/\/\n\/\/ You should have received a copy of the GNU General Public License\n\/\/ along with Moodle. If not, see .\n\n\/**\n * Autocomplete wrapper for select2 library.\n *\n * @module core\/form-autocomplete\n * @copyright 2015 Damyon Wiese \n * @license http:\/\/www.gnu.org\/copyleft\/gpl.html GNU GPL v3 or later\n * @since 3.0\n *\/\ndefine([\n 'jquery',\n 'core\/log',\n 'core\/str',\n 'core\/templates',\n 'core\/notification',\n 'core\/loadingicon',\n 'core\/aria',\n 'core_form\/changechecker',\n 'core\/popper2',\n], function(\n $,\n log,\n str,\n templates,\n notification,\n LoadingIcon,\n Aria,\n FormChangeChecker,\n Popper\n) {\n \/\/ Private functions and variables.\n \/** @var {Object} KEYS - List of keycode constants. *\/\n var KEYS = {\n DOWN: 40,\n ENTER: 13,\n SPACE: 32,\n ESCAPE: 27,\n COMMA: 44,\n UP: 38,\n LEFT: 37,\n RIGHT: 39\n };\n\n var uniqueId = Date.now();\n\n \/**\n * Make an item in the selection list \"active\".\n *\n * @method activateSelection\n * @private\n * @param {Number} index The index in the current (visible) list of selection.\n * @param {Object} state State variables for this autocomplete element.\n * @return {Promise}\n *\/\n var activateSelection = function(index, state) {\n \/\/ Find the elements in the DOM.\n var selectionElement = $(document.getElementById(state.selectionId));\n\n index = wrapListIndex(index, selectionElement.children('[aria-selected=true]').length);\n \/\/ Find the specified element.\n var element = $(selectionElement.children('[aria-selected=true]').get(index));\n \/\/ Create an id we can assign to this element.\n var itemId = state.selectionId + '-' + index;\n\n \/\/ Deselect all the selections.\n selectionElement.children().attr('data-active-selection', null).attr('id', '');\n\n \/\/ Select only this suggestion and assign it the id.\n element.attr('data-active-selection', true).attr('id', itemId);\n\n \/\/ Tell the input field it has a new active descendant so the item is announced.\n selectionElement.attr('aria-activedescendant', itemId);\n selectionElement.attr('data-active-value', element.attr('data-value'));\n\n return $.Deferred().resolve();\n };\n\n \/**\n * Get the actively selected element from the state object.\n *\n * @param {Object} state\n * @returns {jQuery}\n *\/\n var getActiveElementFromState = function(state) {\n var selectionRegion = $(document.getElementById(state.selectionId));\n var activeId = selectionRegion.attr('aria-activedescendant');\n\n if (activeId) {\n var activeElement = $(document.getElementById(activeId));\n if (activeElement.length) {\n \/\/ The active descendent still exists.\n return activeElement;\n }\n }\n\n \/\/ Ensure we are creating a properly formed selector based on the active value.\n var activeValue = selectionRegion.attr('data-active-value')?.replace(\/\"\/g, '\\\\\"');\n return selectionRegion.find('[data-value=\"' + activeValue + '\"]');\n };\n\n \/**\n * Update the active selection from the given state object.\n *\n * @param {Object} state\n *\/\n var updateActiveSelectionFromState = function(state) {\n var activeElement = getActiveElementFromState(state);\n var activeValue = activeElement.attr('data-value');\n\n var selectionRegion = $(document.getElementById(state.selectionId));\n if (activeValue) {\n \/\/ Find the index of the currently selected index.\n var activeIndex = selectionRegion.find('[aria-selected=true]').index(activeElement);\n\n if (activeIndex !== -1) {\n activateSelection(activeIndex, state);\n return;\n }\n }\n\n \/\/ Either the active index was not set, or it could not be found.\n \/\/ Select the first value instead.\n activateSelection(0, state);\n };\n\n \/**\n * Update the element that shows the currently selected items.\n *\n * @method updateSelectionList\n * @private\n * @param {Object} options Original options for this autocomplete element.\n * @param {Object} state State variables for this autocomplete element.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n *\/\n var updateSelectionList = function(options, state, originalSelect) {\n var pendingKey = 'form-autocomplete-updateSelectionList-' + state.inputId;\n M.util.js_pending(pendingKey);\n\n \/\/ Build up a valid context to re-render the template.\n var items = rebuildOptions(originalSelect.children('option:selected'), false);\n var newSelection = $(document.getElementById(state.selectionId));\n\n if (!hasItemListChanged(state, items)) {\n M.util.js_complete(pendingKey);\n return Promise.resolve();\n }\n\n state.items = items;\n\n var context = $.extend(options, state);\n \/\/ Render the template.\n return templates.render(options.templates.items, context)\n .then(function(html, js) {\n \/\/ Add it to the page.\n templates.replaceNodeContents(newSelection, html, js);\n\n updateActiveSelectionFromState(state);\n\n return;\n })\n .then(function() {\n return M.util.js_complete(pendingKey);\n })\n .catch(notification.exception);\n };\n\n \/**\n * Check whether the list of items stored in the state has changed.\n *\n * @param {Object} state\n * @param {Array} items\n * @returns {Boolean}\n *\/\n var hasItemListChanged = function(state, items) {\n if (state.items.length !== items.length) {\n return true;\n }\n\n \/\/ Check for any items in the state items which are not present in the new items list.\n return state.items.filter(item => items.indexOf(item) === -1).length > 0;\n };\n\n \/**\n * Notify of a change in the selection.\n *\n * @param {jQuery} originalSelect The jQuery object matching the hidden select list.\n *\/\n var notifyChange = function(originalSelect) {\n FormChangeChecker.markFormChangedFromNode(originalSelect[0]);\n\n \/\/ Note, jQuery .change() was not working here. Better to\n \/\/ use plain JavaScript anyway.\n originalSelect[0].dispatchEvent(new Event('change', {bubbles: true}));\n };\n\n \/**\n * Remove the given item from the list of selected things.\n *\n * @method deselectItem\n * @private\n * @param {Object} options Original options for this autocomplete element.\n * @param {Object} state State variables for this autocomplete element.\n * @param {Element} item The item to be deselected.\n * @param {Element} originalSelect The original select list.\n * @return {Promise}\n *\/\n const deselectItem = async(options, state, item, originalSelect) => {\n var selectedItemValue = $(item).attr('data-value');\n\n \/\/ Preprend an empty option to the select list to avoid having a default selected option.\n if (originalSelect.find('option').first().attr('value') !== undefined) {\n originalSelect.prepend($(''));\n }\n\n \/\/ Look for a match, and toggle the selected property if there is a match.\n originalSelect.children('option').each(function(index, ele) {\n if ($(ele).attr('value') == selectedItemValue) {\n $(ele).prop('selected', false);\n \/\/ We remove newly created custom tags from the suggestions list when they are deselected.\n if ($(ele).attr('data-iscustom')) {\n $(ele).remove();\n }\n }\n });\n\n const selectedItemText = item[0].childNodes[2].textContent?.trim();\n await announceChanges(state.selectionId, selectedItemText, 'removed');\n\n \/\/ Rerender the selection list.\n await updateSelectionList(options, state, originalSelect);\n\n \/\/ Notify that the selection changed.\n notifyChange(originalSelect);\n };\n\n \/**\n * Make an item in the suggestions \"active\" (about to be selected).\n *\n * @method activateItem\n * @private\n * @param {Number} index The index in the current (visible) list of suggestions.\n * @param {Object} state State variables for this instance of autocomplete.\n * @return {Promise}\n *\/\n var activateItem = function(index, state) {\n \/\/ Find the elements in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n \/\/ Count the visible items.\n var length = suggestionsElement.children(':not([aria-hidden])').length;\n \/\/ Limit the index to the upper\/lower bounds of the list (wrap in both directions).\n index = index % length;\n while (index < 0) {\n index += length;\n }\n \/\/ Find the specified element.\n var element = $(suggestionsElement.children(':not([aria-hidden])').get(index));\n \/\/ Find the index of this item in the full list of suggestions (including hidden).\n var globalIndex = $(suggestionsElement.children('[role=option]')).index(element);\n \/\/ Create an id we can assign to this element.\n var itemId = state.suggestionsId + '-' + globalIndex;\n\n \/\/ Deselect all the suggestions.\n suggestionsElement.children().attr('aria-selected', false).attr('id', '');\n \/\/ Select only this suggestion and assign it the id.\n element.attr('aria-selected', true).attr('id', itemId);\n \/\/ Tell the input field it has a new active descendant so the item is announced.\n inputElement.attr('aria-activedescendant', itemId);\n\n \/\/ Scroll it into view.\n var scrollPos = element.offset().top\n - suggestionsElement.offset().top\n + suggestionsElement.scrollTop()\n - (suggestionsElement.height() \/ 2);\n return suggestionsElement.animate({\n scrollTop: scrollPos\n }, 100).promise();\n };\n\n \/**\n * Return the index of the currently selected item in the suggestions list.\n *\n * @param {jQuery} suggestionsElement\n * @return {Integer}\n *\/\n var getCurrentItem = function(suggestionsElement) {\n \/\/ Find the active one.\n var element = suggestionsElement.children('[aria-selected=true]');\n \/\/ Find its index.\n return suggestionsElement.children(':not([aria-hidden])').index(element);\n };\n\n \/**\n * Limit the index to the upper\/lower bounds of the list (wrap in both directions).\n *\n * @param {Integer} index The target index.\n * @param {Integer} length The length of the list of visible items.\n * @return {Integer} The resulting index with necessary wrapping applied.\n *\/\n var wrapListIndex = function(index, length) {\n index = index % length;\n while (index < 0) {\n index += length;\n }\n return index;\n };\n\n \/**\n * Return the index of the next item in the list without aria-disabled=true.\n *\n * @param {Integer} current The index of the current item.\n * @param {Array} suggestions The list of suggestions.\n * @return {Integer}\n *\/\n var getNextEnabledItem = function(current, suggestions) {\n var nextIndex = wrapListIndex(current + 1, suggestions.length);\n if (suggestions[nextIndex].getAttribute('aria-disabled')) {\n return getNextEnabledItem(nextIndex, suggestions);\n }\n return nextIndex;\n };\n\n \/**\n * Return the index of the previous item in the list without aria-disabled=true.\n *\n * @param {Integer} current The index of the current item.\n * @param {Array} suggestions The list of suggestions.\n * @return {Integer}\n *\/\n var getPreviousEnabledItem = function(current, suggestions) {\n var previousIndex = wrapListIndex(current - 1, suggestions.length);\n if (suggestions[previousIndex].getAttribute('aria-disabled')) {\n return getPreviousEnabledItem(previousIndex, suggestions);\n }\n return previousIndex;\n };\n\n \/**\n * Build a list of renderable options based on a set of option elements from the original select list.\n *\n * @param {jQuery} originalOptions\n * @param {Boolean} includeEmpty\n * @return {Array}\n *\/\n var rebuildOptions = function(originalOptions, includeEmpty) {\n var options = [];\n originalOptions.each(function(index, ele) {\n var label;\n if ($(ele).data('html')) {\n label = $(ele).data('html');\n } else {\n label = $(ele).html();\n }\n if (includeEmpty || label !== '') {\n options.push({\n label: label,\n value: $(ele).attr('value'),\n disabled: ele.disabled,\n classes: ele.classList,\n });\n }\n });\n return options;\n };\n\n \/**\n * Find the index of the current active suggestion, and activate the next one.\n *\n * @method activateNextItem\n * @private\n * @param {Object} state State variable for this auto complete element.\n * @return {Promise}\n *\/\n var activateNextItem = function(state) {\n \/\/ Find the list of suggestions.\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n var suggestions = suggestionsElement.children(':not([aria-hidden])');\n var current = getCurrentItem(suggestionsElement);\n \/\/ Activate the next one.\n return activateItem(getNextEnabledItem(current, suggestions), state);\n };\n\n \/**\n * Find the index of the current active selection, and activate the previous one.\n *\n * @method activatePreviousSelection\n * @private\n * @param {Object} state State variables for this instance of autocomplete.\n * @return {Promise}\n *\/\n var activatePreviousSelection = function(state) {\n \/\/ Find the list of selections.\n var selectionsElement = $(document.getElementById(state.selectionId));\n \/\/ Find the active one.\n var element = selectionsElement.children('[data-active-selection]');\n if (!element) {\n return activateSelection(0, state);\n }\n \/\/ Find it's index.\n var current = selectionsElement.children('[aria-selected=true]').index(element);\n \/\/ Activate the next one.\n return activateSelection(current - 1, state);\n };\n\n \/**\n * Find the index of the current active selection, and activate the next one.\n *\n * @method activateNextSelection\n * @private\n * @param {Object} state State variables for this instance of autocomplete.\n * @return {Promise}\n *\/\n var activateNextSelection = function(state) {\n \/\/ Find the list of selections.\n var selectionsElement = $(document.getElementById(state.selectionId));\n\n \/\/ Find the active one.\n var element = selectionsElement.children('[data-active-selection]');\n var current = 0;\n\n if (element) {\n \/\/ The element was found. Determine the index and move to the next one.\n current = selectionsElement.children('[aria-selected=true]').index(element);\n current = current + 1;\n } else {\n \/\/ No selected item found. Move to the first.\n current = 0;\n }\n\n return activateSelection(current, state);\n };\n\n \/**\n * Find the index of the current active suggestion, and activate the previous one.\n *\n * @method activatePreviousItem\n * @private\n * @param {Object} state State variables for this autocomplete element.\n * @return {Promise}\n *\/\n var activatePreviousItem = function(state) {\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n var suggestions = suggestionsElement.children(':not([aria-hidden])');\n var current = getCurrentItem(suggestionsElement);\n \/\/ Activate the previous one.\n return activateItem(getPreviousEnabledItem(current, suggestions), state);\n };\n\n \/**\n * Close the list of suggestions.\n *\n * @method closeSuggestions\n * @private\n * @param {Object} state State variables for this autocomplete element.\n * @return {Promise}\n *\/\n var closeSuggestions = function(state) {\n \/\/ Find the elements in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n if (inputElement.attr('aria-expanded') === \"true\") {\n \/\/ Announce the list of suggestions was closed.\n inputElement.attr('aria-expanded', false);\n }\n \/\/ Read the current list of selections.\n inputElement.attr('aria-activedescendant', state.selectionId);\n\n \/\/ Hide the suggestions list (from screen readers too).\n Aria.hide(suggestionsElement.get());\n suggestionsElement.hide();\n\n return $.Deferred().resolve();\n };\n\n \/**\n * Rebuild the list of suggestions based on the current values in the select list, and the query.\n *\n * @method updateSuggestions\n * @private\n * @param {Object} options The original options for this autocomplete.\n * @param {Object} state The state variables for this autocomplete.\n * @param {String} query The current text for the search string.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n *\/\n var updateSuggestions = function(options, state, query, originalSelect) {\n var pendingKey = 'form-autocomplete-updateSuggestions-' + state.inputId;\n M.util.js_pending(pendingKey);\n\n \/\/ Find the elements in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n \/\/ Used to track if we found any visible suggestions.\n var matchingElements = false;\n \/\/ Options is used by the context when rendering the suggestions from a template.\n var suggestions = rebuildOptions(originalSelect.children('option:not(:selected)'), true);\n\n \/\/ Re-render the list of suggestions.\n var searchquery = state.caseSensitive ? query : query.toLocaleLowerCase();\n var context = $.extend({options: suggestions}, options, state);\n var returnVal = templates.render(\n 'core\/form_autocomplete_suggestions',\n context\n )\n .then(function(html, js) {\n \/\/ We have the new template, insert it in the page.\n templates.replaceNode(suggestionsElement, html, js);\n\n \/\/ Get the element again.\n suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n \/\/ Show it if it is hidden.\n Aria.unhide(suggestionsElement.get());\n Popper.createPopper(inputElement[0], suggestionsElement[0], {\n placement: 'bottom-start',\n modifiers: [{name: 'flip', enabled: false}],\n });\n\n \/\/ For each option in the list, hide it if it doesn't match the query.\n suggestionsElement.children().each(function(index, node) {\n node = $(node);\n if ((options.caseSensitive && node.text().indexOf(searchquery) > -1) ||\n (!options.caseSensitive && node.text().toLocaleLowerCase().indexOf(searchquery) > -1)) {\n Aria.unhide(node.get());\n node.show();\n matchingElements = true;\n } else {\n node.hide();\n Aria.hide(node.get());\n }\n });\n \/\/ If we found any matches, show the list.\n inputElement.attr('aria-expanded', true);\n if (originalSelect.attr('data-notice')) {\n \/\/ Display a notice rather than actual suggestions.\n suggestionsElement.html(originalSelect.attr('data-notice'));\n } else if (matchingElements) {\n \/\/ We only activate the first item in the list if tags is false,\n \/\/ because otherwise \"Enter\" would select the first item, instead of\n \/\/ creating a new tag.\n if (!options.tags) {\n activateItem(0, state);\n }\n } else {\n \/\/ Nothing matches. Tell them that.\n str.get_string('nosuggestions', 'form').done(function(nosuggestionsstr) {\n suggestionsElement.html(nosuggestionsstr);\n });\n }\n\n return suggestionsElement;\n })\n .then(function() {\n return M.util.js_complete(pendingKey);\n })\n .catch(notification.exception);\n\n return returnVal;\n };\n\n \/**\n * Create a new item for the list (a tag).\n *\n * @method createItem\n * @private\n * @param {Object} options The original options for the autocomplete.\n * @param {Object} state State variables for the autocomplete.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @return {Promise}\n *\/\n const createItem = async(options, state, originalSelect) => {\n \/\/ Find the element in the DOM.\n var inputElement = $(document.getElementById(state.inputId));\n \/\/ Get the current text in the input field.\n var query = inputElement.val();\n var tags = query.split(',');\n var found = false;\n\n $.each(tags, function(tagindex, tag) {\n \/\/ If we can only select one at a time, deselect any current value.\n tag = tag.trim();\n if (tag !== '') {\n if (!options.multiple) {\n originalSelect.children('option').prop('selected', false);\n }\n \/\/ Look for an existing option in the select list that matches this new tag.\n originalSelect.children('option').each(function(index, ele) {\n if ($(ele).attr('value') == tag) {\n found = true;\n $(ele).prop('selected', true);\n }\n });\n \/\/ Only create the item if it's new.\n if (!found) {\n var option = $(' ');\n option.append(document.createTextNode(tag));\n option.attr('value', tag);\n originalSelect.append(option);\n option.prop('selected', true);\n \/\/ We mark newly created custom options as we handle them differently if they are \"deselected\".\n option.attr('data-iscustom', true);\n }\n }\n });\n\n \/\/ Announce the changes to the assistive technology.\n await announceChanges(state.selectionId, query.trim(), 'added');\n\n await updateSelectionList(options, state, originalSelect);\n \/\/ Notify that the selection changed.\n notifyChange(originalSelect);\n\n \/\/ Clear the input field.\n inputElement.val('');\n \/\/ Close the suggestions list.\n await closeSuggestions(state);\n };\n\n \/**\n * Select the currently active item from the suggestions list.\n *\n * @method selectCurrentItem\n * @private\n * @param {Object} options The original options for the autocomplete.\n * @param {Object} state State variables for the autocomplete.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @param {string|null} selectedItem The item to be selected.\n * @return {Promise}\n *\/\n const selectCurrentItem = async(options, state, originalSelect, selectedItem) => {\n \/\/ Find the elements in the page.\n var inputElement = $(document.getElementById(state.inputId));\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n \/\/ Here loop through suggestions and set val to join of all selected items.\n\n var selectedItemValue = suggestionsElement.children('[aria-selected=true]').attr('data-value');\n \/\/ The select will either be a single or multi select, so the following will either\n \/\/ select one or more items correctly.\n \/\/ Take care to use 'prop' and not 'attr' for selected properties.\n \/\/ If only one can be selected at a time, start by deselecting everything.\n if (!options.multiple) {\n originalSelect.children('option').prop('selected', false);\n }\n \/\/ Look for a match, and toggle the selected property if there is a match.\n originalSelect.children('option').each(function (index, ele) {\n if ($(ele).attr('value') == selectedItemValue) {\n $(ele).prop('selected', true);\n }\n });\n\n await announceChanges(state.selectionId, selectedItem, 'added');\n\n await updateSelectionList(options, state, originalSelect);\n\n \/\/ Notify that the selection changed.\n notifyChange(originalSelect);\n\n if (options.closeSuggestionsOnSelect) {\n \/\/ Clear the input element.\n inputElement.val('');\n \/\/ Close the list of suggestions.\n await closeSuggestions(state);\n } else {\n \/\/ Focus on the input element so the suggestions does not auto-close.\n inputElement.focus();\n \/\/ Remove the last selected item from the suggestions list.\n await updateSuggestions(options, state, inputElement.val(), originalSelect);\n }\n };\n\n \/**\n * Fetch a new list of options via ajax.\n *\n * @method updateAjax\n * @private\n * @param {Event} e The event that triggered this update.\n * @param {Object} options The original options for the autocomplete.\n * @param {Object} state The state variables for the autocomplete.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n * @param {Object} ajaxHandler This is a module that does the ajax fetch and translates the results.\n * @return {Promise}\n *\/\n var updateAjax = function(e, options, state, originalSelect, ajaxHandler) {\n var pendingPromise = addPendingJSPromise('updateAjax');\n \/\/ We need to show the indicator outside of the hidden select list.\n \/\/ So we get the parent id of the hidden select list.\n var parentElement = $(document.getElementById(state.selectId)).parent();\n LoadingIcon.addIconToContainerRemoveOnCompletion(parentElement, pendingPromise);\n\n \/\/ Get the query to pass to the ajax function.\n var query = $(e.currentTarget).val();\n \/\/ Call the transport function to do the ajax (name taken from Select2).\n ajaxHandler.transport(options.selector, query, function(results) {\n \/\/ We got a result - pass it through the translator before using it.\n var processedResults = ajaxHandler.processResults(options.selector, results);\n var existingValues = [];\n\n \/\/ Now destroy all options that are not current\n originalSelect.children('option').each(function(optionIndex, option) {\n option = $(option);\n if (!option.prop('selected')) {\n option.remove();\n } else {\n existingValues.push(String(option.attr('value')));\n }\n });\n\n if (!options.multiple && originalSelect.children('option').length === 0) {\n \/\/ If this is a single select - and there are no current options\n \/\/ the first option added will be selected by the browser. This causes a bug!\n \/\/ We need to insert an empty option so that none of the real options are selected.\n var option = $(' ');\n originalSelect.append(option);\n }\n if ($.isArray(processedResults)) {\n \/\/ Add all the new ones returned from ajax.\n $.each(processedResults, function(resultIndex, result) {\n if (existingValues.indexOf(String(result.value)) === -1) {\n var option = $(' ');\n option.append(result.label);\n option.attr('value', result.value);\n originalSelect.append(option);\n }\n });\n originalSelect.attr('data-notice', '');\n } else {\n \/\/ The AJAX handler returned a string instead of the array.\n originalSelect.attr('data-notice', processedResults);\n }\n \/\/ Update the list of suggestions now from the new values in the select list.\n pendingPromise.resolve(updateSuggestions(options, state, '', originalSelect));\n }, function(error) {\n pendingPromise.reject(error);\n });\n\n return pendingPromise;\n };\n\n \/**\n * Add all the event listeners required for keyboard nav, blur clicks etc.\n *\n * @method addNavigation\n * @private\n * @param {Object} options The options used to create this autocomplete element.\n * @param {Object} state State variables for this autocomplete element.\n * @param {JQuery} originalSelect The JQuery object matching the hidden select list.\n *\/\n var addNavigation = function(options, state, originalSelect) {\n \/\/ Start with the input element.\n var inputElement = $(document.getElementById(state.inputId));\n \/\/ Add keyboard nav with keydown.\n inputElement.on('keydown', function(e) {\n var pendingJsPromise = addPendingJSPromise('addNavigation-' + state.inputId + '-' + e.keyCode);\n\n switch (e.keyCode) {\n case KEYS.DOWN:\n \/\/ If the suggestion list is open, move to the next item.\n if (!options.showSuggestions) {\n \/\/ Do not consume this event.\n pendingJsPromise.resolve();\n return true;\n } else if (inputElement.attr('aria-expanded') === \"true\") {\n pendingJsPromise.resolve(activateNextItem(state));\n } else {\n \/\/ Handle ajax population of suggestions.\n if (!inputElement.val() && options.ajax) {\n require([options.ajax], function(ajaxHandler) {\n pendingJsPromise.resolve(updateAjax(e, options, state, originalSelect, ajaxHandler));\n });\n } else {\n \/\/ Open the suggestions list.\n pendingJsPromise.resolve(updateSuggestions(options, state, inputElement.val(), originalSelect));\n }\n }\n \/\/ We handled this event, so prevent it.\n e.preventDefault();\n return false;\n case KEYS.UP:\n \/\/ Choose the previous active item.\n pendingJsPromise.resolve(activatePreviousItem(state));\n\n \/\/ We handled this event, so prevent it.\n e.preventDefault();\n return false;\n case KEYS.ENTER:\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n if ((inputElement.attr('aria-expanded') === \"true\") &&\n (suggestionsElement.children('[aria-selected=true]').length > 0)) {\n const selectedItemText = suggestionsElement.children('[aria-selected=true]')[0].textContent.trim();\n \/\/ If the suggestion list has an active item, select it.\n pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect, selectedItemText));\n } else if (options.tags) {\n \/\/ If tags are enabled, create a tag.\n pendingJsPromise.resolve(createItem(options, state, originalSelect));\n } else {\n pendingJsPromise.resolve();\n }\n\n \/\/ We handled this event, so prevent it.\n e.preventDefault();\n return false;\n case KEYS.ESCAPE:\n if (inputElement.attr('aria-expanded') === \"true\") {\n \/\/ If the suggestion list is open, close it.\n pendingJsPromise.resolve(closeSuggestions(state));\n } else {\n pendingJsPromise.resolve();\n }\n \/\/ We handled this event, so prevent it.\n e.preventDefault();\n return false;\n }\n pendingJsPromise.resolve();\n return true;\n });\n \/\/ Support multi lingual COMMA keycode (44).\n inputElement.on('keypress', function(e) {\n\n if (e.keyCode === KEYS.COMMA) {\n if (options.tags) {\n \/\/ If we are allowing tags, comma should create a tag (or enter).\n addPendingJSPromise('keypress-' + e.keyCode)\n .resolve(createItem(options, state, originalSelect));\n }\n \/\/ We handled this event, so prevent it.\n e.preventDefault();\n return false;\n }\n return true;\n });\n \/\/ Support submitting the form without leaving the autocomplete element,\n \/\/ or submitting too quick before the blur handler action is completed.\n inputElement.closest('form').on('submit', function() {\n if (options.tags) {\n \/\/ If tags are enabled, create a tag.\n addPendingJSPromise('form-autocomplete-submit')\n .resolve(createItem(options, state, originalSelect));\n }\n\n return true;\n });\n inputElement.on('blur', function() {\n var pendingPromise = addPendingJSPromise('form-autocomplete-blur');\n window.setTimeout(function() {\n \/\/ Get the current element with focus.\n var focusElement = $(document.activeElement);\n var timeoutPromise = $.Deferred();\n\n \/\/ Only close the menu if the input hasn't regained focus and if the element still exists,\n \/\/ and regain focus if the scrollbar is clicked.\n \/\/ Due to the half a second delay, it is possible that the input element no longer exist\n \/\/ by the time this code is being executed.\n if (focusElement.is(document.getElementById(state.suggestionsId))) {\n inputElement.focus(); \/\/ Probably the scrollbar is clicked. Regain focus.\n } else if (!focusElement.is(inputElement) && $(document.getElementById(state.inputId)).length) {\n if (options.tags) {\n timeoutPromise.then(function() {\n return createItem(options, state, originalSelect);\n })\n .catch();\n }\n timeoutPromise.then(function() {\n return closeSuggestions(state);\n })\n .catch();\n }\n\n timeoutPromise.then(function() {\n return pendingPromise.resolve();\n })\n .catch();\n timeoutPromise.resolve();\n }, 500);\n });\n if (options.showSuggestions) {\n var arrowElement = $(document.getElementById(state.downArrowId));\n arrowElement.on('click', function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-show-suggestions');\n\n \/\/ Prevent the close timer, or we will open, then close the suggestions.\n inputElement.focus();\n\n \/\/ Handle ajax population of suggestions.\n if (!inputElement.val() && options.ajax) {\n require([options.ajax], function(ajaxHandler) {\n pendingPromise.resolve(updateAjax(e, options, state, originalSelect, ajaxHandler));\n });\n } else {\n \/\/ Else - open the suggestions list.\n pendingPromise.resolve(updateSuggestions(options, state, inputElement.val(), originalSelect));\n }\n });\n }\n\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n \/\/ Remove any click handler first.\n suggestionsElement.parent().prop(\"onclick\", null).off(\"click\");\n suggestionsElement.parent().on('click', `#${state.suggestionsId} [role=option]`, function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-parent');\n \/\/ Handle clicks on suggestions.\n var element = $(e.currentTarget).closest('[role=option]');\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n \/\/ Find the index of the clicked on suggestion.\n var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n \/\/ Activate it.\n activateItem(current, state)\n .then(function() {\n \/\/ And select it.\n const selectedItemText = element[0].textContent.trim();\n return selectCurrentItem(options, state, originalSelect, selectedItemText);\n })\n .then(function() {\n return pendingPromise.resolve();\n })\n .catch(notification.exception);\n });\n var selectionElement = $(document.getElementById(state.selectionId));\n\n \/\/ Handle clicks on the selected items (will unselect an item).\n selectionElement.on('click', '[role=option]', function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-clicks');\n\n \/\/ Remove it from the selection.\n pendingPromise.resolve(deselectItem(options, state, $(e.currentTarget), originalSelect));\n });\n\n \/\/ When listbox is focused, focus on the first option if there is no focused option.\n selectionElement.on('focus', function() {\n updateActiveSelectionFromState(state);\n });\n\n \/\/ Keyboard navigation for the selection list.\n selectionElement.on('keydown', function(e) {\n var pendingPromise = addPendingJSPromise('form-autocomplete-keydown-' + e.keyCode);\n switch (e.keyCode) {\n case KEYS.RIGHT:\n case KEYS.DOWN:\n \/\/ We handled this event, so prevent it.\n e.preventDefault();\n\n \/\/ Choose the next selection item.\n pendingPromise.resolve(activateNextSelection(state));\n return;\n case KEYS.LEFT:\n case KEYS.UP:\n \/\/ We handled this event, so prevent it.\n e.preventDefault();\n\n \/\/ Choose the previous selection item.\n pendingPromise.resolve(activatePreviousSelection(state));\n return;\n case KEYS.SPACE:\n case KEYS.ENTER:\n \/\/ Get the item that is currently selected.\n var selectedItem = $(document.getElementById(state.selectionId)).children('[data-active-selection]');\n if (selectedItem) {\n e.preventDefault();\n\n \/\/ Unselect this item.\n pendingPromise.resolve(deselectItem(options, state, selectedItem, originalSelect));\n }\n return;\n }\n\n \/\/ Not handled. Resolve the promise.\n pendingPromise.resolve();\n });\n \/\/ Whenever the input field changes, update the suggestion list.\n if (options.showSuggestions) {\n \/\/ Store the value of the field as its last value, when the field gains focus.\n inputElement.on('focus', function(e) {\n var query = $(e.currentTarget).val();\n $(e.currentTarget).data('last-value', query);\n });\n\n \/\/ If this field uses ajax, set it up.\n if (options.ajax) {\n require([options.ajax], function(ajaxHandler) {\n \/\/ Creating throttled handlers free of race conditions, and accurate.\n \/\/ This code keeps track of a throttleTimeout, which is periodically polled.\n \/\/ Once the throttled function is executed, the fact that it is running is noted.\n \/\/ If a subsequent request comes in whilst it is running, this request is re-applied.\n var throttleTimeout = null;\n var inProgress = false;\n var pendingKey = 'autocomplete-throttledhandler';\n var handler = function(e) {\n \/\/ Empty the current timeout.\n throttleTimeout = null;\n\n \/\/ Mark this request as in-progress.\n inProgress = true;\n\n \/\/ Process the request.\n updateAjax(e, options, state, originalSelect, ajaxHandler)\n .then(function() {\n \/\/ Check if the throttleTimeout is still empty.\n \/\/ There's a potential condition whereby the JS request takes long enough to complete that\n \/\/ another task has been queued.\n \/\/ In this case another task will be kicked off and we must wait for that before marking htis as\n \/\/ complete.\n if (null === throttleTimeout) {\n \/\/ Mark this task as complete.\n M.util.js_complete(pendingKey);\n }\n inProgress = false;\n\n return arguments[0];\n })\n .catch(notification.exception);\n };\n\n \/\/ For input events, we do not want to trigger many, many updates.\n var throttledHandler = function(e) {\n window.clearTimeout(throttleTimeout);\n if (inProgress) {\n \/\/ A request is currently ongoing.\n \/\/ Delay this request another 100ms.\n throttleTimeout = window.setTimeout(throttledHandler.bind(this, e), 100);\n return;\n }\n\n if (throttleTimeout === null) {\n \/\/ There is currently no existing timeout handler, and it has not been recently cleared, so\n \/\/ this is the start of a throttling check.\n M.util.js_pending(pendingKey);\n }\n\n \/\/ There is currently no existing timeout handler, and it has not been recently cleared, so this\n \/\/ is the start of a throttling check.\n \/\/ Queue a call to the handler.\n throttleTimeout = window.setTimeout(handler.bind(this, e), 300);\n };\n\n \/\/ Trigger an ajax update after the text field value changes.\n inputElement.on('input', function(e) {\n var query = $(e.currentTarget).val();\n var last = $(e.currentTarget).data('last-value');\n \/\/ IE11 fires many more input events than required - even when the value has not changed.\n if (last !== query) {\n throttledHandler(e);\n }\n $(e.currentTarget).data('last-value', query);\n });\n });\n } else {\n inputElement.on('input', function(e) {\n var query = $(e.currentTarget).val();\n var last = $(e.currentTarget).data('last-value');\n \/\/ IE11 fires many more input events than required - even when the value has not changed.\n \/\/ We need to only do this for real value changed events or the suggestions will be\n \/\/ unclickable on IE11 (because they will be rebuilt before the click event fires).\n \/\/ Note - because of this we cannot close the list when the query is empty or it will break\n \/\/ on IE11.\n if (last !== query) {\n updateSuggestions(options, state, query, originalSelect);\n }\n $(e.currentTarget).data('last-value', query);\n });\n }\n }\n };\n\n \/**\n * Create and return an unresolved Promise for some pending JS.\n *\n * @param {String} key The unique identifier for this promise\n * @return {Promise}\n *\/\n var addPendingJSPromise = function(key) {\n var pendingKey = 'form-autocomplete:' + key;\n\n M.util.js_pending(pendingKey);\n\n var pendingPromise = $.Deferred();\n\n pendingPromise\n .then(function() {\n M.util.js_complete(pendingKey);\n\n return arguments[0];\n })\n .catch(notification.exception);\n\n return pendingPromise;\n };\n\n \/**\n * Turn a boring select box into an auto-complete beast.\n *\n * @method enhanceField\n * @param {string} selector The selector that identifies the select box.\n * @param {boolean} tags Whether to allow support for tags (can define new entries).\n * @param {string} ajax Name of an AMD module to handle ajax requests. If specified, the AMD\n * module must expose 2 functions \"transport\" and \"processResults\".\n * These are modeled on Select2 see: https:\/\/select2.github.io\/options.html#ajax\n * @param {String|Promise} placeholder - The text to display before a selection is made.\n * @param {Boolean} caseSensitive - If search has to be made case sensitive.\n * @param {Boolean} showSuggestions - If suggestions should be shown\n * @param {String|Promise} noSelectionString - Text to display when there is no selection\n * @param {Boolean} closeSuggestionsOnSelect - Whether to close the suggestions immediately after making a selection.\n * @param {Object} templateOverrides A set of templates to use instead of the standard templates\n * @return {Promise}\n *\/\n var enhanceField = async function(selector, tags, ajax, placeholder, caseSensitive, showSuggestions, noSelectionString,\n closeSuggestionsOnSelect, templateOverrides) {\n \/\/ Set some default values.\n var options = {\n selector: selector,\n tags: false,\n ajax: false,\n placeholder: await placeholder,\n caseSensitive: false,\n showSuggestions: true,\n noSelectionString: await noSelectionString,\n templates: $.extend({\n input: 'core\/form_autocomplete_input',\n items: 'core\/form_autocomplete_selection_items',\n layout: 'core\/form_autocomplete_layout',\n selection: 'core\/form_autocomplete_selection',\n suggestions: 'core\/form_autocomplete_suggestions',\n }, templateOverrides),\n };\n var pendingKey = 'autocomplete-setup-' + selector;\n M.util.js_pending(pendingKey);\n if (typeof tags !== \"undefined\") {\n options.tags = tags;\n }\n if (typeof ajax !== \"undefined\") {\n options.ajax = ajax;\n }\n if (typeof caseSensitive !== \"undefined\") {\n options.caseSensitive = caseSensitive;\n }\n if (typeof showSuggestions !== \"undefined\") {\n options.showSuggestions = showSuggestions;\n }\n if (typeof noSelectionString === \"undefined\") {\n str.get_string('noselection', 'form').done(function(result) {\n options.noSelectionString = result;\n }).fail(notification.exception);\n }\n\n \/\/ Look for the select element.\n var originalSelect = $(selector);\n if (!originalSelect) {\n log.debug('Selector not found: ' + selector);\n M.util.js_complete(pendingKey);\n return false;\n }\n\n \/\/ Ensure we enhance the element only once.\n if (originalSelect.data('enhanced') === 'enhanced') {\n M.util.js_complete(pendingKey);\n return false;\n }\n originalSelect.data('enhanced', 'enhanced');\n\n \/\/ Hide the original select.\n Aria.hide(originalSelect.get());\n originalSelect.css('visibility', 'hidden');\n\n \/\/ Find or generate some ids.\n var state = {\n selectId: originalSelect.attr('id'),\n inputId: 'form_autocomplete_input-' + uniqueId,\n suggestionsId: 'form_autocomplete_suggestions-' + uniqueId,\n selectionId: 'form_autocomplete_selection-' + uniqueId,\n downArrowId: 'form_autocomplete_downarrow-' + uniqueId,\n items: [],\n required: originalSelect[0]?.ariaRequired === 'true',\n };\n\n \/\/ Increment the unique counter so we don't get duplicates ever.\n uniqueId++;\n\n options.multiple = originalSelect.attr('multiple');\n if (!options.multiple) {\n \/\/ If this is a single select then there is no way to de-select the current value -\n \/\/ unless we add a bogus blank option to be selected when nothing else is.\n \/\/ This matches similar code in updateAjax above.\n originalSelect.prepend('');\n }\n\n if (typeof closeSuggestionsOnSelect !== \"undefined\") {\n options.closeSuggestionsOnSelect = closeSuggestionsOnSelect;\n } else {\n \/\/ If not specified, this will close suggestions by default for single-select elements only.\n options.closeSuggestionsOnSelect = !options.multiple;\n }\n\n var originalLabel = $('[for=' + state.selectId + ']');\n \/\/ Create the new markup and insert it after the select.\n var suggestions = rebuildOptions(originalSelect.children('option'), true);\n\n \/\/ Render all the parts of our UI.\n var context = $.extend({}, options, state);\n context.options = suggestions;\n context.items = [];\n\n \/\/ Collect rendered inline JS to be executed once the HTML is shown.\n var collectedjs = '';\n\n var renderLayout = templates.render(options.templates.layout, {})\n .then(function(html) {\n return $(html);\n });\n\n var renderInput = templates.render(options.templates.input, context).then(function(html, js) {\n collectedjs += js;\n return $(html);\n });\n\n var renderDatalist = templates.render(options.templates.suggestions, context).then(function(html, js) {\n collectedjs += js;\n return $(html);\n });\n\n var renderSelection = templates.render(options.templates.selection, context).then(function(html, js) {\n collectedjs += js;\n return $(html);\n });\n\n return Promise.all([renderLayout, renderInput, renderDatalist, renderSelection])\n .then(function([layout, input, suggestions, selection]) {\n originalSelect.hide();\n var container = originalSelect.parent();\n\n \/\/ Ensure that the data-fieldtype is set for behat.\n input.find('input').attr('data-fieldtype', 'autocomplete');\n\n container.append(layout);\n container.find('[data-region=\"form_autocomplete-input\"]').replaceWith(input);\n container.find('[data-region=\"form_autocomplete-suggestions\"]').replaceWith(suggestions);\n container.find('[data-region=\"form_autocomplete-selection\"]').replaceWith(selection);\n\n templates.runTemplateJS(collectedjs);\n\n \/\/ Update the form label to point to the text input.\n originalLabel.attr('for', state.inputId);\n \/\/ Add the event handlers.\n addNavigation(options, state, originalSelect);\n\n var suggestionsElement = $(document.getElementById(state.suggestionsId));\n \/\/ Hide the suggestions by default.\n suggestionsElement.hide();\n Aria.hide(suggestionsElement.get());\n\n return;\n })\n .then(function() {\n \/\/ Show the current values in the selection list.\n return updateSelectionList(options, state, originalSelect);\n })\n .then(function() {\n return M.util.js_complete(pendingKey);\n })\n .catch(function(error) {\n M.util.js_complete(pendingKey);\n notification.exception(error);\n });\n };\n\n \/**\n * Announces changes to a tag in the autocomplete form.\n *\n * Updates the text content of a status element to inform users about the addition or removal\n * of a tag. This is useful for accessibility purposes, ensuring screen readers can notify users\n * of changes in the autocomplete component.\n *\n * @param {string} selectionId - The ID of the selection element used to locate the announcer element.\n * @param {string|null|undefined} tagname - The name of the tag that was added or removed.\n * @param {string} action - The action performed on the tag (e.g., \"added\" or \"removed\").\n *\/\n const announceChanges = async(selectionId, tagname, action) => {\n if (!tagname) {\n return;\n }\n\n const status = document.getElementById(`${selectionId}-announcer`);\n if (!status) {\n return;\n }\n\n status.textContent = await str.get_string(action, 'core', tagname);\n\n \/\/ Remove the status message after 4 seconds to prevent screen readers from announcing it.\n setTimeout(() => {\n status.textContent = '';\n }, 4000);\n\n };\n\n return {\n \/\/ Public variables and functions.\n enhanceField: enhanceField,\n\n \/**\n * We need to use jQuery here as some calling code uses .done() and .fail() rather than native .then() and .catch()\n *\n * @method enhance\n * @return {Promise} A jQuery promise\n *\/\n enhance: function() {\n return $.when(enhanceField(...arguments));\n }\n };\n});\n"],"names":["define","$","log","str","templates","notification","LoadingIcon","Aria","FormChangeChecker","Popper","KEYS","uniqueId","Date","now","activateSelection","index","state","selectionElement","document","getElementById","selectionId","wrapListIndex","children","length","element","get","itemId","attr","Deferred","resolve","updateActiveSelectionFromState","activeElement","selectionRegion","activeId","activeValue","_selectionRegion$attr","replace","find","getActiveElementFromState","activeIndex","updateSelectionList","options","originalSelect","pendingKey","inputId","M","util","js_pending","items","rebuildOptions","newSelection","hasItemListChanged","js_complete","Promise","context","extend","render","then","html","js","replaceNodeContents","catch","exception","filter","item","indexOf","notifyChange","markFormChangedFromNode","dispatchEvent","Event","bubbles","deselectItem","async","selectedItemValue","undefined","first","prepend","each","ele","prop","remove","selectedItemText","childNodes","textContent","_item$0$childNodes$2$","trim","announceChanges","activateItem","inputElement","suggestionsElement","suggestionsId","globalIndex","scrollPos","offset","top","scrollTop","height","animate","promise","getCurrentItem","getNextEnabledItem","current","suggestions","nextIndex","getAttribute","getPreviousEnabledItem","previousIndex","originalOptions","includeEmpty","label","data","push","value","disabled","classes","classList","closeSuggestions","hide","updateSuggestions","query","matchingElements","searchquery","caseSensitive","toLocaleLowerCase","replaceNode","unhide","createPopper","placement","modifiers","name","enabled","node","text","show","tags","get_string","done","nosuggestionsstr","createItem","val","split","found","tagindex","tag","multiple","option","append","createTextNode","selectCurrentItem","selectedItem","closeSuggestionsOnSelect","focus","updateAjax","e","ajaxHandler","pendingPromise","addPendingJSPromise","parentElement","selectId","parent","addIconToContainerRemoveOnCompletion","currentTarget","transport","selector","results","processedResults","processResults","existingValues","optionIndex","String","isArray","resultIndex","result","error","reject","addNavigation","on","pendingJsPromise","keyCode","showSuggestions","activateNextItem","ajax","require","preventDefault","activatePreviousItem","closest","window","setTimeout","focusElement","timeoutPromise","is","downArrowId","off","selectionsElement","activateNextSelection","activatePreviousSelection","throttleTimeout","inProgress","handler","arguments","throttledHandler","clearTimeout","bind","this","key","enhanceField","placeholder","noSelectionString","templateOverrides","input","layout","selection","fail","debug","css","required","ariaRequired","originalLabel","collectedjs","renderLayout","renderInput","renderDatalist","renderSelection","all","container","replaceWith","runTemplateJS","tagname","action","status","enhance","when"],"mappings":"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\/Be,eAAef,KAAK,eAEpB8D,mBAAmB\/B,KAAKhB,eAAef,KAAK,gBACrC6F,iBAIF\/E,QAAQ6F,MACT\/C,aAAa,EAAGvE,OAIpBb,IAAIoI,WAAW,gBAAiB,QAAQC,MAAK,SAASC,kBAClDhD,mBAAmB\/B,KAAK+E,qBAIzBhD,sBAEVhC,MAAK,kBACKZ,EAAEC,KAAKM,YAAYT,eAE7BkB,MAAMxD,aAAayD,kBAelB4E,WAAalE,MAAM\/B,QAASzB,MAAO0B,sBAEjC8C,aAAevF,EAAEiB,SAASC,eAAeH,MAAM4B,UAE\/C2E,MAAQ\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\/D,aAAamD,OAASlG,QAAQ4I,KAC\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"}