From 3caa6bfbe11662867084e163ade5283106e55a74 Mon Sep 17 00:00:00 2001
From: Andrew Nicols <andrew@nicols.co.uk>
Date: Mon, 2 Nov 2020 08:12:22 +0800
Subject: [PATCH 1/5] MDL-70075 core: Listen for the `focus` and `blur` events
 again

The `blur` event does not bubble, but the `focusout` events are not
available in all supported versions of Firefox.

Rather than switching event, this patch using event capture to
effectively achieve the same result and bubble the event up through the
DOM to the delegated listener.

There should be no functional change with this patch, except to support
Firefox fully.
---
 lib/amd/build/custom_interaction_events.min.js     |  2 +-
 lib/amd/build/custom_interaction_events.min.js.map |  2 +-
 lib/amd/src/custom_interaction_events.js           | 10 ++++++----
 3 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/lib/amd/build/custom_interaction_events.min.js b/lib/amd/build/custom_interaction_events.min.js
index fdf405e8e8c..2e6312a9df8 100644
--- a/lib/amd/build/custom_interaction_events.min.js
+++ b/lib/amd/build/custom_interaction_events.min.js
@@ -1,2 +1,2 @@
-define ("core/custom_interaction_events",["jquery","core/key_codes"],function(a,b){var c={activate:"cie:activate",keyboardActivate:"cie:keyboardactivate",escape:"cie:escape",down:"cie:down",up:"cie:up",home:"cie:home",end:"cie:end",next:"cie:next",previous:"cie:previous",asterix:"cie:asterix",scrollLock:"cie:scrollLock",scrollTop:"cie:scrollTop",scrollBottom:"cie:scrollBottom",ctrlPageUp:"cie:ctrlPageUp",ctrlPageDown:"cie:ctrlPageDown",enter:"cie:enter",accessibleChange:"cie:accessibleChange"},d={},e=function(a,b){b=b||[];if(b.length&&-1!==b.indexOf(a)){return!0}return!1},f=function(a){return a.shiftKey||a.metaKey||a.altKey||a.ctrlKey},g=function(b,c){var e="";if(!c.hasOwnProperty("originalEvent")){e=""+b+c.type+c.timeStamp;if(!d.hasOwnProperty(e)){d[e]=!0;a(c.target).trigger(b,[{originalEvent:c}])}return}e="triggeredCustom_"+b;if(!c.originalEvent.hasOwnProperty(e)){c.originalEvent[e]=!0;a(c.target).trigger(b,[{originalEvent:c}])}},h=function(a,b,c){a.off("keydown."+b).on("keydown."+b,function(a){if(!f(a)){if(a.keyCode==c){g(b,a)}}})},i=function(a){a.off("click.cie.activate").on("click.cie.activate",function(a){g(c.activate,a)});a.off("keydown.cie.activate").on("keydown.cie.activate",function(a){if(!f(a)){if(a.keyCode==b.enter||a.keyCode==b.space){g(c.activate,a)}}})},j=function(a){a.off("keydown.cie.keyboardactivate").on("keydown.cie.keyboardactivate",function(a){if(!f(a)){if(a.keyCode==b.enter||a.keyCode==b.space){g(c.keyboardActivate,a)}}})},k=function(a){h(a,c.escape,b.escape)},l=function(a){h(a,c.down,b.arrowDown)},m=function(a){h(a,c.up,b.arrowUp)},n=function(a){h(a,c.home,b.home)},o=function(a){h(a,c.end,b.end)},p=function(d){var e="rtl"==a("html").attr("dir")?b.arrowLeft:b.arrowRight;h(d,c.next,e)},q=function(d){var e="rtl"==a("html").attr("dir")?b.arrowRight:b.arrowLeft;h(d,c.previous,e)},r=function(a){h(a,c.asterix,b.asterix)},s=function(a){a.off("scroll.cie.scrollTop").on("scroll.cie.scrollTop",function(b){var d=a.scrollTop();if(0===d){g(c.scrollTop,b)}})},t=function(a){a.off("scroll.cie.scrollBottom").on("scroll.cie.scrollBottom",function(b){var d=a.scrollTop(),e=a.innerHeight(),f=a[0].scrollHeight;if(d+e>=f){g(c.scrollBottom,b)}})},u=function(a){a.off("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock").on("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock",function(b){var d=a.scrollTop(),e=a[0].scrollHeight,f=a.height(),h="DOMMouseScroll"==b.type?-40*b.originalEvent.detail:b.originalEvent.wheelDelta,i=0<h;if(!i&&-h>e-f-d){a.scrollTop(e);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}else if(i&&h>d){a.scrollTop(0);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}return!0})},v=function(a){a.off("keydown.cie.ctrlpageup").on("keydown.cie.ctrlpageup",function(a){if(a.ctrlKey){if(a.keyCode==b.pageUp){g(c.ctrlPageUp,a)}}})},w=function(a){a.off("keydown.cie.ctrlpagedown").on("keydown.cie.ctrlpagedown",function(a){if(a.ctrlKey){if(a.keyCode==b.pageDown){g(c.ctrlPageDown,a)}}})},x=function(a){h(a,c.enter,b.enter)},y=function(d){var e=-1!==navigator.userAgent.indexOf("Macintosh"),f="ontouchstart"in window||"msMaxTouchPoints"in navigator&&0<navigator.msMaxTouchPoints;if(e||f){d.on("change",function(a){g(c.accessibleChange,a)})}else{d.on("focusin",function(b){a(b.target).data("initValue",b.target.value)});d.on("focusout",function(b){var d=a(b.target).data("initValue");a(b.target).removeData("initValue");if(b.target.value!==d){g(c.accessibleChange,b)}});d.on("keydown",function(d){if(d.which===b.enter&&d.target.value!==a(d.target).data("initValue")){g(c.accessibleChange,d)}else if(d.which===b.escape){d.target.value=a(d.target).data("initValue")}});d.on("click",function(b){var d=a(b.target).data("initValue");if("undefined"!=typeof d&&d!=b.target.value){g(c.accessibleChange,b)}})}},z=function(){var a={};a[c.activate]=i;a[c.keyboardActivate]=j;a[c.escape]=k;a[c.down]=l;a[c.up]=m;a[c.home]=n;a[c.end]=o;a[c.next]=p;a[c.previous]=q;a[c.asterix]=r;a[c.scrollLock]=u;a[c.scrollTop]=s;a[c.scrollBottom]=t;a[c.ctrlPageUp]=v;a[c.ctrlPageDown]=w;a[c.enter]=x;a[c.accessibleChange]=y;return a};return{define:function define(b,c){b=a(b);c=c||[];if(!b.length||!c.length){return}a.each(z(),function(a,d){if(e(a,c)){d(b)}})},events:c}});
+define ("core/custom_interaction_events",["jquery","core/key_codes"],function(a,b){var c={activate:"cie:activate",keyboardActivate:"cie:keyboardactivate",escape:"cie:escape",down:"cie:down",up:"cie:up",home:"cie:home",end:"cie:end",next:"cie:next",previous:"cie:previous",asterix:"cie:asterix",scrollLock:"cie:scrollLock",scrollTop:"cie:scrollTop",scrollBottom:"cie:scrollBottom",ctrlPageUp:"cie:ctrlPageUp",ctrlPageDown:"cie:ctrlPageDown",enter:"cie:enter",accessibleChange:"cie:accessibleChange"},d={},e=function(a,b){b=b||[];if(b.length&&-1!==b.indexOf(a)){return!0}return!1},f=function(a){return a.shiftKey||a.metaKey||a.altKey||a.ctrlKey},g=function(b,c){var e="";if(!c.hasOwnProperty("originalEvent")){e=""+b+c.type+c.timeStamp;if(!d.hasOwnProperty(e)){d[e]=!0;a(c.target).trigger(b,[{originalEvent:c}])}return}e="triggeredCustom_"+b;if(!c.originalEvent.hasOwnProperty(e)){c.originalEvent[e]=!0;a(c.target).trigger(b,[{originalEvent:c}])}},h=function(a,b,c){a.off("keydown."+b).on("keydown."+b,function(a){if(!f(a)){if(a.keyCode==c){g(b,a)}}})},i=function(a){a.off("click.cie.activate").on("click.cie.activate",function(a){g(c.activate,a)});a.off("keydown.cie.activate").on("keydown.cie.activate",function(a){if(!f(a)){if(a.keyCode==b.enter||a.keyCode==b.space){g(c.activate,a)}}})},j=function(a){a.off("keydown.cie.keyboardactivate").on("keydown.cie.keyboardactivate",function(a){if(!f(a)){if(a.keyCode==b.enter||a.keyCode==b.space){g(c.keyboardActivate,a)}}})},k=function(a){h(a,c.escape,b.escape)},l=function(a){h(a,c.down,b.arrowDown)},m=function(a){h(a,c.up,b.arrowUp)},n=function(a){h(a,c.home,b.home)},o=function(a){h(a,c.end,b.end)},p=function(d){var e="rtl"==a("html").attr("dir")?b.arrowLeft:b.arrowRight;h(d,c.next,e)},q=function(d){var e="rtl"==a("html").attr("dir")?b.arrowRight:b.arrowLeft;h(d,c.previous,e)},r=function(a){h(a,c.asterix,b.asterix)},s=function(a){a.off("scroll.cie.scrollTop").on("scroll.cie.scrollTop",function(b){var d=a.scrollTop();if(0===d){g(c.scrollTop,b)}})},t=function(a){a.off("scroll.cie.scrollBottom").on("scroll.cie.scrollBottom",function(b){var d=a.scrollTop(),e=a.innerHeight(),f=a[0].scrollHeight;if(d+e>=f){g(c.scrollBottom,b)}})},u=function(a){a.off("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock").on("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock",function(b){var d=a.scrollTop(),e=a[0].scrollHeight,f=a.height(),h="DOMMouseScroll"==b.type?-40*b.originalEvent.detail:b.originalEvent.wheelDelta,i=0<h;if(!i&&-h>e-f-d){a.scrollTop(e);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}else if(i&&h>d){a.scrollTop(0);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}return!0})},v=function(a){a.off("keydown.cie.ctrlpageup").on("keydown.cie.ctrlpageup",function(a){if(a.ctrlKey){if(a.keyCode==b.pageUp){g(c.ctrlPageUp,a)}}})},w=function(a){a.off("keydown.cie.ctrlpagedown").on("keydown.cie.ctrlpagedown",function(a){if(a.ctrlKey){if(a.keyCode==b.pageDown){g(c.ctrlPageDown,a)}}})},x=function(a){h(a,c.enter,b.enter)},y=function(d){var e=-1!==navigator.userAgent.indexOf("Macintosh"),f="ontouchstart"in window||"msMaxTouchPoints"in navigator&&0<navigator.msMaxTouchPoints;if(e||f){d.on("change",function(a){g(c.accessibleChange,a)})}else{var h=d.get()[0];h.addEventListener("focus",function(b){a(b.target).data("initValue",b.target.value)},!0);h.addEventListener("blur",function(b){var d=a(b.target).data("initValue");a(b.target).removeData("initValue");if(b.target.value!==d){g(c.accessibleChange,b)}},!0);d.on("keydown",function(d){if(d.which===b.enter&&d.target.value!==a(d.target).data("initValue")){g(c.accessibleChange,d)}else if(d.which===b.escape){d.target.value=a(d.target).data("initValue")}});d.on("click",function(b){var d=a(b.target).data("initValue");if("undefined"!=typeof d&&d!=b.target.value){g(c.accessibleChange,b)}})}},z=function(){var a={};a[c.activate]=i;a[c.keyboardActivate]=j;a[c.escape]=k;a[c.down]=l;a[c.up]=m;a[c.home]=n;a[c.end]=o;a[c.next]=p;a[c.previous]=q;a[c.asterix]=r;a[c.scrollLock]=u;a[c.scrollTop]=s;a[c.scrollBottom]=t;a[c.ctrlPageUp]=v;a[c.ctrlPageDown]=w;a[c.enter]=x;a[c.accessibleChange]=y;return a};return{define:function define(b,c){b=a(b);c=c||[];if(!b.length||!c.length){return}a.each(z(),function(a,d){if(e(a,c)){d(b)}})},events:c}});
 //# sourceMappingURL=custom_interaction_events.min.js.map
diff --git a/lib/amd/build/custom_interaction_events.min.js.map b/lib/amd/build/custom_interaction_events.min.js.map
index 2ca3bca412f..a603b954104 100644
--- a/lib/amd/build/custom_interaction_events.min.js.map
+++ b/lib/amd/build/custom_interaction_events.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/custom_interaction_events.js"],"names":["define","$","keyCodes","events","activate","keyboardActivate","escape","down","up","home","end","next","previous","asterix","scrollLock","scrollTop","scrollBottom","ctrlPageUp","ctrlPageDown","enter","accessibleChange","triggeredEvents","shouldAddEvent","eventType","include","length","indexOf","isModifierPressed","e","shiftKey","metaKey","altKey","ctrlKey","triggerEvent","eventName","eventTypeKey","hasOwnProperty","type","timeStamp","target","trigger","originalEvent","addKeyboardEvent","element","event","keyCode","off","on","addActivateListener","space","addKeyboardActivateListener","addEscapeListener","addDownListener","arrowDown","addUpListener","arrowUp","addHomeListener","addEndListener","addNextListener","attr","arrowLeft","arrowRight","addPreviousListener","addAsterixListener","addScrollTopListener","addScrollBottomListener","innerHeight","scrollHeight","addScrollLockListener","height","delta","detail","wheelDelta","stopPropagation","preventDefault","returnValue","addCtrlPageUpListener","pageUp","addCtrlPageDownListener","pageDown","addEnterListener","addAccessibleChangeListener","onMac","navigator","userAgent","touchEnabled","window","msMaxTouchPoints","data","value","initValue","removeData","which","getHandlers","handlers","each","handler"],"mappings":"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","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 <http://www.gnu.org/licenses/>.\n\n/**\n * This module provides a wrapper to encapsulate a lot of the common combinations of\n * user interaction we use in Moodle.\n *\n * @module     core/custom_interaction_events\n * @class      custom_interaction_events\n * @package    core\n * @copyright  2016 Ryan Wyllie <ryan@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.2\n */\ndefine(['jquery', 'core/key_codes'], function($, keyCodes) {\n    // The list of events provided by this module. Namespaced to avoid clashes.\n    var events = {\n        activate: 'cie:activate',\n        keyboardActivate: 'cie:keyboardactivate',\n        escape: 'cie:escape',\n        down: 'cie:down',\n        up: 'cie:up',\n        home: 'cie:home',\n        end: 'cie:end',\n        next: 'cie:next',\n        previous: 'cie:previous',\n        asterix: 'cie:asterix',\n        scrollLock: 'cie:scrollLock',\n        scrollTop: 'cie:scrollTop',\n        scrollBottom: 'cie:scrollBottom',\n        ctrlPageUp: 'cie:ctrlPageUp',\n        ctrlPageDown: 'cie:ctrlPageDown',\n        enter: 'cie:enter',\n        accessibleChange: 'cie:accessibleChange',\n    };\n    // Static cache of jQuery events that have been handled. This should\n    // only be populated by JavaScript generated events (which will keep it\n    // fairly small).\n    var triggeredEvents = {};\n\n    /**\n     * Check if the caller has asked for the given event type to be\n     * registered.\n     *\n     * @method shouldAddEvent\n     * @private\n     * @param {string} eventType name of the event (see events above)\n     * @param {array} include the list of events to be added\n     * @return {bool} true if the event should be added, false otherwise.\n     */\n    var shouldAddEvent = function(eventType, include) {\n        include = include || [];\n\n        if (include.length && include.indexOf(eventType) !== -1) {\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * Check if any of the modifier keys have been pressed on the event.\n     *\n     * @method isModifierPressed\n     * @private\n     * @param {event} e jQuery event\n     * @return {bool} true if shift, meta (command on Mac), alt or ctrl are pressed\n     */\n    var isModifierPressed = function(e) {\n        return (e.shiftKey || e.metaKey || e.altKey || e.ctrlKey);\n    };\n\n    /**\n     * Trigger the custom event for the given jQuery event.\n     *\n     * This function will only fire the custom event if one hasn't already been\n     * fired for the jQuery event.\n     *\n     * This is to prevent multiple custom event handlers triggering multiple\n     * custom events for a single jQuery event as it bubbles up the stack.\n     *\n     * @param  {string} eventName The name of the custom event\n     * @param  {event} e          The jQuery event\n     * @return {void}\n     */\n    var triggerEvent = function(eventName, e) {\n        var eventTypeKey = \"\";\n\n        if (!e.hasOwnProperty('originalEvent')) {\n            // This is a jQuery event generated from JavaScript not a browser event so\n            // we need to build the cache key for the event.\n            eventTypeKey = \"\" + eventName + e.type + e.timeStamp;\n\n            if (!triggeredEvents.hasOwnProperty(eventTypeKey)) {\n                // If we haven't seen this jQuery event before then fire a custom\n                // event for it and remember the event for later.\n                triggeredEvents[eventTypeKey] = true;\n                $(e.target).trigger(eventName, [{originalEvent: e}]);\n            }\n            return;\n        }\n\n        eventTypeKey = \"triggeredCustom_\" + eventName;\n        if (!e.originalEvent.hasOwnProperty(eventTypeKey)) {\n            // If this is a jQuery event generated by the browser then set a\n            // property on the original event to track that we've seen it before.\n            // The property is set on the original event because it's the only part\n            // of the jQuery event that is maintained through multiple event handlers.\n            e.originalEvent[eventTypeKey] = true;\n            $(e.target).trigger(eventName, [{originalEvent: e}]);\n            return;\n        }\n    };\n\n    /**\n     * Register a keyboard event that ignores modifier keys.\n     *\n     * @method addKeyboardEvent\n     * @private\n     * @param {object} element A jQuery object of the element to bind events to\n     * @param {string} event The custom interaction event name\n     * @param {int} keyCode The key code.\n     */\n    var addKeyboardEvent = function(element, event, keyCode) {\n        element.off('keydown.' + event).on('keydown.' + event, function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCode) {\n                    triggerEvent(event, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the activate event on the given element if it is clicked or the enter\n     * or space key are pressed without a modifier key.\n     *\n     * @method addActivateListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addActivateListener = function(element) {\n        element.off('click.cie.activate').on('click.cie.activate', function(e) {\n            triggerEvent(events.activate, e);\n        });\n        element.off('keydown.cie.activate').on('keydown.cie.activate', function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n                    triggerEvent(events.activate, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the keyboard activate event on the given element if the enter\n     * or space key are pressed without a modifier key.\n     *\n     * @method addKeyboardActivateListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addKeyboardActivateListener = function(element) {\n        element.off('keydown.cie.keyboardactivate').on('keydown.cie.keyboardactivate', function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n                    triggerEvent(events.keyboardActivate, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the escape event on the given element if the escape key is pressed\n     * without a modifier key.\n     *\n     * @method addEscapeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEscapeListener = function(element) {\n        addKeyboardEvent(element, events.escape, keyCodes.escape);\n    };\n\n    /**\n     * Trigger the down event on the given element if the down arrow key is pressed\n     * without a modifier key.\n     *\n     * @method addDownListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addDownListener = function(element) {\n        addKeyboardEvent(element, events.down, keyCodes.arrowDown);\n    };\n\n    /**\n     * Trigger the up event on the given element if the up arrow key is pressed\n     * without a modifier key.\n     *\n     * @method addUpListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addUpListener = function(element) {\n        addKeyboardEvent(element, events.up, keyCodes.arrowUp);\n    };\n\n    /**\n     * Trigger the home event on the given element if the home key is pressed\n     * without a modifier key.\n     *\n     * @method addHomeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addHomeListener = function(element) {\n        addKeyboardEvent(element, events.home, keyCodes.home);\n    };\n\n    /**\n     * Trigger the end event on the given element if the end key is pressed\n     * without a modifier key.\n     *\n     * @method addEndListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEndListener = function(element) {\n        addKeyboardEvent(element, events.end, keyCodes.end);\n    };\n\n    /**\n     * Trigger the next event on the given element if the right arrow key is pressed\n     * without a modifier key in LTR mode or left arrow key in RTL mode.\n     *\n     * @method addNextListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addNextListener = function(element) {\n        // Left and right are flipped in RTL mode.\n        var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowLeft : keyCodes.arrowRight;\n\n        addKeyboardEvent(element, events.next, keyCode);\n    };\n\n    /**\n     * Trigger the previous event on the given element if the left arrow key is pressed\n     * without a modifier key in LTR mode or right arrow key in RTL mode.\n     *\n     * @method addPreviousListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addPreviousListener = function(element) {\n        // Left and right are flipped in RTL mode.\n        var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowRight : keyCodes.arrowLeft;\n\n        addKeyboardEvent(element, events.previous, keyCode);\n    };\n\n    /**\n     * Trigger the asterix event on the given element if the asterix key is pressed\n     * without a modifier key.\n     *\n     * @method addAsterixListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addAsterixListener = function(element) {\n        addKeyboardEvent(element, events.asterix, keyCodes.asterix);\n    };\n\n\n    /**\n     * Trigger the scrollTop event on the given element if the user scrolls to\n     * the top of the given element.\n     *\n     * @method addScrollTopListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addScrollTopListener = function(element) {\n        element.off('scroll.cie.scrollTop').on('scroll.cie.scrollTop', function(e) {\n            var scrollTop = element.scrollTop();\n            if (scrollTop === 0) {\n                triggerEvent(events.scrollTop, e);\n            }\n        });\n    };\n\n    /**\n     * Trigger the scrollBottom event on the given element if the user scrolls to\n     * the bottom of the given element.\n     *\n     * @method addScrollBottomListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addScrollBottomListener = function(element) {\n        element.off('scroll.cie.scrollBottom').on('scroll.cie.scrollBottom', function(e) {\n            var scrollTop = element.scrollTop();\n            var innerHeight = element.innerHeight();\n            var scrollHeight = element[0].scrollHeight;\n\n            if (scrollTop + innerHeight >= scrollHeight) {\n                triggerEvent(events.scrollBottom, e);\n            }\n        });\n    };\n\n    /**\n     * Trigger the scrollLock event on the given element if the user scrolls to\n     * the bottom or top of the given element.\n     *\n     * @method addScrollLockListener\n     * @private\n     * @param {jQuery} element jQuery object to add event listeners to\n     */\n    var addScrollLockListener = function(element) {\n        // Lock mousewheel scrolling within the element to stop the annoying window scroll.\n        element.off('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock')\n            .on('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock', function(e) {\n                var scrollTop = element.scrollTop();\n                var scrollHeight = element[0].scrollHeight;\n                var height = element.height();\n                var delta = (e.type == 'DOMMouseScroll' ?\n                    e.originalEvent.detail * -40 :\n                    e.originalEvent.wheelDelta);\n                var up = delta > 0;\n\n                if (!up && -delta > scrollHeight - height - scrollTop) {\n                    // Scrolling down past the bottom.\n                    element.scrollTop(scrollHeight);\n                    e.stopPropagation();\n                    e.preventDefault();\n                    e.returnValue = false;\n                    // Fire the scroll lock event.\n                    triggerEvent(events.scrollLock, e);\n\n                    return false;\n                } else if (up && delta > scrollTop) {\n                    // Scrolling up past the top.\n                    element.scrollTop(0);\n                    e.stopPropagation();\n                    e.preventDefault();\n                    e.returnValue = false;\n                    // Fire the scroll lock event.\n                    triggerEvent(events.scrollLock, e);\n\n                    return false;\n                }\n\n                return true;\n            });\n    };\n\n    /**\n     * Trigger the ctrlPageUp event on the given element if the user presses the\n     * control and page up key.\n     *\n     * @method addCtrlPageUpListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addCtrlPageUpListener = function(element) {\n        element.off('keydown.cie.ctrlpageup').on('keydown.cie.ctrlpageup', function(e) {\n            if (e.ctrlKey) {\n                if (e.keyCode == keyCodes.pageUp) {\n                    triggerEvent(events.ctrlPageUp, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the ctrlPageDown event on the given element if the user presses the\n     * control and page down key.\n     *\n     * @method addCtrlPageDownListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addCtrlPageDownListener = function(element) {\n        element.off('keydown.cie.ctrlpagedown').on('keydown.cie.ctrlpagedown', function(e) {\n            if (e.ctrlKey) {\n                if (e.keyCode == keyCodes.pageDown) {\n                    triggerEvent(events.ctrlPageDown, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the enter event on the given element if the enter key is pressed\n     * without a modifier key.\n     *\n     * @method addEnterListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEnterListener = function(element) {\n        addKeyboardEvent(element, events.enter, keyCodes.enter);\n    };\n\n    /**\n     * Trigger the AccessibleChange event on the given element if the value of the element is changed.\n     *\n     * @method addAccessibleChangeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addAccessibleChangeListener = function(element) {\n        var onMac = navigator.userAgent.indexOf('Macintosh') !== -1;\n        var touchEnabled = ('ontouchstart' in window) || (('msMaxTouchPoints' in navigator) && (navigator.msMaxTouchPoints > 0));\n        if (onMac || touchEnabled) {\n            element.on('change', function(e) {\n                triggerEvent(events.accessibleChange, e);\n            });\n        } else {\n            element.on('focusin', function(e) {\n                $(e.target).data('initValue', e.target.value);\n            });\n            element.on('focusout', function(e) {\n                var initValue = $(e.target).data('initValue');\n                $(e.target).removeData('initValue');\n                if (e.target.value !== initValue) {\n                    triggerEvent(events.accessibleChange, e);\n                }\n            });\n            element.on('keydown', function(e) {\n                if ((e.which === keyCodes.enter) && e.target.value !== $(e.target).data('initValue')) {\n                    triggerEvent(events.accessibleChange, e);\n                } else if (e.which === keyCodes.escape) {\n                    e.target.value = $(e.target).data('initValue');\n                }\n            });\n            element.on('click', function(e) {\n                var initValue = $(e.target).data('initValue');\n                // Some browsers trigger onclick before onblur, therefore it is possible that initValue is undefined.\n                if (typeof initValue !== 'undefined' && initValue != e.target.value) {\n                    triggerEvent(events.accessibleChange, e);\n                }\n            });\n        }\n    };\n\n    /**\n     * Get the list of events and their handlers.\n     *\n     * @method getHandlers\n     * @private\n     * @return {object} object key of event names and value of handler functions\n     */\n    var getHandlers = function() {\n        var handlers = {};\n\n        handlers[events.activate] = addActivateListener;\n        handlers[events.keyboardActivate] = addKeyboardActivateListener;\n        handlers[events.escape] = addEscapeListener;\n        handlers[events.down] = addDownListener;\n        handlers[events.up] = addUpListener;\n        handlers[events.home] = addHomeListener;\n        handlers[events.end] = addEndListener;\n        handlers[events.next] = addNextListener;\n        handlers[events.previous] = addPreviousListener;\n        handlers[events.asterix] = addAsterixListener;\n        handlers[events.scrollLock] = addScrollLockListener;\n        handlers[events.scrollTop] = addScrollTopListener;\n        handlers[events.scrollBottom] = addScrollBottomListener;\n        handlers[events.ctrlPageUp] = addCtrlPageUpListener;\n        handlers[events.ctrlPageDown] = addCtrlPageDownListener;\n        handlers[events.enter] = addEnterListener;\n        handlers[events.accessibleChange] = addAccessibleChangeListener;\n\n        return handlers;\n    };\n\n    /**\n     * Add all of the listeners on the given element for the requested events.\n     *\n     * @method define\n     * @public\n     * @param {object} element the DOM element to register event listeners on\n     * @param {array} include the array of events to be triggered\n     */\n    var define = function(element, include) {\n        element = $(element);\n        include = include || [];\n\n        if (!element.length || !include.length) {\n            return;\n        }\n\n        $.each(getHandlers(), function(eventType, handler) {\n            if (shouldAddEvent(eventType, include)) {\n                handler(element);\n            }\n        });\n    };\n\n    return /** @module core/custom_interaction_events */ {\n        define: define,\n        events: events,\n    };\n});\n"],"file":"custom_interaction_events.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/custom_interaction_events.js"],"names":["define","$","keyCodes","events","activate","keyboardActivate","escape","down","up","home","end","next","previous","asterix","scrollLock","scrollTop","scrollBottom","ctrlPageUp","ctrlPageDown","enter","accessibleChange","triggeredEvents","shouldAddEvent","eventType","include","length","indexOf","isModifierPressed","e","shiftKey","metaKey","altKey","ctrlKey","triggerEvent","eventName","eventTypeKey","hasOwnProperty","type","timeStamp","target","trigger","originalEvent","addKeyboardEvent","element","event","keyCode","off","on","addActivateListener","space","addKeyboardActivateListener","addEscapeListener","addDownListener","arrowDown","addUpListener","arrowUp","addHomeListener","addEndListener","addNextListener","attr","arrowLeft","arrowRight","addPreviousListener","addAsterixListener","addScrollTopListener","addScrollBottomListener","innerHeight","scrollHeight","addScrollLockListener","height","delta","detail","wheelDelta","stopPropagation","preventDefault","returnValue","addCtrlPageUpListener","pageUp","addCtrlPageDownListener","pageDown","addEnterListener","addAccessibleChangeListener","onMac","navigator","userAgent","touchEnabled","window","msMaxTouchPoints","nativeElement","get","addEventListener","data","value","initValue","removeData","which","getHandlers","handlers","each","handler"],"mappings":"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","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 <http://www.gnu.org/licenses/>.\n\n/**\n * This module provides a wrapper to encapsulate a lot of the common combinations of\n * user interaction we use in Moodle.\n *\n * @module     core/custom_interaction_events\n * @class      custom_interaction_events\n * @package    core\n * @copyright  2016 Ryan Wyllie <ryan@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.2\n */\ndefine(['jquery', 'core/key_codes'], function($, keyCodes) {\n    // The list of events provided by this module. Namespaced to avoid clashes.\n    var events = {\n        activate: 'cie:activate',\n        keyboardActivate: 'cie:keyboardactivate',\n        escape: 'cie:escape',\n        down: 'cie:down',\n        up: 'cie:up',\n        home: 'cie:home',\n        end: 'cie:end',\n        next: 'cie:next',\n        previous: 'cie:previous',\n        asterix: 'cie:asterix',\n        scrollLock: 'cie:scrollLock',\n        scrollTop: 'cie:scrollTop',\n        scrollBottom: 'cie:scrollBottom',\n        ctrlPageUp: 'cie:ctrlPageUp',\n        ctrlPageDown: 'cie:ctrlPageDown',\n        enter: 'cie:enter',\n        accessibleChange: 'cie:accessibleChange',\n    };\n    // Static cache of jQuery events that have been handled. This should\n    // only be populated by JavaScript generated events (which will keep it\n    // fairly small).\n    var triggeredEvents = {};\n\n    /**\n     * Check if the caller has asked for the given event type to be\n     * registered.\n     *\n     * @method shouldAddEvent\n     * @private\n     * @param {string} eventType name of the event (see events above)\n     * @param {array} include the list of events to be added\n     * @return {bool} true if the event should be added, false otherwise.\n     */\n    var shouldAddEvent = function(eventType, include) {\n        include = include || [];\n\n        if (include.length && include.indexOf(eventType) !== -1) {\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * Check if any of the modifier keys have been pressed on the event.\n     *\n     * @method isModifierPressed\n     * @private\n     * @param {event} e jQuery event\n     * @return {bool} true if shift, meta (command on Mac), alt or ctrl are pressed\n     */\n    var isModifierPressed = function(e) {\n        return (e.shiftKey || e.metaKey || e.altKey || e.ctrlKey);\n    };\n\n    /**\n     * Trigger the custom event for the given jQuery event.\n     *\n     * This function will only fire the custom event if one hasn't already been\n     * fired for the jQuery event.\n     *\n     * This is to prevent multiple custom event handlers triggering multiple\n     * custom events for a single jQuery event as it bubbles up the stack.\n     *\n     * @param  {string} eventName The name of the custom event\n     * @param  {event} e          The jQuery event\n     * @return {void}\n     */\n    var triggerEvent = function(eventName, e) {\n        var eventTypeKey = \"\";\n\n        if (!e.hasOwnProperty('originalEvent')) {\n            // This is a jQuery event generated from JavaScript not a browser event so\n            // we need to build the cache key for the event.\n            eventTypeKey = \"\" + eventName + e.type + e.timeStamp;\n\n            if (!triggeredEvents.hasOwnProperty(eventTypeKey)) {\n                // If we haven't seen this jQuery event before then fire a custom\n                // event for it and remember the event for later.\n                triggeredEvents[eventTypeKey] = true;\n                $(e.target).trigger(eventName, [{originalEvent: e}]);\n            }\n            return;\n        }\n\n        eventTypeKey = \"triggeredCustom_\" + eventName;\n        if (!e.originalEvent.hasOwnProperty(eventTypeKey)) {\n            // If this is a jQuery event generated by the browser then set a\n            // property on the original event to track that we've seen it before.\n            // The property is set on the original event because it's the only part\n            // of the jQuery event that is maintained through multiple event handlers.\n            e.originalEvent[eventTypeKey] = true;\n            $(e.target).trigger(eventName, [{originalEvent: e}]);\n            return;\n        }\n    };\n\n    /**\n     * Register a keyboard event that ignores modifier keys.\n     *\n     * @method addKeyboardEvent\n     * @private\n     * @param {object} element A jQuery object of the element to bind events to\n     * @param {string} event The custom interaction event name\n     * @param {int} keyCode The key code.\n     */\n    var addKeyboardEvent = function(element, event, keyCode) {\n        element.off('keydown.' + event).on('keydown.' + event, function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCode) {\n                    triggerEvent(event, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the activate event on the given element if it is clicked or the enter\n     * or space key are pressed without a modifier key.\n     *\n     * @method addActivateListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addActivateListener = function(element) {\n        element.off('click.cie.activate').on('click.cie.activate', function(e) {\n            triggerEvent(events.activate, e);\n        });\n        element.off('keydown.cie.activate').on('keydown.cie.activate', function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n                    triggerEvent(events.activate, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the keyboard activate event on the given element if the enter\n     * or space key are pressed without a modifier key.\n     *\n     * @method addKeyboardActivateListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addKeyboardActivateListener = function(element) {\n        element.off('keydown.cie.keyboardactivate').on('keydown.cie.keyboardactivate', function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n                    triggerEvent(events.keyboardActivate, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the escape event on the given element if the escape key is pressed\n     * without a modifier key.\n     *\n     * @method addEscapeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEscapeListener = function(element) {\n        addKeyboardEvent(element, events.escape, keyCodes.escape);\n    };\n\n    /**\n     * Trigger the down event on the given element if the down arrow key is pressed\n     * without a modifier key.\n     *\n     * @method addDownListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addDownListener = function(element) {\n        addKeyboardEvent(element, events.down, keyCodes.arrowDown);\n    };\n\n    /**\n     * Trigger the up event on the given element if the up arrow key is pressed\n     * without a modifier key.\n     *\n     * @method addUpListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addUpListener = function(element) {\n        addKeyboardEvent(element, events.up, keyCodes.arrowUp);\n    };\n\n    /**\n     * Trigger the home event on the given element if the home key is pressed\n     * without a modifier key.\n     *\n     * @method addHomeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addHomeListener = function(element) {\n        addKeyboardEvent(element, events.home, keyCodes.home);\n    };\n\n    /**\n     * Trigger the end event on the given element if the end key is pressed\n     * without a modifier key.\n     *\n     * @method addEndListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEndListener = function(element) {\n        addKeyboardEvent(element, events.end, keyCodes.end);\n    };\n\n    /**\n     * Trigger the next event on the given element if the right arrow key is pressed\n     * without a modifier key in LTR mode or left arrow key in RTL mode.\n     *\n     * @method addNextListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addNextListener = function(element) {\n        // Left and right are flipped in RTL mode.\n        var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowLeft : keyCodes.arrowRight;\n\n        addKeyboardEvent(element, events.next, keyCode);\n    };\n\n    /**\n     * Trigger the previous event on the given element if the left arrow key is pressed\n     * without a modifier key in LTR mode or right arrow key in RTL mode.\n     *\n     * @method addPreviousListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addPreviousListener = function(element) {\n        // Left and right are flipped in RTL mode.\n        var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowRight : keyCodes.arrowLeft;\n\n        addKeyboardEvent(element, events.previous, keyCode);\n    };\n\n    /**\n     * Trigger the asterix event on the given element if the asterix key is pressed\n     * without a modifier key.\n     *\n     * @method addAsterixListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addAsterixListener = function(element) {\n        addKeyboardEvent(element, events.asterix, keyCodes.asterix);\n    };\n\n\n    /**\n     * Trigger the scrollTop event on the given element if the user scrolls to\n     * the top of the given element.\n     *\n     * @method addScrollTopListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addScrollTopListener = function(element) {\n        element.off('scroll.cie.scrollTop').on('scroll.cie.scrollTop', function(e) {\n            var scrollTop = element.scrollTop();\n            if (scrollTop === 0) {\n                triggerEvent(events.scrollTop, e);\n            }\n        });\n    };\n\n    /**\n     * Trigger the scrollBottom event on the given element if the user scrolls to\n     * the bottom of the given element.\n     *\n     * @method addScrollBottomListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addScrollBottomListener = function(element) {\n        element.off('scroll.cie.scrollBottom').on('scroll.cie.scrollBottom', function(e) {\n            var scrollTop = element.scrollTop();\n            var innerHeight = element.innerHeight();\n            var scrollHeight = element[0].scrollHeight;\n\n            if (scrollTop + innerHeight >= scrollHeight) {\n                triggerEvent(events.scrollBottom, e);\n            }\n        });\n    };\n\n    /**\n     * Trigger the scrollLock event on the given element if the user scrolls to\n     * the bottom or top of the given element.\n     *\n     * @method addScrollLockListener\n     * @private\n     * @param {jQuery} element jQuery object to add event listeners to\n     */\n    var addScrollLockListener = function(element) {\n        // Lock mousewheel scrolling within the element to stop the annoying window scroll.\n        element.off('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock')\n            .on('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock', function(e) {\n                var scrollTop = element.scrollTop();\n                var scrollHeight = element[0].scrollHeight;\n                var height = element.height();\n                var delta = (e.type == 'DOMMouseScroll' ?\n                    e.originalEvent.detail * -40 :\n                    e.originalEvent.wheelDelta);\n                var up = delta > 0;\n\n                if (!up && -delta > scrollHeight - height - scrollTop) {\n                    // Scrolling down past the bottom.\n                    element.scrollTop(scrollHeight);\n                    e.stopPropagation();\n                    e.preventDefault();\n                    e.returnValue = false;\n                    // Fire the scroll lock event.\n                    triggerEvent(events.scrollLock, e);\n\n                    return false;\n                } else if (up && delta > scrollTop) {\n                    // Scrolling up past the top.\n                    element.scrollTop(0);\n                    e.stopPropagation();\n                    e.preventDefault();\n                    e.returnValue = false;\n                    // Fire the scroll lock event.\n                    triggerEvent(events.scrollLock, e);\n\n                    return false;\n                }\n\n                return true;\n            });\n    };\n\n    /**\n     * Trigger the ctrlPageUp event on the given element if the user presses the\n     * control and page up key.\n     *\n     * @method addCtrlPageUpListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addCtrlPageUpListener = function(element) {\n        element.off('keydown.cie.ctrlpageup').on('keydown.cie.ctrlpageup', function(e) {\n            if (e.ctrlKey) {\n                if (e.keyCode == keyCodes.pageUp) {\n                    triggerEvent(events.ctrlPageUp, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the ctrlPageDown event on the given element if the user presses the\n     * control and page down key.\n     *\n     * @method addCtrlPageDownListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addCtrlPageDownListener = function(element) {\n        element.off('keydown.cie.ctrlpagedown').on('keydown.cie.ctrlpagedown', function(e) {\n            if (e.ctrlKey) {\n                if (e.keyCode == keyCodes.pageDown) {\n                    triggerEvent(events.ctrlPageDown, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the enter event on the given element if the enter key is pressed\n     * without a modifier key.\n     *\n     * @method addEnterListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEnterListener = function(element) {\n        addKeyboardEvent(element, events.enter, keyCodes.enter);\n    };\n\n    /**\n     * Trigger the AccessibleChange event on the given element if the value of the element is changed.\n     *\n     * @method addAccessibleChangeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addAccessibleChangeListener = function(element) {\n        var onMac = navigator.userAgent.indexOf('Macintosh') !== -1;\n        var touchEnabled = ('ontouchstart' in window) || (('msMaxTouchPoints' in navigator) && (navigator.msMaxTouchPoints > 0));\n        if (onMac || touchEnabled) {\n            element.on('change', function(e) {\n                triggerEvent(events.accessibleChange, e);\n            });\n        } else {\n            var nativeElement = element.get()[0];\n            // The `focus` and `blur` events do not support bubbling. Use Event Capture instead.\n            nativeElement.addEventListener('focus', function(e) {\n                $(e.target).data('initValue', e.target.value);\n            }, true);\n            nativeElement.addEventListener('blur', function(e) {\n                var initValue = $(e.target).data('initValue');\n                $(e.target).removeData('initValue');\n                if (e.target.value !== initValue) {\n                    triggerEvent(events.accessibleChange, e);\n                }\n            }, true);\n            element.on('keydown', function(e) {\n                if ((e.which === keyCodes.enter) && e.target.value !== $(e.target).data('initValue')) {\n                    triggerEvent(events.accessibleChange, e);\n                } else if (e.which === keyCodes.escape) {\n                    e.target.value = $(e.target).data('initValue');\n                }\n            });\n            element.on('click', function(e) {\n                var initValue = $(e.target).data('initValue');\n                // Some browsers trigger onclick before onblur, therefore it is possible that initValue is undefined.\n                if (typeof initValue !== 'undefined' && initValue != e.target.value) {\n                    triggerEvent(events.accessibleChange, e);\n                }\n            });\n        }\n    };\n\n    /**\n     * Get the list of events and their handlers.\n     *\n     * @method getHandlers\n     * @private\n     * @return {object} object key of event names and value of handler functions\n     */\n    var getHandlers = function() {\n        var handlers = {};\n\n        handlers[events.activate] = addActivateListener;\n        handlers[events.keyboardActivate] = addKeyboardActivateListener;\n        handlers[events.escape] = addEscapeListener;\n        handlers[events.down] = addDownListener;\n        handlers[events.up] = addUpListener;\n        handlers[events.home] = addHomeListener;\n        handlers[events.end] = addEndListener;\n        handlers[events.next] = addNextListener;\n        handlers[events.previous] = addPreviousListener;\n        handlers[events.asterix] = addAsterixListener;\n        handlers[events.scrollLock] = addScrollLockListener;\n        handlers[events.scrollTop] = addScrollTopListener;\n        handlers[events.scrollBottom] = addScrollBottomListener;\n        handlers[events.ctrlPageUp] = addCtrlPageUpListener;\n        handlers[events.ctrlPageDown] = addCtrlPageDownListener;\n        handlers[events.enter] = addEnterListener;\n        handlers[events.accessibleChange] = addAccessibleChangeListener;\n\n        return handlers;\n    };\n\n    /**\n     * Add all of the listeners on the given element for the requested events.\n     *\n     * @method define\n     * @public\n     * @param {object} element the DOM element to register event listeners on\n     * @param {array} include the array of events to be triggered\n     */\n    var define = function(element, include) {\n        element = $(element);\n        include = include || [];\n\n        if (!element.length || !include.length) {\n            return;\n        }\n\n        $.each(getHandlers(), function(eventType, handler) {\n            if (shouldAddEvent(eventType, include)) {\n                handler(element);\n            }\n        });\n    };\n\n    return /** @module core/custom_interaction_events */ {\n        define: define,\n        events: events,\n    };\n});\n"],"file":"custom_interaction_events.min.js"}
\ No newline at end of file
diff --git a/lib/amd/src/custom_interaction_events.js b/lib/amd/src/custom_interaction_events.js
index 84f09d2d5fd..c429e926341 100644
--- a/lib/amd/src/custom_interaction_events.js
+++ b/lib/amd/src/custom_interaction_events.js
@@ -431,16 +431,18 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
                 triggerEvent(events.accessibleChange, e);
             });
         } else {
-            element.on('focusin', function(e) {
+            var nativeElement = element.get()[0];
+            // The `focus` and `blur` events do not support bubbling. Use Event Capture instead.
+            nativeElement.addEventListener('focus', function(e) {
                 $(e.target).data('initValue', e.target.value);
-            });
-            element.on('focusout', function(e) {
+            }, true);
+            nativeElement.addEventListener('blur', function(e) {
                 var initValue = $(e.target).data('initValue');
                 $(e.target).removeData('initValue');
                 if (e.target.value !== initValue) {
                     triggerEvent(events.accessibleChange, e);
                 }
-            });
+            }, true);
             element.on('keydown', function(e) {
                 if ((e.which === keyCodes.enter) && e.target.value !== $(e.target).data('initValue')) {
                     triggerEvent(events.accessibleChange, e);

From 189a4c8f8e8da3bbec0e6988fd578ce18649e6e3 Mon Sep 17 00:00:00 2001
From: Andrew Nicols <andrew@nicols.co.uk>
Date: Mon, 2 Nov 2020 09:33:05 +0800
Subject: [PATCH 2/5] MDL-70075 core: Listen for `change` in  accessibleChange
 event

The accessibleChange custom interaction event was only listening for
blur and focus, however some OS/browser combinations do not emit these
events until the element is explicitly blurred. This is notably
different on Firefox on some Operating Systems.

Recent changes in MDL-68167 explicitly moved the user participants page
filter module to use the accessibleChange event, which means that the
selections are now only triggered on an explicit blur when using
Firefox. This highlight a bug whereby, when the mouse is used to make a
selection, the event is not triggered until the element is blurred.

This change modifies the accessibleChange event to ignore the `change`
event where it was triggered by the keyboard and where that keybaord
event was not a [return] or [escape] keypress, but to otherwise respect
the native change event.
---
 .../build/custom_interaction_events.min.js    |  2 +-
 .../custom_interaction_events.min.js.map      |  2 +-
 lib/amd/src/custom_interaction_events.js      | 88 ++++++++++++++++---
 3 files changed, 76 insertions(+), 16 deletions(-)

diff --git a/lib/amd/build/custom_interaction_events.min.js b/lib/amd/build/custom_interaction_events.min.js
index 2e6312a9df8..00d449bd8c3 100644
--- a/lib/amd/build/custom_interaction_events.min.js
+++ b/lib/amd/build/custom_interaction_events.min.js
@@ -1,2 +1,2 @@
-define ("core/custom_interaction_events",["jquery","core/key_codes"],function(a,b){var c={activate:"cie:activate",keyboardActivate:"cie:keyboardactivate",escape:"cie:escape",down:"cie:down",up:"cie:up",home:"cie:home",end:"cie:end",next:"cie:next",previous:"cie:previous",asterix:"cie:asterix",scrollLock:"cie:scrollLock",scrollTop:"cie:scrollTop",scrollBottom:"cie:scrollBottom",ctrlPageUp:"cie:ctrlPageUp",ctrlPageDown:"cie:ctrlPageDown",enter:"cie:enter",accessibleChange:"cie:accessibleChange"},d={},e=function(a,b){b=b||[];if(b.length&&-1!==b.indexOf(a)){return!0}return!1},f=function(a){return a.shiftKey||a.metaKey||a.altKey||a.ctrlKey},g=function(b,c){var e="";if(!c.hasOwnProperty("originalEvent")){e=""+b+c.type+c.timeStamp;if(!d.hasOwnProperty(e)){d[e]=!0;a(c.target).trigger(b,[{originalEvent:c}])}return}e="triggeredCustom_"+b;if(!c.originalEvent.hasOwnProperty(e)){c.originalEvent[e]=!0;a(c.target).trigger(b,[{originalEvent:c}])}},h=function(a,b,c){a.off("keydown."+b).on("keydown."+b,function(a){if(!f(a)){if(a.keyCode==c){g(b,a)}}})},i=function(a){a.off("click.cie.activate").on("click.cie.activate",function(a){g(c.activate,a)});a.off("keydown.cie.activate").on("keydown.cie.activate",function(a){if(!f(a)){if(a.keyCode==b.enter||a.keyCode==b.space){g(c.activate,a)}}})},j=function(a){a.off("keydown.cie.keyboardactivate").on("keydown.cie.keyboardactivate",function(a){if(!f(a)){if(a.keyCode==b.enter||a.keyCode==b.space){g(c.keyboardActivate,a)}}})},k=function(a){h(a,c.escape,b.escape)},l=function(a){h(a,c.down,b.arrowDown)},m=function(a){h(a,c.up,b.arrowUp)},n=function(a){h(a,c.home,b.home)},o=function(a){h(a,c.end,b.end)},p=function(d){var e="rtl"==a("html").attr("dir")?b.arrowLeft:b.arrowRight;h(d,c.next,e)},q=function(d){var e="rtl"==a("html").attr("dir")?b.arrowRight:b.arrowLeft;h(d,c.previous,e)},r=function(a){h(a,c.asterix,b.asterix)},s=function(a){a.off("scroll.cie.scrollTop").on("scroll.cie.scrollTop",function(b){var d=a.scrollTop();if(0===d){g(c.scrollTop,b)}})},t=function(a){a.off("scroll.cie.scrollBottom").on("scroll.cie.scrollBottom",function(b){var d=a.scrollTop(),e=a.innerHeight(),f=a[0].scrollHeight;if(d+e>=f){g(c.scrollBottom,b)}})},u=function(a){a.off("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock").on("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock",function(b){var d=a.scrollTop(),e=a[0].scrollHeight,f=a.height(),h="DOMMouseScroll"==b.type?-40*b.originalEvent.detail:b.originalEvent.wheelDelta,i=0<h;if(!i&&-h>e-f-d){a.scrollTop(e);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}else if(i&&h>d){a.scrollTop(0);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}return!0})},v=function(a){a.off("keydown.cie.ctrlpageup").on("keydown.cie.ctrlpageup",function(a){if(a.ctrlKey){if(a.keyCode==b.pageUp){g(c.ctrlPageUp,a)}}})},w=function(a){a.off("keydown.cie.ctrlpagedown").on("keydown.cie.ctrlpagedown",function(a){if(a.ctrlKey){if(a.keyCode==b.pageDown){g(c.ctrlPageDown,a)}}})},x=function(a){h(a,c.enter,b.enter)},y=function(d){var e=-1!==navigator.userAgent.indexOf("Macintosh"),f="ontouchstart"in window||"msMaxTouchPoints"in navigator&&0<navigator.msMaxTouchPoints;if(e||f){d.on("change",function(a){g(c.accessibleChange,a)})}else{var h=d.get()[0];h.addEventListener("focus",function(b){a(b.target).data("initValue",b.target.value)},!0);h.addEventListener("blur",function(b){var d=a(b.target).data("initValue");a(b.target).removeData("initValue");if(b.target.value!==d){g(c.accessibleChange,b)}},!0);d.on("keydown",function(d){if(d.which===b.enter&&d.target.value!==a(d.target).data("initValue")){g(c.accessibleChange,d)}else if(d.which===b.escape){d.target.value=a(d.target).data("initValue")}});d.on("click",function(b){var d=a(b.target).data("initValue");if("undefined"!=typeof d&&d!=b.target.value){g(c.accessibleChange,b)}})}},z=function(){var a={};a[c.activate]=i;a[c.keyboardActivate]=j;a[c.escape]=k;a[c.down]=l;a[c.up]=m;a[c.home]=n;a[c.end]=o;a[c.next]=p;a[c.previous]=q;a[c.asterix]=r;a[c.scrollLock]=u;a[c.scrollTop]=s;a[c.scrollBottom]=t;a[c.ctrlPageUp]=v;a[c.ctrlPageDown]=w;a[c.enter]=x;a[c.accessibleChange]=y;return a};return{define:function define(b,c){b=a(b);c=c||[];if(!b.length||!c.length){return}a.each(z(),function(a,d){if(e(a,c)){d(b)}})},events:c}});
+define ("core/custom_interaction_events",["jquery","core/key_codes"],function(a,b){var c={activate:"cie:activate",keyboardActivate:"cie:keyboardactivate",escape:"cie:escape",down:"cie:down",up:"cie:up",home:"cie:home",end:"cie:end",next:"cie:next",previous:"cie:previous",asterix:"cie:asterix",scrollLock:"cie:scrollLock",scrollTop:"cie:scrollTop",scrollBottom:"cie:scrollBottom",ctrlPageUp:"cie:ctrlPageUp",ctrlPageDown:"cie:ctrlPageDown",enter:"cie:enter",accessibleChange:"cie:accessibleChange"},d={},e=function(a,b){b=b||[];if(b.length&&-1!==b.indexOf(a)){return!0}return!1},f=function(a){return a.shiftKey||a.metaKey||a.altKey||a.ctrlKey},g=function(b,c){var e="";if(!c.hasOwnProperty("originalEvent")){e=""+b+c.type+c.timeStamp;if(!d.hasOwnProperty(e)){d[e]=!0;a(c.target).trigger(b,[{originalEvent:c}])}return}e="triggeredCustom_"+b;if(!c.originalEvent.hasOwnProperty(e)){c.originalEvent[e]=!0;a(c.target).trigger(b,[{originalEvent:c}])}},h=function(a,b,c){a.off("keydown."+b).on("keydown."+b,function(a){if(!f(a)){if(a.keyCode==c){g(b,a)}}})},i=function(a){a.off("click.cie.activate").on("click.cie.activate",function(a){g(c.activate,a)});a.off("keydown.cie.activate").on("keydown.cie.activate",function(a){if(!f(a)){if(a.keyCode==b.enter||a.keyCode==b.space){g(c.activate,a)}}})},j=function(a){a.off("keydown.cie.keyboardactivate").on("keydown.cie.keyboardactivate",function(a){if(!f(a)){if(a.keyCode==b.enter||a.keyCode==b.space){g(c.keyboardActivate,a)}}})},k=function(a){h(a,c.escape,b.escape)},l=function(a){h(a,c.down,b.arrowDown)},m=function(a){h(a,c.up,b.arrowUp)},n=function(a){h(a,c.home,b.home)},o=function(a){h(a,c.end,b.end)},p=function(d){var e="rtl"==a("html").attr("dir")?b.arrowLeft:b.arrowRight;h(d,c.next,e)},q=function(d){var e="rtl"==a("html").attr("dir")?b.arrowRight:b.arrowLeft;h(d,c.previous,e)},r=function(a){h(a,c.asterix,b.asterix)},s=function(a){a.off("scroll.cie.scrollTop").on("scroll.cie.scrollTop",function(b){var d=a.scrollTop();if(0===d){g(c.scrollTop,b)}})},t=function(a){a.off("scroll.cie.scrollBottom").on("scroll.cie.scrollBottom",function(b){var d=a.scrollTop(),e=a.innerHeight(),f=a[0].scrollHeight;if(d+e>=f){g(c.scrollBottom,b)}})},u=function(a){a.off("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock").on("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock",function(b){var d=a.scrollTop(),e=a[0].scrollHeight,f=a.height(),h="DOMMouseScroll"==b.type?-40*b.originalEvent.detail:b.originalEvent.wheelDelta,i=0<h;if(!i&&-h>e-f-d){a.scrollTop(e);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}else if(i&&h>d){a.scrollTop(0);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}return!0})},v=function(a){a.off("keydown.cie.ctrlpageup").on("keydown.cie.ctrlpageup",function(a){if(a.ctrlKey){if(a.keyCode==b.pageUp){g(c.ctrlPageUp,a)}}})},w=function(a){a.off("keydown.cie.ctrlpagedown").on("keydown.cie.ctrlpagedown",function(a){if(a.ctrlKey){if(a.keyCode==b.pageDown){g(c.ctrlPageDown,a)}}})},x=function(a){h(a,c.enter,b.enter)},y=function(a){var d=-1!==navigator.userAgent.indexOf("Macintosh"),e="ontouchstart"in window||"msMaxTouchPoints"in navigator&&0<navigator.msMaxTouchPoints;if(d||e){a.on("change",function(a){g(c.accessibleChange,a)})}else{var f=function(a){a.dataset.initValue=a.value},h=function(a){if("initValue"in a.dataset){a.value=a.dataset.initValue}},i=function(a){if(!("initValue"in a.target.dataset)){return}if(a.target.value!==a.target.dataset.initValue){a.target.dataset.initValue=a.target.value;g(c.accessibleChange,a)}},j=a.get()[0];j.addEventListener("focus",function(a){f(a.target)},!0);j.addEventListener("blur",function(a){i(a)},!0);a.on("keydown",function(a){if(a.which===b.enter){i(a)}else if(a.which===b.escape){h(a.target);a.target.dataset.ignoreChange=!0}else{a.target.dataset.ignoreChange=!0}});a.on("change",function(a){if(a.target.dataset.ignoreChange){return}i(a)});a.on("keyup",function(a){delete a.target.dataset.ignoreChange});a.on("click",function(a){i(a)})}},z=function(){var a={};a[c.activate]=i;a[c.keyboardActivate]=j;a[c.escape]=k;a[c.down]=l;a[c.up]=m;a[c.home]=n;a[c.end]=o;a[c.next]=p;a[c.previous]=q;a[c.asterix]=r;a[c.scrollLock]=u;a[c.scrollTop]=s;a[c.scrollBottom]=t;a[c.ctrlPageUp]=v;a[c.ctrlPageDown]=w;a[c.enter]=x;a[c.accessibleChange]=y;return a};return{define:function define(b,c){b=a(b);c=c||[];if(!b.length||!c.length){return}a.each(z(),function(a,d){if(e(a,c)){d(b)}})},events:c}});
 //# sourceMappingURL=custom_interaction_events.min.js.map
diff --git a/lib/amd/build/custom_interaction_events.min.js.map b/lib/amd/build/custom_interaction_events.min.js.map
index a603b954104..6d148be2fc5 100644
--- a/lib/amd/build/custom_interaction_events.min.js.map
+++ b/lib/amd/build/custom_interaction_events.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/custom_interaction_events.js"],"names":["define","$","keyCodes","events","activate","keyboardActivate","escape","down","up","home","end","next","previous","asterix","scrollLock","scrollTop","scrollBottom","ctrlPageUp","ctrlPageDown","enter","accessibleChange","triggeredEvents","shouldAddEvent","eventType","include","length","indexOf","isModifierPressed","e","shiftKey","metaKey","altKey","ctrlKey","triggerEvent","eventName","eventTypeKey","hasOwnProperty","type","timeStamp","target","trigger","originalEvent","addKeyboardEvent","element","event","keyCode","off","on","addActivateListener","space","addKeyboardActivateListener","addEscapeListener","addDownListener","arrowDown","addUpListener","arrowUp","addHomeListener","addEndListener","addNextListener","attr","arrowLeft","arrowRight","addPreviousListener","addAsterixListener","addScrollTopListener","addScrollBottomListener","innerHeight","scrollHeight","addScrollLockListener","height","delta","detail","wheelDelta","stopPropagation","preventDefault","returnValue","addCtrlPageUpListener","pageUp","addCtrlPageDownListener","pageDown","addEnterListener","addAccessibleChangeListener","onMac","navigator","userAgent","touchEnabled","window","msMaxTouchPoints","nativeElement","get","addEventListener","data","value","initValue","removeData","which","getHandlers","handlers","each","handler"],"mappings":"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","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 <http://www.gnu.org/licenses/>.\n\n/**\n * This module provides a wrapper to encapsulate a lot of the common combinations of\n * user interaction we use in Moodle.\n *\n * @module     core/custom_interaction_events\n * @class      custom_interaction_events\n * @package    core\n * @copyright  2016 Ryan Wyllie <ryan@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.2\n */\ndefine(['jquery', 'core/key_codes'], function($, keyCodes) {\n    // The list of events provided by this module. Namespaced to avoid clashes.\n    var events = {\n        activate: 'cie:activate',\n        keyboardActivate: 'cie:keyboardactivate',\n        escape: 'cie:escape',\n        down: 'cie:down',\n        up: 'cie:up',\n        home: 'cie:home',\n        end: 'cie:end',\n        next: 'cie:next',\n        previous: 'cie:previous',\n        asterix: 'cie:asterix',\n        scrollLock: 'cie:scrollLock',\n        scrollTop: 'cie:scrollTop',\n        scrollBottom: 'cie:scrollBottom',\n        ctrlPageUp: 'cie:ctrlPageUp',\n        ctrlPageDown: 'cie:ctrlPageDown',\n        enter: 'cie:enter',\n        accessibleChange: 'cie:accessibleChange',\n    };\n    // Static cache of jQuery events that have been handled. This should\n    // only be populated by JavaScript generated events (which will keep it\n    // fairly small).\n    var triggeredEvents = {};\n\n    /**\n     * Check if the caller has asked for the given event type to be\n     * registered.\n     *\n     * @method shouldAddEvent\n     * @private\n     * @param {string} eventType name of the event (see events above)\n     * @param {array} include the list of events to be added\n     * @return {bool} true if the event should be added, false otherwise.\n     */\n    var shouldAddEvent = function(eventType, include) {\n        include = include || [];\n\n        if (include.length && include.indexOf(eventType) !== -1) {\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * Check if any of the modifier keys have been pressed on the event.\n     *\n     * @method isModifierPressed\n     * @private\n     * @param {event} e jQuery event\n     * @return {bool} true if shift, meta (command on Mac), alt or ctrl are pressed\n     */\n    var isModifierPressed = function(e) {\n        return (e.shiftKey || e.metaKey || e.altKey || e.ctrlKey);\n    };\n\n    /**\n     * Trigger the custom event for the given jQuery event.\n     *\n     * This function will only fire the custom event if one hasn't already been\n     * fired for the jQuery event.\n     *\n     * This is to prevent multiple custom event handlers triggering multiple\n     * custom events for a single jQuery event as it bubbles up the stack.\n     *\n     * @param  {string} eventName The name of the custom event\n     * @param  {event} e          The jQuery event\n     * @return {void}\n     */\n    var triggerEvent = function(eventName, e) {\n        var eventTypeKey = \"\";\n\n        if (!e.hasOwnProperty('originalEvent')) {\n            // This is a jQuery event generated from JavaScript not a browser event so\n            // we need to build the cache key for the event.\n            eventTypeKey = \"\" + eventName + e.type + e.timeStamp;\n\n            if (!triggeredEvents.hasOwnProperty(eventTypeKey)) {\n                // If we haven't seen this jQuery event before then fire a custom\n                // event for it and remember the event for later.\n                triggeredEvents[eventTypeKey] = true;\n                $(e.target).trigger(eventName, [{originalEvent: e}]);\n            }\n            return;\n        }\n\n        eventTypeKey = \"triggeredCustom_\" + eventName;\n        if (!e.originalEvent.hasOwnProperty(eventTypeKey)) {\n            // If this is a jQuery event generated by the browser then set a\n            // property on the original event to track that we've seen it before.\n            // The property is set on the original event because it's the only part\n            // of the jQuery event that is maintained through multiple event handlers.\n            e.originalEvent[eventTypeKey] = true;\n            $(e.target).trigger(eventName, [{originalEvent: e}]);\n            return;\n        }\n    };\n\n    /**\n     * Register a keyboard event that ignores modifier keys.\n     *\n     * @method addKeyboardEvent\n     * @private\n     * @param {object} element A jQuery object of the element to bind events to\n     * @param {string} event The custom interaction event name\n     * @param {int} keyCode The key code.\n     */\n    var addKeyboardEvent = function(element, event, keyCode) {\n        element.off('keydown.' + event).on('keydown.' + event, function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCode) {\n                    triggerEvent(event, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the activate event on the given element if it is clicked or the enter\n     * or space key are pressed without a modifier key.\n     *\n     * @method addActivateListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addActivateListener = function(element) {\n        element.off('click.cie.activate').on('click.cie.activate', function(e) {\n            triggerEvent(events.activate, e);\n        });\n        element.off('keydown.cie.activate').on('keydown.cie.activate', function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n                    triggerEvent(events.activate, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the keyboard activate event on the given element if the enter\n     * or space key are pressed without a modifier key.\n     *\n     * @method addKeyboardActivateListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addKeyboardActivateListener = function(element) {\n        element.off('keydown.cie.keyboardactivate').on('keydown.cie.keyboardactivate', function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n                    triggerEvent(events.keyboardActivate, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the escape event on the given element if the escape key is pressed\n     * without a modifier key.\n     *\n     * @method addEscapeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEscapeListener = function(element) {\n        addKeyboardEvent(element, events.escape, keyCodes.escape);\n    };\n\n    /**\n     * Trigger the down event on the given element if the down arrow key is pressed\n     * without a modifier key.\n     *\n     * @method addDownListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addDownListener = function(element) {\n        addKeyboardEvent(element, events.down, keyCodes.arrowDown);\n    };\n\n    /**\n     * Trigger the up event on the given element if the up arrow key is pressed\n     * without a modifier key.\n     *\n     * @method addUpListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addUpListener = function(element) {\n        addKeyboardEvent(element, events.up, keyCodes.arrowUp);\n    };\n\n    /**\n     * Trigger the home event on the given element if the home key is pressed\n     * without a modifier key.\n     *\n     * @method addHomeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addHomeListener = function(element) {\n        addKeyboardEvent(element, events.home, keyCodes.home);\n    };\n\n    /**\n     * Trigger the end event on the given element if the end key is pressed\n     * without a modifier key.\n     *\n     * @method addEndListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEndListener = function(element) {\n        addKeyboardEvent(element, events.end, keyCodes.end);\n    };\n\n    /**\n     * Trigger the next event on the given element if the right arrow key is pressed\n     * without a modifier key in LTR mode or left arrow key in RTL mode.\n     *\n     * @method addNextListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addNextListener = function(element) {\n        // Left and right are flipped in RTL mode.\n        var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowLeft : keyCodes.arrowRight;\n\n        addKeyboardEvent(element, events.next, keyCode);\n    };\n\n    /**\n     * Trigger the previous event on the given element if the left arrow key is pressed\n     * without a modifier key in LTR mode or right arrow key in RTL mode.\n     *\n     * @method addPreviousListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addPreviousListener = function(element) {\n        // Left and right are flipped in RTL mode.\n        var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowRight : keyCodes.arrowLeft;\n\n        addKeyboardEvent(element, events.previous, keyCode);\n    };\n\n    /**\n     * Trigger the asterix event on the given element if the asterix key is pressed\n     * without a modifier key.\n     *\n     * @method addAsterixListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addAsterixListener = function(element) {\n        addKeyboardEvent(element, events.asterix, keyCodes.asterix);\n    };\n\n\n    /**\n     * Trigger the scrollTop event on the given element if the user scrolls to\n     * the top of the given element.\n     *\n     * @method addScrollTopListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addScrollTopListener = function(element) {\n        element.off('scroll.cie.scrollTop').on('scroll.cie.scrollTop', function(e) {\n            var scrollTop = element.scrollTop();\n            if (scrollTop === 0) {\n                triggerEvent(events.scrollTop, e);\n            }\n        });\n    };\n\n    /**\n     * Trigger the scrollBottom event on the given element if the user scrolls to\n     * the bottom of the given element.\n     *\n     * @method addScrollBottomListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addScrollBottomListener = function(element) {\n        element.off('scroll.cie.scrollBottom').on('scroll.cie.scrollBottom', function(e) {\n            var scrollTop = element.scrollTop();\n            var innerHeight = element.innerHeight();\n            var scrollHeight = element[0].scrollHeight;\n\n            if (scrollTop + innerHeight >= scrollHeight) {\n                triggerEvent(events.scrollBottom, e);\n            }\n        });\n    };\n\n    /**\n     * Trigger the scrollLock event on the given element if the user scrolls to\n     * the bottom or top of the given element.\n     *\n     * @method addScrollLockListener\n     * @private\n     * @param {jQuery} element jQuery object to add event listeners to\n     */\n    var addScrollLockListener = function(element) {\n        // Lock mousewheel scrolling within the element to stop the annoying window scroll.\n        element.off('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock')\n            .on('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock', function(e) {\n                var scrollTop = element.scrollTop();\n                var scrollHeight = element[0].scrollHeight;\n                var height = element.height();\n                var delta = (e.type == 'DOMMouseScroll' ?\n                    e.originalEvent.detail * -40 :\n                    e.originalEvent.wheelDelta);\n                var up = delta > 0;\n\n                if (!up && -delta > scrollHeight - height - scrollTop) {\n                    // Scrolling down past the bottom.\n                    element.scrollTop(scrollHeight);\n                    e.stopPropagation();\n                    e.preventDefault();\n                    e.returnValue = false;\n                    // Fire the scroll lock event.\n                    triggerEvent(events.scrollLock, e);\n\n                    return false;\n                } else if (up && delta > scrollTop) {\n                    // Scrolling up past the top.\n                    element.scrollTop(0);\n                    e.stopPropagation();\n                    e.preventDefault();\n                    e.returnValue = false;\n                    // Fire the scroll lock event.\n                    triggerEvent(events.scrollLock, e);\n\n                    return false;\n                }\n\n                return true;\n            });\n    };\n\n    /**\n     * Trigger the ctrlPageUp event on the given element if the user presses the\n     * control and page up key.\n     *\n     * @method addCtrlPageUpListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addCtrlPageUpListener = function(element) {\n        element.off('keydown.cie.ctrlpageup').on('keydown.cie.ctrlpageup', function(e) {\n            if (e.ctrlKey) {\n                if (e.keyCode == keyCodes.pageUp) {\n                    triggerEvent(events.ctrlPageUp, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the ctrlPageDown event on the given element if the user presses the\n     * control and page down key.\n     *\n     * @method addCtrlPageDownListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addCtrlPageDownListener = function(element) {\n        element.off('keydown.cie.ctrlpagedown').on('keydown.cie.ctrlpagedown', function(e) {\n            if (e.ctrlKey) {\n                if (e.keyCode == keyCodes.pageDown) {\n                    triggerEvent(events.ctrlPageDown, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the enter event on the given element if the enter key is pressed\n     * without a modifier key.\n     *\n     * @method addEnterListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEnterListener = function(element) {\n        addKeyboardEvent(element, events.enter, keyCodes.enter);\n    };\n\n    /**\n     * Trigger the AccessibleChange event on the given element if the value of the element is changed.\n     *\n     * @method addAccessibleChangeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addAccessibleChangeListener = function(element) {\n        var onMac = navigator.userAgent.indexOf('Macintosh') !== -1;\n        var touchEnabled = ('ontouchstart' in window) || (('msMaxTouchPoints' in navigator) && (navigator.msMaxTouchPoints > 0));\n        if (onMac || touchEnabled) {\n            element.on('change', function(e) {\n                triggerEvent(events.accessibleChange, e);\n            });\n        } else {\n            var nativeElement = element.get()[0];\n            // The `focus` and `blur` events do not support bubbling. Use Event Capture instead.\n            nativeElement.addEventListener('focus', function(e) {\n                $(e.target).data('initValue', e.target.value);\n            }, true);\n            nativeElement.addEventListener('blur', function(e) {\n                var initValue = $(e.target).data('initValue');\n                $(e.target).removeData('initValue');\n                if (e.target.value !== initValue) {\n                    triggerEvent(events.accessibleChange, e);\n                }\n            }, true);\n            element.on('keydown', function(e) {\n                if ((e.which === keyCodes.enter) && e.target.value !== $(e.target).data('initValue')) {\n                    triggerEvent(events.accessibleChange, e);\n                } else if (e.which === keyCodes.escape) {\n                    e.target.value = $(e.target).data('initValue');\n                }\n            });\n            element.on('click', function(e) {\n                var initValue = $(e.target).data('initValue');\n                // Some browsers trigger onclick before onblur, therefore it is possible that initValue is undefined.\n                if (typeof initValue !== 'undefined' && initValue != e.target.value) {\n                    triggerEvent(events.accessibleChange, e);\n                }\n            });\n        }\n    };\n\n    /**\n     * Get the list of events and their handlers.\n     *\n     * @method getHandlers\n     * @private\n     * @return {object} object key of event names and value of handler functions\n     */\n    var getHandlers = function() {\n        var handlers = {};\n\n        handlers[events.activate] = addActivateListener;\n        handlers[events.keyboardActivate] = addKeyboardActivateListener;\n        handlers[events.escape] = addEscapeListener;\n        handlers[events.down] = addDownListener;\n        handlers[events.up] = addUpListener;\n        handlers[events.home] = addHomeListener;\n        handlers[events.end] = addEndListener;\n        handlers[events.next] = addNextListener;\n        handlers[events.previous] = addPreviousListener;\n        handlers[events.asterix] = addAsterixListener;\n        handlers[events.scrollLock] = addScrollLockListener;\n        handlers[events.scrollTop] = addScrollTopListener;\n        handlers[events.scrollBottom] = addScrollBottomListener;\n        handlers[events.ctrlPageUp] = addCtrlPageUpListener;\n        handlers[events.ctrlPageDown] = addCtrlPageDownListener;\n        handlers[events.enter] = addEnterListener;\n        handlers[events.accessibleChange] = addAccessibleChangeListener;\n\n        return handlers;\n    };\n\n    /**\n     * Add all of the listeners on the given element for the requested events.\n     *\n     * @method define\n     * @public\n     * @param {object} element the DOM element to register event listeners on\n     * @param {array} include the array of events to be triggered\n     */\n    var define = function(element, include) {\n        element = $(element);\n        include = include || [];\n\n        if (!element.length || !include.length) {\n            return;\n        }\n\n        $.each(getHandlers(), function(eventType, handler) {\n            if (shouldAddEvent(eventType, include)) {\n                handler(element);\n            }\n        });\n    };\n\n    return /** @module core/custom_interaction_events */ {\n        define: define,\n        events: events,\n    };\n});\n"],"file":"custom_interaction_events.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/custom_interaction_events.js"],"names":["define","$","keyCodes","events","activate","keyboardActivate","escape","down","up","home","end","next","previous","asterix","scrollLock","scrollTop","scrollBottom","ctrlPageUp","ctrlPageDown","enter","accessibleChange","triggeredEvents","shouldAddEvent","eventType","include","length","indexOf","isModifierPressed","e","shiftKey","metaKey","altKey","ctrlKey","triggerEvent","eventName","eventTypeKey","hasOwnProperty","type","timeStamp","target","trigger","originalEvent","addKeyboardEvent","element","event","keyCode","off","on","addActivateListener","space","addKeyboardActivateListener","addEscapeListener","addDownListener","arrowDown","addUpListener","arrowUp","addHomeListener","addEndListener","addNextListener","attr","arrowLeft","arrowRight","addPreviousListener","addAsterixListener","addScrollTopListener","addScrollBottomListener","innerHeight","scrollHeight","addScrollLockListener","height","delta","detail","wheelDelta","stopPropagation","preventDefault","returnValue","addCtrlPageUpListener","pageUp","addCtrlPageDownListener","pageDown","addEnterListener","addAccessibleChangeListener","onMac","navigator","userAgent","touchEnabled","window","msMaxTouchPoints","setInitialValue","dataset","initValue","value","resetToInitialValue","checkAndTriggerAccessibleChange","nativeElement","get","addEventListener","which","ignoreChange","getHandlers","handlers","each","handler"],"mappings":"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","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 <http://www.gnu.org/licenses/>.\n\n/**\n * This module provides a wrapper to encapsulate a lot of the common combinations of\n * user interaction we use in Moodle.\n *\n * @module     core/custom_interaction_events\n * @class      custom_interaction_events\n * @package    core\n * @copyright  2016 Ryan Wyllie <ryan@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.2\n */\ndefine(['jquery', 'core/key_codes'], function($, keyCodes) {\n    // The list of events provided by this module. Namespaced to avoid clashes.\n    var events = {\n        activate: 'cie:activate',\n        keyboardActivate: 'cie:keyboardactivate',\n        escape: 'cie:escape',\n        down: 'cie:down',\n        up: 'cie:up',\n        home: 'cie:home',\n        end: 'cie:end',\n        next: 'cie:next',\n        previous: 'cie:previous',\n        asterix: 'cie:asterix',\n        scrollLock: 'cie:scrollLock',\n        scrollTop: 'cie:scrollTop',\n        scrollBottom: 'cie:scrollBottom',\n        ctrlPageUp: 'cie:ctrlPageUp',\n        ctrlPageDown: 'cie:ctrlPageDown',\n        enter: 'cie:enter',\n        accessibleChange: 'cie:accessibleChange',\n    };\n    // Static cache of jQuery events that have been handled. This should\n    // only be populated by JavaScript generated events (which will keep it\n    // fairly small).\n    var triggeredEvents = {};\n\n    /**\n     * Check if the caller has asked for the given event type to be\n     * registered.\n     *\n     * @method shouldAddEvent\n     * @private\n     * @param {string} eventType name of the event (see events above)\n     * @param {array} include the list of events to be added\n     * @return {bool} true if the event should be added, false otherwise.\n     */\n    var shouldAddEvent = function(eventType, include) {\n        include = include || [];\n\n        if (include.length && include.indexOf(eventType) !== -1) {\n            return true;\n        }\n\n        return false;\n    };\n\n    /**\n     * Check if any of the modifier keys have been pressed on the event.\n     *\n     * @method isModifierPressed\n     * @private\n     * @param {event} e jQuery event\n     * @return {bool} true if shift, meta (command on Mac), alt or ctrl are pressed\n     */\n    var isModifierPressed = function(e) {\n        return (e.shiftKey || e.metaKey || e.altKey || e.ctrlKey);\n    };\n\n    /**\n     * Trigger the custom event for the given jQuery event.\n     *\n     * This function will only fire the custom event if one hasn't already been\n     * fired for the jQuery event.\n     *\n     * This is to prevent multiple custom event handlers triggering multiple\n     * custom events for a single jQuery event as it bubbles up the stack.\n     *\n     * @param  {string} eventName The name of the custom event\n     * @param  {event} e          The jQuery event\n     * @return {void}\n     */\n    var triggerEvent = function(eventName, e) {\n        var eventTypeKey = \"\";\n\n        if (!e.hasOwnProperty('originalEvent')) {\n            // This is a jQuery event generated from JavaScript not a browser event so\n            // we need to build the cache key for the event.\n            eventTypeKey = \"\" + eventName + e.type + e.timeStamp;\n\n            if (!triggeredEvents.hasOwnProperty(eventTypeKey)) {\n                // If we haven't seen this jQuery event before then fire a custom\n                // event for it and remember the event for later.\n                triggeredEvents[eventTypeKey] = true;\n                $(e.target).trigger(eventName, [{originalEvent: e}]);\n            }\n            return;\n        }\n\n        eventTypeKey = \"triggeredCustom_\" + eventName;\n        if (!e.originalEvent.hasOwnProperty(eventTypeKey)) {\n            // If this is a jQuery event generated by the browser then set a\n            // property on the original event to track that we've seen it before.\n            // The property is set on the original event because it's the only part\n            // of the jQuery event that is maintained through multiple event handlers.\n            e.originalEvent[eventTypeKey] = true;\n            $(e.target).trigger(eventName, [{originalEvent: e}]);\n            return;\n        }\n    };\n\n    /**\n     * Register a keyboard event that ignores modifier keys.\n     *\n     * @method addKeyboardEvent\n     * @private\n     * @param {object} element A jQuery object of the element to bind events to\n     * @param {string} event The custom interaction event name\n     * @param {int} keyCode The key code.\n     */\n    var addKeyboardEvent = function(element, event, keyCode) {\n        element.off('keydown.' + event).on('keydown.' + event, function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCode) {\n                    triggerEvent(event, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the activate event on the given element if it is clicked or the enter\n     * or space key are pressed without a modifier key.\n     *\n     * @method addActivateListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addActivateListener = function(element) {\n        element.off('click.cie.activate').on('click.cie.activate', function(e) {\n            triggerEvent(events.activate, e);\n        });\n        element.off('keydown.cie.activate').on('keydown.cie.activate', function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n                    triggerEvent(events.activate, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the keyboard activate event on the given element if the enter\n     * or space key are pressed without a modifier key.\n     *\n     * @method addKeyboardActivateListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addKeyboardActivateListener = function(element) {\n        element.off('keydown.cie.keyboardactivate').on('keydown.cie.keyboardactivate', function(e) {\n            if (!isModifierPressed(e)) {\n                if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n                    triggerEvent(events.keyboardActivate, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the escape event on the given element if the escape key is pressed\n     * without a modifier key.\n     *\n     * @method addEscapeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEscapeListener = function(element) {\n        addKeyboardEvent(element, events.escape, keyCodes.escape);\n    };\n\n    /**\n     * Trigger the down event on the given element if the down arrow key is pressed\n     * without a modifier key.\n     *\n     * @method addDownListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addDownListener = function(element) {\n        addKeyboardEvent(element, events.down, keyCodes.arrowDown);\n    };\n\n    /**\n     * Trigger the up event on the given element if the up arrow key is pressed\n     * without a modifier key.\n     *\n     * @method addUpListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addUpListener = function(element) {\n        addKeyboardEvent(element, events.up, keyCodes.arrowUp);\n    };\n\n    /**\n     * Trigger the home event on the given element if the home key is pressed\n     * without a modifier key.\n     *\n     * @method addHomeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addHomeListener = function(element) {\n        addKeyboardEvent(element, events.home, keyCodes.home);\n    };\n\n    /**\n     * Trigger the end event on the given element if the end key is pressed\n     * without a modifier key.\n     *\n     * @method addEndListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEndListener = function(element) {\n        addKeyboardEvent(element, events.end, keyCodes.end);\n    };\n\n    /**\n     * Trigger the next event on the given element if the right arrow key is pressed\n     * without a modifier key in LTR mode or left arrow key in RTL mode.\n     *\n     * @method addNextListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addNextListener = function(element) {\n        // Left and right are flipped in RTL mode.\n        var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowLeft : keyCodes.arrowRight;\n\n        addKeyboardEvent(element, events.next, keyCode);\n    };\n\n    /**\n     * Trigger the previous event on the given element if the left arrow key is pressed\n     * without a modifier key in LTR mode or right arrow key in RTL mode.\n     *\n     * @method addPreviousListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addPreviousListener = function(element) {\n        // Left and right are flipped in RTL mode.\n        var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowRight : keyCodes.arrowLeft;\n\n        addKeyboardEvent(element, events.previous, keyCode);\n    };\n\n    /**\n     * Trigger the asterix event on the given element if the asterix key is pressed\n     * without a modifier key.\n     *\n     * @method addAsterixListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addAsterixListener = function(element) {\n        addKeyboardEvent(element, events.asterix, keyCodes.asterix);\n    };\n\n\n    /**\n     * Trigger the scrollTop event on the given element if the user scrolls to\n     * the top of the given element.\n     *\n     * @method addScrollTopListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addScrollTopListener = function(element) {\n        element.off('scroll.cie.scrollTop').on('scroll.cie.scrollTop', function(e) {\n            var scrollTop = element.scrollTop();\n            if (scrollTop === 0) {\n                triggerEvent(events.scrollTop, e);\n            }\n        });\n    };\n\n    /**\n     * Trigger the scrollBottom event on the given element if the user scrolls to\n     * the bottom of the given element.\n     *\n     * @method addScrollBottomListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addScrollBottomListener = function(element) {\n        element.off('scroll.cie.scrollBottom').on('scroll.cie.scrollBottom', function(e) {\n            var scrollTop = element.scrollTop();\n            var innerHeight = element.innerHeight();\n            var scrollHeight = element[0].scrollHeight;\n\n            if (scrollTop + innerHeight >= scrollHeight) {\n                triggerEvent(events.scrollBottom, e);\n            }\n        });\n    };\n\n    /**\n     * Trigger the scrollLock event on the given element if the user scrolls to\n     * the bottom or top of the given element.\n     *\n     * @method addScrollLockListener\n     * @private\n     * @param {jQuery} element jQuery object to add event listeners to\n     */\n    var addScrollLockListener = function(element) {\n        // Lock mousewheel scrolling within the element to stop the annoying window scroll.\n        element.off('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock')\n            .on('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock', function(e) {\n                var scrollTop = element.scrollTop();\n                var scrollHeight = element[0].scrollHeight;\n                var height = element.height();\n                var delta = (e.type == 'DOMMouseScroll' ?\n                    e.originalEvent.detail * -40 :\n                    e.originalEvent.wheelDelta);\n                var up = delta > 0;\n\n                if (!up && -delta > scrollHeight - height - scrollTop) {\n                    // Scrolling down past the bottom.\n                    element.scrollTop(scrollHeight);\n                    e.stopPropagation();\n                    e.preventDefault();\n                    e.returnValue = false;\n                    // Fire the scroll lock event.\n                    triggerEvent(events.scrollLock, e);\n\n                    return false;\n                } else if (up && delta > scrollTop) {\n                    // Scrolling up past the top.\n                    element.scrollTop(0);\n                    e.stopPropagation();\n                    e.preventDefault();\n                    e.returnValue = false;\n                    // Fire the scroll lock event.\n                    triggerEvent(events.scrollLock, e);\n\n                    return false;\n                }\n\n                return true;\n            });\n    };\n\n    /**\n     * Trigger the ctrlPageUp event on the given element if the user presses the\n     * control and page up key.\n     *\n     * @method addCtrlPageUpListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addCtrlPageUpListener = function(element) {\n        element.off('keydown.cie.ctrlpageup').on('keydown.cie.ctrlpageup', function(e) {\n            if (e.ctrlKey) {\n                if (e.keyCode == keyCodes.pageUp) {\n                    triggerEvent(events.ctrlPageUp, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the ctrlPageDown event on the given element if the user presses the\n     * control and page down key.\n     *\n     * @method addCtrlPageDownListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addCtrlPageDownListener = function(element) {\n        element.off('keydown.cie.ctrlpagedown').on('keydown.cie.ctrlpagedown', function(e) {\n            if (e.ctrlKey) {\n                if (e.keyCode == keyCodes.pageDown) {\n                    triggerEvent(events.ctrlPageDown, e);\n                }\n            }\n        });\n    };\n\n    /**\n     * Trigger the enter event on the given element if the enter key is pressed\n     * without a modifier key.\n     *\n     * @method addEnterListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addEnterListener = function(element) {\n        addKeyboardEvent(element, events.enter, keyCodes.enter);\n    };\n\n    /**\n     * Trigger the AccessibleChange event on the given element if the value of the element is changed.\n     *\n     * @method addAccessibleChangeListener\n     * @private\n     * @param {object} element jQuery object to add event listeners to\n     */\n    var addAccessibleChangeListener = function(element) {\n        var onMac = navigator.userAgent.indexOf('Macintosh') !== -1;\n        var touchEnabled = ('ontouchstart' in window) || (('msMaxTouchPoints' in navigator) && (navigator.msMaxTouchPoints > 0));\n        if (onMac || touchEnabled) {\n            // On Mac devices, and touch-enabled devices, the change event seems to be handled correctly and\n            // consistently at this time.\n            element.on('change', function(e) {\n                triggerEvent(events.accessibleChange, e);\n            });\n        } else {\n            // Some browsers have non-normalised behaviour for handling the selection of values in a <select> element.\n            // When using Chrome on Linux (and possibly others), a 'change' event is fired when pressing the Escape key.\n            // When using Firefox on Linux (and possibly others), a 'change' event is fired when navigating through the\n            // list with a keyboard.\n            //\n            // To normalise these behaviours:\n            // - the initial value is stored in a data attribute when focusing the element\n            // - the current value is checked against the stored initial value when and the accessibleChange event fired when:\n            // --- blurring the element\n            // --- the 'Enter' key is pressed\n            // --- the element is clicked\n            // --- the 'change' event is fired, except where it is from a keyboard interaction\n            //\n            // To facilitate the change event keyboard interaction check, the 'keyDown' handler sets a flag to ignore\n            // the change event handler which is unset on the 'keyUp' event.\n            //\n            // Unfortunately we cannot control this entirely as some browsers (Chrome) trigger a change event when\n            // pressign the Escape key, and this is considered to be the correct behaviour.\n            // Chrome https://bugs.chromium.org/p/chromium/issues/detail?id=839717\n            //\n            // Our longer-term solution to this should be to switch away from using <select> boxes as a single-select,\n            // and make use of a dropdown of action links like the Bootstrap Dropdown menu.\n            var setInitialValue = function(target) {\n                target.dataset.initValue = target.value;\n            };\n            var resetToInitialValue = function(target) {\n                if ('initValue' in target.dataset) {\n                    target.value = target.dataset.initValue;\n                }\n            };\n            var checkAndTriggerAccessibleChange = function(e) {\n                if (!('initValue' in e.target.dataset)) {\n                    // Some browsers trigger click before focus, therefore it is possible that initValue is undefined.\n                    // In this case it's likely that it's being focused for the first time and we should therefore not submit.\n                    return;\n                }\n\n                if (e.target.value !== e.target.dataset.initValue) {\n                    // Update the initValue when the event is triggered.\n                    // This means that if the click handler fires before the focus handler on a subsequent interaction\n                    // with the element, the currently dispalyed value will be the best guess current value.\n                    e.target.dataset.initValue = e.target.value;\n                    triggerEvent(events.accessibleChange, e);\n                }\n            };\n            var nativeElement = element.get()[0];\n            // The `focus` and `blur` events do not support bubbling. Use Event Capture instead.\n            nativeElement.addEventListener('focus', function(e) {\n                setInitialValue(e.target);\n            }, true);\n            nativeElement.addEventListener('blur', function(e) {\n                checkAndTriggerAccessibleChange(e);\n            }, true);\n            element.on('keydown', function(e) {\n                if ((e.which === keyCodes.enter)) {\n                    checkAndTriggerAccessibleChange(e);\n                } else if (e.which === keyCodes.escape) {\n                    resetToInitialValue(e.target);\n                    e.target.dataset.ignoreChange = true;\n                } else {\n                    // Firefox triggers a change event when using the keyboard to scroll through the selection.\n                    // Set a data- attribute that the change listener can use to ignore the change event where it was\n                    // generated from a keyboard change such as typing to complete a value, or using arrow keys.\n                    e.target.dataset.ignoreChange = true;\n\n                }\n            });\n            element.on('change', function(e) {\n                if (e.target.dataset.ignoreChange) {\n                    // This change event was triggered from a keyboard change which is not yet complete.\n                    // Do not trigger the accessibleChange event until the selection is completed using the [return]\n                    // key.\n                    return;\n                }\n\n                checkAndTriggerAccessibleChange(e);\n            });\n            element.on('keyup', function(e) {\n                // The key has been lifted. Stop ignoring the change event.\n                delete e.target.dataset.ignoreChange;\n            });\n            element.on('click', function(e) {\n                checkAndTriggerAccessibleChange(e);\n            });\n        }\n    };\n\n    /**\n     * Get the list of events and their handlers.\n     *\n     * @method getHandlers\n     * @private\n     * @return {object} object key of event names and value of handler functions\n     */\n    var getHandlers = function() {\n        var handlers = {};\n\n        handlers[events.activate] = addActivateListener;\n        handlers[events.keyboardActivate] = addKeyboardActivateListener;\n        handlers[events.escape] = addEscapeListener;\n        handlers[events.down] = addDownListener;\n        handlers[events.up] = addUpListener;\n        handlers[events.home] = addHomeListener;\n        handlers[events.end] = addEndListener;\n        handlers[events.next] = addNextListener;\n        handlers[events.previous] = addPreviousListener;\n        handlers[events.asterix] = addAsterixListener;\n        handlers[events.scrollLock] = addScrollLockListener;\n        handlers[events.scrollTop] = addScrollTopListener;\n        handlers[events.scrollBottom] = addScrollBottomListener;\n        handlers[events.ctrlPageUp] = addCtrlPageUpListener;\n        handlers[events.ctrlPageDown] = addCtrlPageDownListener;\n        handlers[events.enter] = addEnterListener;\n        handlers[events.accessibleChange] = addAccessibleChangeListener;\n\n        return handlers;\n    };\n\n    /**\n     * Add all of the listeners on the given element for the requested events.\n     *\n     * @method define\n     * @public\n     * @param {object} element the DOM element to register event listeners on\n     * @param {array} include the array of events to be triggered\n     */\n    var define = function(element, include) {\n        element = $(element);\n        include = include || [];\n\n        if (!element.length || !include.length) {\n            return;\n        }\n\n        $.each(getHandlers(), function(eventType, handler) {\n            if (shouldAddEvent(eventType, include)) {\n                handler(element);\n            }\n        });\n    };\n\n    return /** @module core/custom_interaction_events */ {\n        define: define,\n        events: events,\n    };\n});\n"],"file":"custom_interaction_events.min.js"}
\ No newline at end of file
diff --git a/lib/amd/src/custom_interaction_events.js b/lib/amd/src/custom_interaction_events.js
index c429e926341..ca22b7275c2 100644
--- a/lib/amd/src/custom_interaction_events.js
+++ b/lib/amd/src/custom_interaction_events.js
@@ -427,35 +427,95 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) {
         var onMac = navigator.userAgent.indexOf('Macintosh') !== -1;
         var touchEnabled = ('ontouchstart' in window) || (('msMaxTouchPoints' in navigator) && (navigator.msMaxTouchPoints > 0));
         if (onMac || touchEnabled) {
+            // On Mac devices, and touch-enabled devices, the change event seems to be handled correctly and
+            // consistently at this time.
             element.on('change', function(e) {
                 triggerEvent(events.accessibleChange, e);
             });
         } else {
+            // Some browsers have non-normalised behaviour for handling the selection of values in a <select> element.
+            // When using Chrome on Linux (and possibly others), a 'change' event is fired when pressing the Escape key.
+            // When using Firefox on Linux (and possibly others), a 'change' event is fired when navigating through the
+            // list with a keyboard.
+            //
+            // To normalise these behaviours:
+            // - the initial value is stored in a data attribute when focusing the element
+            // - the current value is checked against the stored initial value when and the accessibleChange event fired when:
+            // --- blurring the element
+            // --- the 'Enter' key is pressed
+            // --- the element is clicked
+            // --- the 'change' event is fired, except where it is from a keyboard interaction
+            //
+            // To facilitate the change event keyboard interaction check, the 'keyDown' handler sets a flag to ignore
+            // the change event handler which is unset on the 'keyUp' event.
+            //
+            // Unfortunately we cannot control this entirely as some browsers (Chrome) trigger a change event when
+            // pressign the Escape key, and this is considered to be the correct behaviour.
+            // Chrome https://bugs.chromium.org/p/chromium/issues/detail?id=839717
+            //
+            // Our longer-term solution to this should be to switch away from using <select> boxes as a single-select,
+            // and make use of a dropdown of action links like the Bootstrap Dropdown menu.
+            var setInitialValue = function(target) {
+                target.dataset.initValue = target.value;
+            };
+            var resetToInitialValue = function(target) {
+                if ('initValue' in target.dataset) {
+                    target.value = target.dataset.initValue;
+                }
+            };
+            var checkAndTriggerAccessibleChange = function(e) {
+                if (!('initValue' in e.target.dataset)) {
+                    // Some browsers trigger click before focus, therefore it is possible that initValue is undefined.
+                    // In this case it's likely that it's being focused for the first time and we should therefore not submit.
+                    return;
+                }
+
+                if (e.target.value !== e.target.dataset.initValue) {
+                    // Update the initValue when the event is triggered.
+                    // This means that if the click handler fires before the focus handler on a subsequent interaction
+                    // with the element, the currently dispalyed value will be the best guess current value.
+                    e.target.dataset.initValue = e.target.value;
+                    triggerEvent(events.accessibleChange, e);
+                }
+            };
             var nativeElement = element.get()[0];
             // The `focus` and `blur` events do not support bubbling. Use Event Capture instead.
             nativeElement.addEventListener('focus', function(e) {
-                $(e.target).data('initValue', e.target.value);
+                setInitialValue(e.target);
             }, true);
             nativeElement.addEventListener('blur', function(e) {
-                var initValue = $(e.target).data('initValue');
-                $(e.target).removeData('initValue');
-                if (e.target.value !== initValue) {
-                    triggerEvent(events.accessibleChange, e);
-                }
+                checkAndTriggerAccessibleChange(e);
             }, true);
             element.on('keydown', function(e) {
-                if ((e.which === keyCodes.enter) && e.target.value !== $(e.target).data('initValue')) {
-                    triggerEvent(events.accessibleChange, e);
+                if ((e.which === keyCodes.enter)) {
+                    checkAndTriggerAccessibleChange(e);
                 } else if (e.which === keyCodes.escape) {
-                    e.target.value = $(e.target).data('initValue');
+                    resetToInitialValue(e.target);
+                    e.target.dataset.ignoreChange = true;
+                } else {
+                    // Firefox triggers a change event when using the keyboard to scroll through the selection.
+                    // Set a data- attribute that the change listener can use to ignore the change event where it was
+                    // generated from a keyboard change such as typing to complete a value, or using arrow keys.
+                    e.target.dataset.ignoreChange = true;
+
                 }
             });
-            element.on('click', function(e) {
-                var initValue = $(e.target).data('initValue');
-                // Some browsers trigger onclick before onblur, therefore it is possible that initValue is undefined.
-                if (typeof initValue !== 'undefined' && initValue != e.target.value) {
-                    triggerEvent(events.accessibleChange, e);
+            element.on('change', function(e) {
+                if (e.target.dataset.ignoreChange) {
+                    // This change event was triggered from a keyboard change which is not yet complete.
+                    // Do not trigger the accessibleChange event until the selection is completed using the [return]
+                    // key.
+                    return;
                 }
+
+                checkAndTriggerAccessibleChange(e);
+            });
+            element.on('keyup', function(e) {
+                // The key has been lifted. Stop ignoring the change event.
+                delete e.target.dataset.ignoreChange;
+            });
+            element.on('click', function(e) {
+                checkAndTriggerAccessibleChange(e);
             });
         }
     };

From 5d16bfcf7cb87476564176060ad8ccbaef2adbdd Mon Sep 17 00:00:00 2001
From: Andrew Nicols <andrew@nicols.co.uk>
Date: Mon, 2 Nov 2020 15:42:13 +0800
Subject: [PATCH 3/5] MDL-70075 core: jQuery.attr() does not accept a bool
 value

The documented values that jQuery.attr() accepts are String, Number, or
null. For some reason, when we pass a Boolean value, the subsequent
click handler does not work in some situations.

Changing this to take a Number, and unsetting it when empty, resolves
this issue.
---
 lib/amd/build/form-autocomplete.min.js     |  2 +-
 lib/amd/build/form-autocomplete.min.js.map |  2 +-
 lib/amd/src/form-autocomplete.js           | 12 +++++++-----
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/lib/amd/build/form-autocomplete.min.js b/lib/amd/build/form-autocomplete.min.js
index ce28280ce1d..fa95f55fc1f 100644
--- a/lib/amd/build/form-autocomplete.min.js
+++ b/lib/amd/build/form-autocomplete.min.js
@@ -1,2 +1,2 @@
-define ("core/form-autocomplete",["jquery","core/log","core/str","core/templates","core/notification","core/loadingicon","core/aria"],function(a,b,c,d,f,g,h){var i={DOWN:40,ENTER:13,SPACE:32,ESCAPE:27,COMMA:44,UP:38,LEFT:37,RIGHT:39},j=Date.now(),k=function(b,c){var d=a(document.getElementById(c.selectionId)),e=d.children("[aria-selected=true]").length;b=b%e;while(0>b){b+=e}var f=a(d.children("[aria-selected=true]").get(b)),g=c.selectionId+"-"+b;d.children().attr("data-active-selection",!1).attr("id","");f.attr("data-active-selection",!0).attr("id",g);d.attr("aria-activedescendant",g);return a.Deferred().resolve()},l=function(b,c,e){var g="form-autocomplete-updateSelectionList-"+c.inputId;M.util.js_pending(g);var h=[],i=a(document.getElementById(c.selectionId)),j=i.attr("aria-activedescendant"),l=!1;if(j){l=a(document.getElementById(j)).attr("data-value")}e.children("option").each(function(b,c){if(a(c).prop("selected")){var d;if(a(c).data("html")){d=a(c).data("html")}else{d=a(c).html()}if(""!==d){h.push({label:d,value:a(c).attr("value")})}}});var m=a.extend({items:h},b,c);return d.render(b.templates.items,m).then(function(b,e){d.replaceNodeContents(i,b,e);if(!1!==l){i.children("[aria-selected=true]").each(function(b,d){if(a(d).attr("data-value")===l){k(b,c)}})}return l}).then(function(){return M.util.js_complete(g)}).catch(f.exception)},m=function(a){if("undefined"!=typeof M.core_formchangechecker){M.core_formchangechecker.set_form_changed()}a[0].dispatchEvent(new Event("change"))},n=function(b,c,d,e){var f=a(d).attr("data-value");e.children("option").each(function(b,c){if(a(c).attr("value")==f){a(c).prop("selected",!1);if(a(c).attr("data-iscustom")){a(c).remove()}}});return l(b,c,e).then(function(){m(e)})},o=function(b,c){var d=a(document.getElementById(c.inputId)),e=a(document.getElementById(c.suggestionsId)),f=e.children(":not([aria-hidden])").length;b=b%f;while(0>b){b+=f}var g=a(e.children(":not([aria-hidden])").get(b)),h=a(e.children("[role=option]")).index(g),i=c.suggestionsId+"-"+h;e.children().attr("aria-selected",!1).attr("id","");g.attr("aria-selected",!0).attr("id",i);d.attr("aria-activedescendant",i);var j=g.offset().top-e.offset().top+e.scrollTop()-e.height()/2;return e.animate({scrollTop:j},100).promise()},p=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return o(e+1,b)},q=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection=true]");if(!d){return k(0,b)}var e=c.children("[aria-selected=true]").index(d);return k(e-1,b)},r=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection=true]"),e=0;if(d){e=c.children("[aria-selected=true]").index(d);e=e+1}else{e=0}return k(e,b)},s=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return o(e-1,b)},t=function(b){var c=a(document.getElementById(b.inputId)),d=a(document.getElementById(b.suggestionsId));if("true"===c.attr("aria-expanded")){c.attr("aria-expanded",!1)}c.attr("aria-activedescendant",b.selectionId);h.hide(d.get());d.hide();return a.Deferred().resolve()},u=function(b,e,g,i){var j="form-autocomplete-updateSuggestions-"+e.inputId;M.util.js_pending(j);var k=a(document.getElementById(e.inputId)),l=a(document.getElementById(e.suggestionsId)),m=!1,n=[];i.children("option").each(function(b,c){if(!0!==a(c).prop("selected")){n[n.length]={label:c.innerHTML,value:a(c).attr("value")}}});var p=e.caseSensitive?g:g.toLocaleLowerCase(),q=a.extend({options:n},b,e),r=d.render("core/form_autocomplete_suggestions",q).then(function(f,g){d.replaceNode(l,f,g);l=a(document.getElementById(e.suggestionsId));h.unhide(l.get());l.show();l.children().each(function(c,d){d=a(d);if(b.caseSensitive&&-1<d.text().indexOf(p)||!b.caseSensitive&&-1<d.text().toLocaleLowerCase().indexOf(p)){h.unhide(d.get());d.show();m=!0}else{d.hide();h.hide(d.get())}});k.attr("aria-expanded",!0);if(i.attr("data-notice")){l.html(i.attr("data-notice"))}else if(m){if(!b.tags){o(0,e)}}else{c.get_string("nosuggestions","form").done(function(a){l.html(a)})}return l}).then(function(){return M.util.js_complete(j)}).catch(f.exception);return r},v=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=e.val(),g=f.split(","),h=!1;a.each(g,function(c,e){e=e.trim();if(""!==e){if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==e){h=!0;a(c).prop("selected",!0)}});if(!h){var f=a("<option>");f.append(document.createTextNode(e));f.attr("value",e);d.append(f);f.prop("selected",!0);f.attr("data-iscustom",!0)}}});return l(b,c,d).then(function(){m(d)}).then(function(){e.val("")}).then(function(){return t(c)})},w=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=a(document.getElementById(c.suggestionsId)),g=f.children("[aria-selected=true]").attr("data-value");if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==g){a(c).prop("selected",!0)}});return l(b,c,d).then(function(){m(d)}).then(function(){if(b.closeSuggestionsOnSelect){e.val("");return t(c)}else{e.focus();return u(b,c,e.val(),d)}})},x=function(b,c,d,e,f){var h=z("updateAjax"),i=a(document.getElementById(d.selectId)).parent();g.addIconToContainerRemoveOnCompletion(i,h);var j=a(b.currentTarget).val();f.transport(c.selector,j,function(b){var g=f.processResults(c.selector,b),i=[];if(!c.multiple){e.children("option").remove()}e.children("option").each(function(b,c){c=a(c);if(!c.prop("selected")){c.remove()}else{i.push(c.attr("value")+"")}});if(!c.multiple&&0===e.children("option").length){var j=a("<option>");e.append(j)}if(a.isArray(g)){a.each(g,function(b,c){if(-1===i.indexOf(c.value+"")){var d=a("<option>");d.append(c.label);d.attr("value",c.value);e.append(d)}});e.attr("data-notice","")}else{e.attr("data-notice",g)}h.resolve(u(c,d,"",e))},function(a){h.reject(a)});return h},y=function(b,c,d){var g=a(document.getElementById(c.inputId));g.on("keydown",function(f){var e=z("addNavigation-"+c.inputId+"-"+f.keyCode);switch(f.keyCode){case i.DOWN:if(!b.showSuggestions){e.resolve();return!0}else if("true"===g.attr("aria-expanded")){e.resolve(p(c))}else{if(!g.val()&&b.ajax){require([b.ajax],function(a){e.resolve(x(f,b,c,d,a))})}else{e.resolve(u(b,c,g.val(),d))}}f.preventDefault();return!1;case i.UP:e.resolve(s(c));f.preventDefault();return!1;case i.ENTER:var h=a(document.getElementById(c.suggestionsId));if("true"===g.attr("aria-expanded")&&0<h.children("[aria-selected=true]").length){e.resolve(w(b,c,d))}else if(b.tags){e.resolve(v(b,c,d))}else{e.resolve()}f.preventDefault();return!1;case i.ESCAPE:if("true"===g.attr("aria-expanded")){e.resolve(t(c))}else{e.resolve()}f.preventDefault();return!1;}e.resolve();return!0});g.on("keypress",function(a){if(a.keyCode===i.COMMA){if(b.tags){z("keypress-"+a.keyCode).resolve(v(b,c,d))}a.preventDefault();return!1}return!0});g.closest("form").on("submit",function(){if(b.tags){z("form-autocomplete-submit").resolve(v(b,c,d))}return!0});g.on("blur",function(){var e=z("form-autocomplete-blur");window.setTimeout(function(){var f=a(document.activeElement),h=a.Deferred();if(f.is(document.getElementById(c.suggestionsId))){g.focus()}else if(!f.is(g)&&a(document.getElementById(c.inputId)).length){if(b.tags){h.then(function(){return v(b,c,d)}).catch()}h.then(function(){return t(c)}).catch()}h.then(function(){return e.resolve()}).catch();h.resolve()},500)});if(b.showSuggestions){var h=a(document.getElementById(c.downArrowId));h.on("click",function(a){var e=z("form-autocomplete-show-suggestions");g.focus();if(!g.val()&&b.ajax){require([b.ajax],function(f){e.resolve(x(a,b,c,d,f))})}else{e.resolve(u(b,c,g.val(),d))}})}var j=a(document.getElementById(c.suggestionsId));j.parent().prop("onclick",null).off("click");j.parent().on("click","#".concat(c.suggestionsId," [role=option]"),function(f){var e=z("form-autocomplete-parent"),g=a(f.currentTarget).closest("[role=option]"),h=a(document.getElementById(c.suggestionsId)),i=h.children(":not([aria-hidden])").index(g);o(i,c).then(function(){return w(b,c,d)}).then(function(){return e.resolve()}).catch()});var l=a(document.getElementById(c.selectionId));l.on("click","[role=option]",function(f){var e=z("form-autocomplete-clicks");e.resolve(n(b,c,a(f.currentTarget),d))});l.on("focus",function(){var b=a(document.getElementById(c.selectionId)),d=b.children("[data-active-selection=true]");if(!d.length){return k(0,c)}});l.on("keydown",function(f){var e=z("form-autocomplete-keydown-"+f.keyCode);switch(f.keyCode){case i.RIGHT:case i.DOWN:f.preventDefault();e.resolve(r(c));return!1;case i.LEFT:case i.UP:f.preventDefault();e.resolve(q(c));return!1;case i.SPACE:case i.ENTER:var g=a(document.getElementById(c.selectionId)).children("[data-active-selection=true]");if(g){f.preventDefault();e.resolve(n(b,c,g,d))}return!1;}e.resolve();return!0});if(b.showSuggestions){g.on("focus",function(b){var c=a(b.currentTarget).val();a(b.currentTarget).data("last-value",c)});if(b.ajax){require([b.ajax],function(h){var i=null,j=!1,k="autocomplete-throttledhandler",l=function(a){i=null;j=!0;x(a,b,c,d,h).then(function(){if(null===i){M.util.js_complete(k)}j=!1;return arguments[0]}).catch(f.exception)},m=function(a){window.clearTimeout(i);if(j){i=window.setTimeout(m.bind(this,a),100);return}if(null===i){M.util.js_pending(k)}i=window.setTimeout(l.bind(this,a),300)};g.on("input",function(b){var c=a(b.currentTarget).val(),d=a(b.currentTarget).data("last-value");if(d!==c){m(b)}a(b.currentTarget).data("last-value",c)})})}else{g.on("input",function(f){var e=a(f.currentTarget).val(),g=a(f.currentTarget).data("last-value");if(g!==e){u(b,c,e,d)}a(f.currentTarget).data("last-value",e)})}}},z=function(b){var c="form-autocomplete:"+b;M.util.js_pending(c);var d=a.Deferred();d.then(function(){M.util.js_complete(c);return arguments[0]}).catch(f.exception);return d};return{enhance:function enhance(e,g,i,k,m,n,o,p,q){var r={selector:e,tags:!1,ajax:!1,placeholder:k,caseSensitive:!1,showSuggestions:!0,noSelectionString:o,templates:a.extend({input:"core/form_autocomplete_input",items:"core/form_autocomplete_selection_items",layout:"core/form_autocomplete_layout",selection:"core/form_autocomplete_selection",suggestions:"core/form_autocomplete_suggestions"},q)},s="autocomplete-setup-"+e;M.util.js_pending(s);if("undefined"!=typeof g){r.tags=g}if("undefined"!=typeof i){r.ajax=i}if("undefined"!=typeof m){r.caseSensitive=m}if("undefined"!=typeof n){r.showSuggestions=n}if("undefined"==typeof o){c.get_string("noselection","form").done(function(a){r.noSelectionString=a}).fail(f.exception)}var t=a(e);if(!t){b.debug("Selector not found: "+e);M.util.js_complete(s);return!1}h.hide(t.get());t.css("visibility","hidden");var u={selectId:t.attr("id"),inputId:"form_autocomplete_input-"+j,suggestionsId:"form_autocomplete_suggestions-"+j,selectionId:"form_autocomplete_selection-"+j,downArrowId:"form_autocomplete_downarrow-"+j};j++;r.multiple=t.attr("multiple");if(!r.multiple){t.prepend("<option>")}if("undefined"!=typeof p){r.closeSuggestionsOnSelect=p}else{r.closeSuggestionsOnSelect=!r.multiple}var v=a("[for="+u.selectId+"]"),w=[];t.children("option").each(function(b,c){w[b]={label:c.innerHTML,value:a(c).attr("value")}});var x=a.extend({},r,u);x.options=w;x.items=[];var z="",A=d.render(r.templates.layout,{}).then(function(b){return a(b)}),B=d.render(r.templates.input,x).then(function(b,c){z+=c;return a(b)}),C=d.render(r.templates.suggestions,x).then(function(b,c){z+=c;return a(b)}),D=d.render(r.templates.selection,x).then(function(b,c){z+=c;return a(b)});return a.when(A,B,C,D).then(function(b,c,e,f){t.hide();var g=t.parent();g.append(b);g.find("[data-region=\"form_autocomplete-input\"]").replaceWith(c);g.find("[data-region=\"form_autocomplete-suggestions\"]").replaceWith(e);g.find("[data-region=\"form_autocomplete-selection\"]").replaceWith(f);d.runTemplateJS(z);v.attr("for",u.inputId);y(r,u,t);var i=a(document.getElementById(u.suggestionsId));i.hide();h.hide(i.get())}).then(function(){return l(r,u,t)}).then(function(){return M.util.js_complete(s)}).catch(function(a){M.util.js_complete(s);f.exception(a)})}}});
+define ("core/form-autocomplete",["jquery","core/log","core/str","core/templates","core/notification","core/loadingicon","core/aria"],function(a,b,c,d,f,g,h){var i={DOWN:40,ENTER:13,SPACE:32,ESCAPE:27,COMMA:44,UP:38,LEFT:37,RIGHT:39},j=Date.now(),k=function(b,c){var d=a(document.getElementById(c.selectionId)),e=d.children("[aria-selected=true]").length;b=b%e;while(0>b){b+=e}var f=a(d.children("[aria-selected=true]").get(b)),g=c.selectionId+"-"+b;d.children().attr("data-active-selection",null).attr("id","");f.attr("data-active-selection",!0).attr("id",g);d.attr("aria-activedescendant",g);return a.Deferred().resolve()},l=function(b,c,e){var g="form-autocomplete-updateSelectionList-"+c.inputId;M.util.js_pending(g);var h=[],i=a(document.getElementById(c.selectionId)),j=i.attr("aria-activedescendant"),l=!1;if(j){l=a(document.getElementById(j)).attr("data-value")}e.children("option").each(function(b,c){if(a(c).prop("selected")){var d;if(a(c).data("html")){d=a(c).data("html")}else{d=a(c).html()}if(""!==d){h.push({label:d,value:a(c).attr("value")})}}});var m=a.extend({items:h},b,c);return d.render(b.templates.items,m).then(function(b,e){d.replaceNodeContents(i,b,e);if(!1!==l){i.children("[aria-selected=true]").each(function(b,d){if(a(d).attr("data-value")===l){k(b,c)}})}return l}).then(function(){return M.util.js_complete(g)}).catch(f.exception)},m=function(a){if("undefined"!=typeof M.core_formchangechecker){M.core_formchangechecker.set_form_changed()}a[0].dispatchEvent(new Event("change"))},n=function(b,c,d,e){var f=a(d).attr("data-value");e.children("option").each(function(b,c){if(a(c).attr("value")==f){a(c).prop("selected",!1);if(a(c).attr("data-iscustom")){a(c).remove()}}});return l(b,c,e).then(function(){m(e)})},o=function(b,c){var d=a(document.getElementById(c.inputId)),e=a(document.getElementById(c.suggestionsId)),f=e.children(":not([aria-hidden])").length;b=b%f;while(0>b){b+=f}var g=a(e.children(":not([aria-hidden])").get(b)),h=a(e.children("[role=option]")).index(g),i=c.suggestionsId+"-"+h;e.children().attr("aria-selected",!1).attr("id","");g.attr("aria-selected",!0).attr("id",i);d.attr("aria-activedescendant",i);var j=g.offset().top-e.offset().top+e.scrollTop()-e.height()/2;return e.animate({scrollTop:j},100).promise()},p=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return o(e+1,b)},q=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]");if(!d){return k(0,b)}var e=c.children("[aria-selected=true]").index(d);return k(e-1,b)},r=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]"),e=0;if(d){e=c.children("[aria-selected=true]").index(d);e=e+1}else{e=0}return k(e,b)},s=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return o(e-1,b)},t=function(b){var c=a(document.getElementById(b.inputId)),d=a(document.getElementById(b.suggestionsId));if("true"===c.attr("aria-expanded")){c.attr("aria-expanded",!1)}c.attr("aria-activedescendant",b.selectionId);h.hide(d.get());d.hide();return a.Deferred().resolve()},u=function(b,e,g,i){var j="form-autocomplete-updateSuggestions-"+e.inputId;M.util.js_pending(j);var k=a(document.getElementById(e.inputId)),l=a(document.getElementById(e.suggestionsId)),m=!1,n=[];i.children("option").each(function(b,c){if(!0!==a(c).prop("selected")){n[n.length]={label:c.innerHTML,value:a(c).attr("value")}}});var p=e.caseSensitive?g:g.toLocaleLowerCase(),q=a.extend({options:n},b,e),r=d.render("core/form_autocomplete_suggestions",q).then(function(f,g){d.replaceNode(l,f,g);l=a(document.getElementById(e.suggestionsId));h.unhide(l.get());l.show();l.children().each(function(c,d){d=a(d);if(b.caseSensitive&&-1<d.text().indexOf(p)||!b.caseSensitive&&-1<d.text().toLocaleLowerCase().indexOf(p)){h.unhide(d.get());d.show();m=!0}else{d.hide();h.hide(d.get())}});k.attr("aria-expanded",!0);if(i.attr("data-notice")){l.html(i.attr("data-notice"))}else if(m){if(!b.tags){o(0,e)}}else{c.get_string("nosuggestions","form").done(function(a){l.html(a)})}return l}).then(function(){return M.util.js_complete(j)}).catch(f.exception);return r},v=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=e.val(),g=f.split(","),h=!1;a.each(g,function(c,e){e=e.trim();if(""!==e){if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==e){h=!0;a(c).prop("selected",!0)}});if(!h){var f=a("<option>");f.append(document.createTextNode(e));f.attr("value",e);d.append(f);f.prop("selected",!0);f.attr("data-iscustom",!0)}}});return l(b,c,d).then(function(){m(d)}).then(function(){e.val("")}).then(function(){return t(c)})},w=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=a(document.getElementById(c.suggestionsId)),g=f.children("[aria-selected=true]").attr("data-value");if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==g){a(c).prop("selected",!0)}});return l(b,c,d).then(function(){m(d)}).then(function(){if(b.closeSuggestionsOnSelect){e.val("");return t(c)}else{e.focus();return u(b,c,e.val(),d)}})},x=function(b,c,d,e,f){var h=z("updateAjax"),i=a(document.getElementById(d.selectId)).parent();g.addIconToContainerRemoveOnCompletion(i,h);var j=a(b.currentTarget).val();f.transport(c.selector,j,function(b){var g=f.processResults(c.selector,b),i=[];if(!c.multiple){e.children("option").remove()}e.children("option").each(function(b,c){c=a(c);if(!c.prop("selected")){c.remove()}else{i.push(c.attr("value")+"")}});if(!c.multiple&&0===e.children("option").length){var j=a("<option>");e.append(j)}if(a.isArray(g)){a.each(g,function(b,c){if(-1===i.indexOf(c.value+"")){var d=a("<option>");d.append(c.label);d.attr("value",c.value);e.append(d)}});e.attr("data-notice","")}else{e.attr("data-notice",g)}h.resolve(u(c,d,"",e))},function(a){h.reject(a)});return h},y=function(b,c,d){var g=a(document.getElementById(c.inputId));g.on("keydown",function(f){var e=z("addNavigation-"+c.inputId+"-"+f.keyCode);switch(f.keyCode){case i.DOWN:if(!b.showSuggestions){e.resolve();return!0}else if("true"===g.attr("aria-expanded")){e.resolve(p(c))}else{if(!g.val()&&b.ajax){require([b.ajax],function(a){e.resolve(x(f,b,c,d,a))})}else{e.resolve(u(b,c,g.val(),d))}}f.preventDefault();return!1;case i.UP:e.resolve(s(c));f.preventDefault();return!1;case i.ENTER:var h=a(document.getElementById(c.suggestionsId));if("true"===g.attr("aria-expanded")&&0<h.children("[aria-selected=true]").length){e.resolve(w(b,c,d))}else if(b.tags){e.resolve(v(b,c,d))}else{e.resolve()}f.preventDefault();return!1;case i.ESCAPE:if("true"===g.attr("aria-expanded")){e.resolve(t(c))}else{e.resolve()}f.preventDefault();return!1;}e.resolve();return!0});g.on("keypress",function(a){if(a.keyCode===i.COMMA){if(b.tags){z("keypress-"+a.keyCode).resolve(v(b,c,d))}a.preventDefault();return!1}return!0});g.closest("form").on("submit",function(){if(b.tags){z("form-autocomplete-submit").resolve(v(b,c,d))}return!0});g.on("blur",function(){var e=z("form-autocomplete-blur");window.setTimeout(function(){var f=a(document.activeElement),h=a.Deferred();if(f.is(document.getElementById(c.suggestionsId))){g.focus()}else if(!f.is(g)&&a(document.getElementById(c.inputId)).length){if(b.tags){h.then(function(){return v(b,c,d)}).catch()}h.then(function(){return t(c)}).catch()}h.then(function(){return e.resolve()}).catch();h.resolve()},500)});if(b.showSuggestions){var h=a(document.getElementById(c.downArrowId));h.on("click",function(a){var e=z("form-autocomplete-show-suggestions");g.focus();if(!g.val()&&b.ajax){require([b.ajax],function(f){e.resolve(x(a,b,c,d,f))})}else{e.resolve(u(b,c,g.val(),d))}})}var j=a(document.getElementById(c.suggestionsId));j.parent().prop("onclick",null).off("click");j.parent().on("click","#".concat(c.suggestionsId," [role=option]"),function(f){var e=z("form-autocomplete-parent"),g=a(f.currentTarget).closest("[role=option]"),h=a(document.getElementById(c.suggestionsId)),i=h.children(":not([aria-hidden])").index(g);o(i,c).then(function(){return w(b,c,d)}).then(function(){return e.resolve()}).catch()});var l=a(document.getElementById(c.selectionId));l.on("click","[role=option]",function(f){var e=z("form-autocomplete-clicks");e.resolve(n(b,c,a(f.currentTarget),d))});l.on("focus",function(){var b=a(document.getElementById(c.selectionId)),d=b.children("[data-active-selection]");if(!d.length){return k(0,c)}});l.on("keydown",function(f){var e=z("form-autocomplete-keydown-"+f.keyCode);switch(f.keyCode){case i.RIGHT:case i.DOWN:f.preventDefault();e.resolve(r(c));return!1;case i.LEFT:case i.UP:f.preventDefault();e.resolve(q(c));return!1;case i.SPACE:case i.ENTER:var g=a(document.getElementById(c.selectionId)).children("[data-active-selection]");if(g){f.preventDefault();e.resolve(n(b,c,g,d))}return!1;}e.resolve();return!0});if(b.showSuggestions){g.on("focus",function(b){var c=a(b.currentTarget).val();a(b.currentTarget).data("last-value",c)});if(b.ajax){require([b.ajax],function(h){var i=null,j=!1,k="autocomplete-throttledhandler",l=function(a){i=null;j=!0;x(a,b,c,d,h).then(function(){if(null===i){M.util.js_complete(k)}j=!1;return arguments[0]}).catch(f.exception)},m=function(a){window.clearTimeout(i);if(j){i=window.setTimeout(m.bind(this,a),100);return}if(null===i){M.util.js_pending(k)}i=window.setTimeout(l.bind(this,a),300)};g.on("input",function(b){var c=a(b.currentTarget).val(),d=a(b.currentTarget).data("last-value");if(d!==c){m(b)}a(b.currentTarget).data("last-value",c)})})}else{g.on("input",function(f){var e=a(f.currentTarget).val(),g=a(f.currentTarget).data("last-value");if(g!==e){u(b,c,e,d)}a(f.currentTarget).data("last-value",e)})}}},z=function(b){var c="form-autocomplete:"+b;M.util.js_pending(c);var d=a.Deferred();d.then(function(){M.util.js_complete(c);return arguments[0]}).catch(f.exception);return d};return{enhance:function enhance(e,g,i,k,m,n,o,p,q){var r={selector:e,tags:!1,ajax:!1,placeholder:k,caseSensitive:!1,showSuggestions:!0,noSelectionString:o,templates:a.extend({input:"core/form_autocomplete_input",items:"core/form_autocomplete_selection_items",layout:"core/form_autocomplete_layout",selection:"core/form_autocomplete_selection",suggestions:"core/form_autocomplete_suggestions"},q)},s="autocomplete-setup-"+e;M.util.js_pending(s);if("undefined"!=typeof g){r.tags=g}if("undefined"!=typeof i){r.ajax=i}if("undefined"!=typeof m){r.caseSensitive=m}if("undefined"!=typeof n){r.showSuggestions=n}if("undefined"==typeof o){c.get_string("noselection","form").done(function(a){r.noSelectionString=a}).fail(f.exception)}var t=a(e);if(!t){b.debug("Selector not found: "+e);M.util.js_complete(s);return!1}h.hide(t.get());t.css("visibility","hidden");var u={selectId:t.attr("id"),inputId:"form_autocomplete_input-"+j,suggestionsId:"form_autocomplete_suggestions-"+j,selectionId:"form_autocomplete_selection-"+j,downArrowId:"form_autocomplete_downarrow-"+j};j++;r.multiple=t.attr("multiple");if(!r.multiple){t.prepend("<option>")}if("undefined"!=typeof p){r.closeSuggestionsOnSelect=p}else{r.closeSuggestionsOnSelect=!r.multiple}var v=a("[for="+u.selectId+"]"),w=[];t.children("option").each(function(b,c){w[b]={label:c.innerHTML,value:a(c).attr("value")}});var x=a.extend({},r,u);x.options=w;x.items=[];var z="",A=d.render(r.templates.layout,{}).then(function(b){return a(b)}),B=d.render(r.templates.input,x).then(function(b,c){z+=c;return a(b)}),C=d.render(r.templates.suggestions,x).then(function(b,c){z+=c;return a(b)}),D=d.render(r.templates.selection,x).then(function(b,c){z+=c;return a(b)});return a.when(A,B,C,D).then(function(b,c,e,f){t.hide();var g=t.parent();g.append(b);g.find("[data-region=\"form_autocomplete-input\"]").replaceWith(c);g.find("[data-region=\"form_autocomplete-suggestions\"]").replaceWith(e);g.find("[data-region=\"form_autocomplete-selection\"]").replaceWith(f);d.runTemplateJS(z);v.attr("for",u.inputId);y(r,u,t);var i=a(document.getElementById(u.suggestionsId));i.hide();h.hide(i.get())}).then(function(){return l(r,u,t)}).then(function(){return M.util.js_complete(s)}).catch(function(a){M.util.js_complete(s);f.exception(a)})}}});
 //# sourceMappingURL=form-autocomplete.min.js.map
diff --git a/lib/amd/build/form-autocomplete.min.js.map b/lib/amd/build/form-autocomplete.min.js.map
index 09d885c9fd3..db1748537db 100644
--- a/lib/amd/build/form-autocomplete.min.js.map
+++ b/lib/amd/build/form-autocomplete.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/form-autocomplete.js"],"names":["define","$","log","str","templates","notification","LoadingIcon","Aria","KEYS","DOWN","ENTER","SPACE","ESCAPE","COMMA","UP","LEFT","RIGHT","uniqueId","Date","now","activateSelection","index","state","selectionElement","document","getElementById","selectionId","length","children","element","get","itemId","attr","Deferred","resolve","updateSelectionList","options","originalSelect","pendingKey","inputId","M","util","js_pending","items","newSelection","activeId","activeValue","each","ele","prop","label","data","html","push","value","context","extend","render","then","js","replaceNodeContents","js_complete","catch","exception","notifyChange","core_formchangechecker","set_form_changed","dispatchEvent","Event","deselectItem","item","selectedItemValue","remove","activateItem","inputElement","suggestionsElement","suggestionsId","globalIndex","scrollPos","offset","top","scrollTop","height","animate","promise","activateNextItem","current","activatePreviousSelection","selectionsElement","activateNextSelection","activatePreviousItem","closeSuggestions","hide","updateSuggestions","query","matchingElements","suggestions","option","innerHTML","searchquery","caseSensitive","toLocaleLowerCase","returnVal","replaceNode","unhide","show","node","text","indexOf","tags","get_string","done","nosuggestionsstr","createItem","val","split","found","tagindex","tag","trim","multiple","append","createTextNode","selectCurrentItem","closeSuggestionsOnSelect","focus","updateAjax","e","ajaxHandler","pendingPromise","addPendingJSPromise","parentElement","selectId","parent","addIconToContainerRemoveOnCompletion","currentTarget","transport","selector","results","processedResults","processResults","existingValues","optionIndex","isArray","resultIndex","result","error","reject","addNavigation","on","pendingJsPromise","keyCode","showSuggestions","ajax","require","preventDefault","closest","window","setTimeout","focusElement","activeElement","timeoutPromise","is","arrowElement","downArrowId","off","selectedItem","throttleTimeout","inProgress","handler","arguments","throttledHandler","clearTimeout","bind","last","key","enhance","placeholder","noSelectionString","templateOverrides","input","layout","selection","fail","debug","css","prepend","originalLabel","collectedjs","renderLayout","renderInput","renderDatalist","renderSelection","when","container","find","replaceWith","runTemplateJS"],"mappings":"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","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Autocomplete wrapper for select2 library.\n *\n * @module     core/form-autocomplete\n * @class      autocomplete\n * @package    core\n * @copyright  2015 Damyon Wiese <damyon@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.0\n */\n/* globals require: false */\ndefine(\n    ['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification', 'core/loadingicon', 'core/aria'],\nfunction($, log, str, templates, notification, LoadingIcon, Aria) {\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        // Count the visible items.\n        var length = selectionElement.children('[aria-selected=true]').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 = $(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', false).attr('id', '');\n        // Select only this suggestion and assign it the id.\n        element.attr('data-active-selection', true).attr('id', itemId);\n        // Tell the input field it has a new active descendant so the item is announced.\n        selectionElement.attr('aria-activedescendant', itemId);\n\n        return $.Deferred().resolve();\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 = [];\n        var newSelection = $(document.getElementById(state.selectionId));\n        var activeId = newSelection.attr('aria-activedescendant');\n        var activeValue = false;\n\n        if (activeId) {\n            activeValue = $(document.getElementById(activeId)).attr('data-value');\n        }\n        originalSelect.children('option').each(function(index, ele) {\n            if ($(ele).prop('selected')) {\n                var label;\n                if ($(ele).data('html')) {\n                    label = $(ele).data('html');\n                } else {\n                    label = $(ele).html();\n                }\n                if (label !== '') {\n                    items.push({label: label, value: $(ele).attr('value')});\n                }\n            }\n        });\n        var context = $.extend({items: items}, 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            if (activeValue !== false) {\n                // Reselect any previously selected item.\n                newSelection.children('[aria-selected=true]').each(function(index, ele) {\n                    if ($(ele).attr('data-value') === activeValue) {\n                        activateSelection(index, state);\n                    }\n                });\n            }\n\n            return activeValue;\n        })\n        .then(function() {\n            return M.util.js_complete(pendingKey);\n        })\n        .catch(notification.exception);\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        if (typeof M.core_formchangechecker !== 'undefined') {\n            M.core_formchangechecker.set_form_changed();\n        }\n\n        // Note, jQuery .change() was not working here. Better to\n        // use plain JavaScript anyway.\n        originalSelect[0].dispatchEvent(new Event('change'));\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    var deselectItem = function(options, state, item, originalSelect) {\n        var selectedItemValue = $(item).attr('data-value');\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        // Rerender the selection list.\n        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        });\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     * 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        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n        // Activate the next one.\n        return activateItem(current + 1, 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=true]');\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=true]');\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        // Find the list of suggestions.\n        var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n        // Activate the previous one.\n        return activateItem(current - 1, 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 = [];\n        originalSelect.children('option').each(function(index, option) {\n            if ($(option).prop('selected') !== true) {\n                suggestions[suggestions.length] = {label: option.innerHTML, value: $(option).attr('value')};\n            }\n        });\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            suggestionsElement.show();\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    var createItem = function(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 = $('<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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            // Clear the input field.\n            inputElement.val('');\n\n            return;\n        })\n        .then(function() {\n            // Close the suggestions list.\n            return closeSuggestions(state);\n        });\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     * @return {Promise}\n     */\n    var selectCurrentItem = function(options, state, originalSelect) {\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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            if (options.closeSuggestionsOnSelect) {\n                // Clear the input element.\n                inputElement.val('');\n                // Close the list of suggestions.\n                return 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                return updateSuggestions(options, state, inputElement.val(), originalSelect);\n            }\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 currently selected.\n            if (!options.multiple) {\n                originalSelect.children('option').remove();\n            }\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 = $('<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 = $('<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                        // If the suggestion list has an active item, select it.\n                        pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect));\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                return selectCurrentItem(options, state, originalSelect);\n            })\n            .then(function() {\n                return pendingPromise.resolve();\n            })\n            .catch();\n        });\n        var selectionElement = $(document.getElementById(state.selectionId));\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        // When listbox is focused, focus on the first option if there is no focused option.\n        selectionElement.on('focus', function() {\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=true]');\n            if (!element.length) {\n                return activateSelection(0, 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 false;\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 false;\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=true]');\n                    if (selectedItem) {\n                        e.preventDefault();\n\n                        // Unselect this item.\n                        pendingPromise.resolve(deselectItem(options, state, selectedItem, originalSelect));\n                    }\n                    return false;\n            }\n\n            // Not handled. Resolve the promise.\n            pendingPromise.resolve();\n            return true;\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    return /** @alias module:core/form-autocomplete */ {\n        // Public variables and functions.\n        /**\n         * Turn a boring select box into an auto-complete beast.\n         *\n         * @method enhance\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} 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} 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        enhance: 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: placeholder,\n                caseSensitive: false,\n                showSuggestions: true,\n                noSelectionString: 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            Aria.hide(originalSelect.get());\n            originalSelect.css('visibility', 'hidden');\n\n            // Hide the original select.\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            };\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('<option>');\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 = [];\n            originalSelect.children('option').each(function(index, option) {\n                suggestions[index] = {label: option.innerHTML, value: $(option).attr('value')};\n            });\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 $.when(renderLayout, renderInput, renderDatalist, renderSelection)\n            .then(function(layout, input, suggestions, selection) {\n                originalSelect.hide();\n                var container = originalSelect.parent();\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"],"file":"form-autocomplete.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/form-autocomplete.js"],"names":["define","$","log","str","templates","notification","LoadingIcon","Aria","KEYS","DOWN","ENTER","SPACE","ESCAPE","COMMA","UP","LEFT","RIGHT","uniqueId","Date","now","activateSelection","index","state","selectionElement","document","getElementById","selectionId","length","children","element","get","itemId","attr","Deferred","resolve","updateSelectionList","options","originalSelect","pendingKey","inputId","M","util","js_pending","items","newSelection","activeId","activeValue","each","ele","prop","label","data","html","push","value","context","extend","render","then","js","replaceNodeContents","js_complete","catch","exception","notifyChange","core_formchangechecker","set_form_changed","dispatchEvent","Event","deselectItem","item","selectedItemValue","remove","activateItem","inputElement","suggestionsElement","suggestionsId","globalIndex","scrollPos","offset","top","scrollTop","height","animate","promise","activateNextItem","current","activatePreviousSelection","selectionsElement","activateNextSelection","activatePreviousItem","closeSuggestions","hide","updateSuggestions","query","matchingElements","suggestions","option","innerHTML","searchquery","caseSensitive","toLocaleLowerCase","returnVal","replaceNode","unhide","show","node","text","indexOf","tags","get_string","done","nosuggestionsstr","createItem","val","split","found","tagindex","tag","trim","multiple","append","createTextNode","selectCurrentItem","closeSuggestionsOnSelect","focus","updateAjax","e","ajaxHandler","pendingPromise","addPendingJSPromise","parentElement","selectId","parent","addIconToContainerRemoveOnCompletion","currentTarget","transport","selector","results","processedResults","processResults","existingValues","optionIndex","isArray","resultIndex","result","error","reject","addNavigation","on","pendingJsPromise","keyCode","showSuggestions","ajax","require","preventDefault","closest","window","setTimeout","focusElement","activeElement","timeoutPromise","is","arrowElement","downArrowId","off","selectedItem","throttleTimeout","inProgress","handler","arguments","throttledHandler","clearTimeout","bind","last","key","enhance","placeholder","noSelectionString","templateOverrides","input","layout","selection","fail","debug","css","prepend","originalLabel","collectedjs","renderLayout","renderInput","renderDatalist","renderSelection","when","container","find","replaceWith","runTemplateJS"],"mappings":"AA0BAA,OAAM,0BACF,CAAC,QAAD,CAAW,UAAX,CAAuB,UAAvB,CAAmC,gBAAnC,CAAqD,mBAArD,CAA0E,kBAA1E,CAA8F,WAA9F,CADE,CAEN,SAASC,CAAT,CAAYC,CAAZ,CAAiBC,CAAjB,CAAsBC,CAAtB,CAAiCC,CAAjC,CAA+CC,CAA/C,CAA4DC,CAA5D,CAAkE,IAI1DC,CAAAA,CAAI,CAAG,CACPC,IAAI,CAAE,EADC,CAEPC,KAAK,CAAE,EAFA,CAGPC,KAAK,CAAE,EAHA,CAIPC,MAAM,CAAE,EAJD,CAKPC,KAAK,CAAE,EALA,CAMPC,EAAE,CAAE,EANG,CAOPC,IAAI,CAAE,EAPC,CAQPC,KAAK,CAAE,EARA,CAJmD,CAe1DC,CAAQ,CAAGC,IAAI,CAACC,GAAL,EAf+C,CA0B1DC,CAAiB,CAAG,SAASC,CAAT,CAAgBC,CAAhB,CAAuB,IAEvCC,CAAAA,CAAgB,CAAGtB,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAFmB,CAKvCC,CAAM,CAAGJ,CAAgB,CAACK,QAAjB,CAA0B,sBAA1B,EAAkDD,MALpB,CAO3CN,CAAK,CAAGA,CAAK,CAAGM,CAAhB,CACA,MAAe,CAAR,CAAAN,CAAP,CAAkB,CACdA,CAAK,EAAIM,CACZ,CAV0C,GAYvCE,CAAAA,CAAO,CAAG5B,CAAC,CAACsB,CAAgB,CAACK,QAAjB,CAA0B,sBAA1B,EAAkDE,GAAlD,CAAsDT,CAAtD,CAAD,CAZ4B,CAcvCU,CAAM,CAAGT,CAAK,CAACI,WAAN,CAAoB,GAApB,CAA0BL,CAdI,CAiB3CE,CAAgB,CAACK,QAAjB,GAA4BI,IAA5B,CAAiC,uBAAjC,CAA0D,IAA1D,EAAgEA,IAAhE,CAAqE,IAArE,CAA2E,EAA3E,EAGAH,CAAO,CAACG,IAAR,CAAa,uBAAb,KAA4CA,IAA5C,CAAiD,IAAjD,CAAuDD,CAAvD,EAGAR,CAAgB,CAACS,IAAjB,CAAsB,uBAAtB,CAA+CD,CAA/C,EAEA,MAAO9B,CAAAA,CAAC,CAACgC,QAAF,GAAaC,OAAb,EACV,CApD6D,CAgE1DC,CAAmB,CAAG,SAASC,CAAT,CAAkBd,CAAlB,CAAyBe,CAAzB,CAAyC,CAC/D,GAAIC,CAAAA,CAAU,CAAG,yCAA2ChB,CAAK,CAACiB,OAAlE,CACAC,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkBJ,CAAlB,EAF+D,GAK3DK,CAAAA,CAAK,CAAG,EALmD,CAM3DC,CAAY,CAAG3C,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAN2C,CAO3DmB,CAAQ,CAAGD,CAAY,CAACZ,IAAb,CAAkB,uBAAlB,CAPgD,CAQ3Dc,CAAW,GARgD,CAU/D,GAAID,CAAJ,CAAc,CACVC,CAAW,CAAG7C,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBoB,CAAxB,CAAD,CAAD,CAAqCb,IAArC,CAA0C,YAA1C,CACjB,CACDK,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkCmB,IAAlC,CAAuC,SAAS1B,CAAT,CAAgB2B,CAAhB,CAAqB,CACxD,GAAI/C,CAAC,CAAC+C,CAAD,CAAD,CAAOC,IAAP,CAAY,UAAZ,CAAJ,CAA6B,CACzB,GAAIC,CAAAA,CAAJ,CACA,GAAIjD,CAAC,CAAC+C,CAAD,CAAD,CAAOG,IAAP,CAAY,MAAZ,CAAJ,CAAyB,CACrBD,CAAK,CAAGjD,CAAC,CAAC+C,CAAD,CAAD,CAAOG,IAAP,CAAY,MAAZ,CACX,CAFD,IAEO,CACHD,CAAK,CAAGjD,CAAC,CAAC+C,CAAD,CAAD,CAAOI,IAAP,EACX,CACD,GAAc,EAAV,GAAAF,CAAJ,CAAkB,CACdP,CAAK,CAACU,IAAN,CAAW,CAACH,KAAK,CAAEA,CAAR,CAAeI,KAAK,CAAErD,CAAC,CAAC+C,CAAD,CAAD,CAAOhB,IAAP,CAAY,OAAZ,CAAtB,CAAX,CACH,CACJ,CACJ,CAZD,EAaA,GAAIuB,CAAAA,CAAO,CAAGtD,CAAC,CAACuD,MAAF,CAAS,CAACb,KAAK,CAAEA,CAAR,CAAT,CAAyBP,CAAzB,CAAkCd,CAAlC,CAAd,CAEA,MAAOlB,CAAAA,CAAS,CAACqD,MAAV,CAAiBrB,CAAO,CAAChC,SAAR,CAAkBuC,KAAnC,CAA0CY,CAA1C,EACNG,IADM,CACD,SAASN,CAAT,CAAeO,CAAf,CAAmB,CAErBvD,CAAS,CAACwD,mBAAV,CAA8BhB,CAA9B,CAA4CQ,CAA5C,CAAkDO,CAAlD,EAEA,GAAI,KAAAb,CAAJ,CAA2B,CAEvBF,CAAY,CAAChB,QAAb,CAAsB,sBAAtB,EAA8CmB,IAA9C,CAAmD,SAAS1B,CAAT,CAAgB2B,CAAhB,CAAqB,CACpE,GAAI/C,CAAC,CAAC+C,CAAD,CAAD,CAAOhB,IAAP,CAAY,YAAZ,IAA8Bc,CAAlC,CAA+C,CAC3C1B,CAAiB,CAACC,CAAD,CAAQC,CAAR,CACpB,CACJ,CAJD,CAKH,CAED,MAAOwB,CAAAA,CACV,CAfM,EAgBNY,IAhBM,CAgBD,UAAW,CACb,MAAOlB,CAAAA,CAAC,CAACC,IAAF,CAAOoB,WAAP,CAAmBvB,CAAnB,CACV,CAlBM,EAmBNwB,KAnBM,CAmBAzD,CAAY,CAAC0D,SAnBb,CAoBV,CAhH6D,CAuH1DC,CAAY,CAAG,SAAS3B,CAAT,CAAyB,CACxC,GAAwC,WAApC,QAAOG,CAAAA,CAAC,CAACyB,sBAAb,CAAqD,CACjDzB,CAAC,CAACyB,sBAAF,CAAyBC,gBAAzB,EACH,CAID7B,CAAc,CAAC,CAAD,CAAd,CAAkB8B,aAAlB,CAAgC,GAAIC,CAAAA,KAAJ,CAAU,QAAV,CAAhC,CACH,CA/H6D,CA4I1DC,CAAY,CAAG,SAASjC,CAAT,CAAkBd,CAAlB,CAAyBgD,CAAzB,CAA+BjC,CAA/B,CAA+C,CAC9D,GAAIkC,CAAAA,CAAiB,CAAGtE,CAAC,CAACqE,CAAD,CAAD,CAAQtC,IAAR,CAAa,YAAb,CAAxB,CAGAK,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkCmB,IAAlC,CAAuC,SAAS1B,CAAT,CAAgB2B,CAAhB,CAAqB,CACxD,GAAI/C,CAAC,CAAC+C,CAAD,CAAD,CAAOhB,IAAP,CAAY,OAAZ,GAAwBuC,CAA5B,CAA+C,CAC3CtE,CAAC,CAAC+C,CAAD,CAAD,CAAOC,IAAP,CAAY,UAAZ,KAEA,GAAIhD,CAAC,CAAC+C,CAAD,CAAD,CAAOhB,IAAP,CAAY,eAAZ,CAAJ,CAAkC,CAC9B/B,CAAC,CAAC+C,CAAD,CAAD,CAAOwB,MAAP,EACH,CACJ,CACJ,CARD,EAUA,MAAOrC,CAAAA,CAAmB,CAACC,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CAAnB,CACNqB,IADM,CACD,UAAW,CAEbM,CAAY,CAAC3B,CAAD,CAGf,CANM,CAOV,CAjK6D,CA4K1DoC,CAAY,CAAG,SAASpD,CAAT,CAAgBC,CAAhB,CAAuB,IAElCoD,CAAAA,CAAY,CAAGzE,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACiB,OAA9B,CAAD,CAFkB,CAGlCoC,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAHY,CAMlCjD,CAAM,CAAGgD,CAAkB,CAAC/C,QAAnB,CAA4B,qBAA5B,EAAmDD,MAN1B,CAQtCN,CAAK,CAAGA,CAAK,CAAGM,CAAhB,CACA,MAAe,CAAR,CAAAN,CAAP,CAAkB,CACdA,CAAK,EAAIM,CACZ,CAXqC,GAalCE,CAAAA,CAAO,CAAG5B,CAAC,CAAC0E,CAAkB,CAAC/C,QAAnB,CAA4B,qBAA5B,EAAmDE,GAAnD,CAAuDT,CAAvD,CAAD,CAbuB,CAelCwD,CAAW,CAAG5E,CAAC,CAAC0E,CAAkB,CAAC/C,QAAnB,CAA4B,eAA5B,CAAD,CAAD,CAAgDP,KAAhD,CAAsDQ,CAAtD,CAfoB,CAiBlCE,CAAM,CAAGT,CAAK,CAACsD,aAAN,CAAsB,GAAtB,CAA4BC,CAjBH,CAoBtCF,CAAkB,CAAC/C,QAAnB,GAA8BI,IAA9B,CAAmC,eAAnC,KAA2DA,IAA3D,CAAgE,IAAhE,CAAsE,EAAtE,EAEAH,CAAO,CAACG,IAAR,CAAa,eAAb,KAAoCA,IAApC,CAAyC,IAAzC,CAA+CD,CAA/C,EAEA2C,CAAY,CAAC1C,IAAb,CAAkB,uBAAlB,CAA2CD,CAA3C,EAGA,GAAI+C,CAAAA,CAAS,CAAGjD,CAAO,CAACkD,MAAR,GAAiBC,GAAjB,CACCL,CAAkB,CAACI,MAAnB,GAA4BC,GAD7B,CAECL,CAAkB,CAACM,SAAnB,EAFD,CAGEN,CAAkB,CAACO,MAAnB,GAA8B,CAHhD,CAIA,MAAOP,CAAAA,CAAkB,CAACQ,OAAnB,CAA2B,CAC9BF,SAAS,CAAEH,CADmB,CAA3B,CAEJ,GAFI,EAECM,OAFD,EAGV,CA9M6D,CAwN1DC,CAAgB,CAAG,SAAS/D,CAAT,CAAgB,IAE/BqD,CAAAA,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAFS,CAI/B/C,CAAO,CAAG8C,CAAkB,CAAC/C,QAAnB,CAA4B,sBAA5B,CAJqB,CAM/B0D,CAAO,CAAGX,CAAkB,CAAC/C,QAAnB,CAA4B,qBAA5B,EAAmDP,KAAnD,CAAyDQ,CAAzD,CANqB,CAQnC,MAAO4C,CAAAA,CAAY,CAACa,CAAO,CAAG,CAAX,CAAchE,CAAd,CACtB,CAjO6D,CA2O1DiE,CAAyB,CAAG,SAASjE,CAAT,CAAgB,IAExCkE,CAAAA,CAAiB,CAAGvF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAFmB,CAIxCG,CAAO,CAAG2D,CAAiB,CAAC5D,QAAlB,CAA2B,yBAA3B,CAJ8B,CAK5C,GAAI,CAACC,CAAL,CAAc,CACV,MAAOT,CAAAA,CAAiB,CAAC,CAAD,CAAIE,CAAJ,CAC3B,CAED,GAAIgE,CAAAA,CAAO,CAAGE,CAAiB,CAAC5D,QAAlB,CAA2B,sBAA3B,EAAmDP,KAAnD,CAAyDQ,CAAzD,CAAd,CAEA,MAAOT,CAAAA,CAAiB,CAACkE,CAAO,CAAG,CAAX,CAAchE,CAAd,CAC3B,CAvP6D,CAiQ1DmE,CAAqB,CAAG,SAASnE,CAAT,CAAgB,IAEpCkE,CAAAA,CAAiB,CAAGvF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAFe,CAKpCG,CAAO,CAAG2D,CAAiB,CAAC5D,QAAlB,CAA2B,yBAA3B,CAL0B,CAMpC0D,CAAO,CAAG,CAN0B,CAQxC,GAAIzD,CAAJ,CAAa,CAETyD,CAAO,CAAGE,CAAiB,CAAC5D,QAAlB,CAA2B,sBAA3B,EAAmDP,KAAnD,CAAyDQ,CAAzD,CAAV,CACAyD,CAAO,CAAGA,CAAO,CAAG,CACvB,CAJD,IAIO,CAEHA,CAAO,CAAG,CACb,CAED,MAAOlE,CAAAA,CAAiB,CAACkE,CAAD,CAAUhE,CAAV,CAC3B,CAnR6D,CA6R1DoE,CAAoB,CAAG,SAASpE,CAAT,CAAgB,IAEnCqD,CAAAA,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAFa,CAKnC/C,CAAO,CAAG8C,CAAkB,CAAC/C,QAAnB,CAA4B,sBAA5B,CALyB,CAQnC0D,CAAO,CAAGX,CAAkB,CAAC/C,QAAnB,CAA4B,qBAA5B,EAAmDP,KAAnD,CAAyDQ,CAAzD,CARyB,CAWvC,MAAO4C,CAAAA,CAAY,CAACa,CAAO,CAAG,CAAX,CAAchE,CAAd,CACtB,CAzS6D,CAmT1DqE,CAAgB,CAAG,SAASrE,CAAT,CAAgB,IAE/BoD,CAAAA,CAAY,CAAGzE,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACiB,OAA9B,CAAD,CAFe,CAG/BoC,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAHS,CAKnC,GAA2C,MAAvC,GAAAF,CAAY,CAAC1C,IAAb,CAAkB,eAAlB,CAAJ,CAAmD,CAE/C0C,CAAY,CAAC1C,IAAb,CAAkB,eAAlB,IACH,CAED0C,CAAY,CAAC1C,IAAb,CAAkB,uBAAlB,CAA2CV,CAAK,CAACI,WAAjD,EAGAnB,CAAI,CAACqF,IAAL,CAAUjB,CAAkB,CAAC7C,GAAnB,EAAV,EACA6C,CAAkB,CAACiB,IAAnB,GAEA,MAAO3F,CAAAA,CAAC,CAACgC,QAAF,GAAaC,OAAb,EACV,CApU6D,CAiV1D2D,CAAiB,CAAG,SAASzD,CAAT,CAAkBd,CAAlB,CAAyBwE,CAAzB,CAAgCzD,CAAhC,CAAgD,CACpE,GAAIC,CAAAA,CAAU,CAAG,uCAAyChB,CAAK,CAACiB,OAAhE,CACAC,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkBJ,CAAlB,EAFoE,GAKhEoC,CAAAA,CAAY,CAAGzE,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACiB,OAA9B,CAAD,CALgD,CAMhEoC,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAN0C,CAShEmB,CAAgB,GATgD,CAWhEC,CAAW,CAAG,EAXkD,CAYpE3D,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkCmB,IAAlC,CAAuC,SAAS1B,CAAT,CAAgB4E,CAAhB,CAAwB,CAC3D,GAAI,KAAAhG,CAAC,CAACgG,CAAD,CAAD,CAAUhD,IAAV,CAAe,UAAf,CAAJ,CAAyC,CACrC+C,CAAW,CAACA,CAAW,CAACrE,MAAb,CAAX,CAAkC,CAACuB,KAAK,CAAE+C,CAAM,CAACC,SAAf,CAA0B5C,KAAK,CAAErD,CAAC,CAACgG,CAAD,CAAD,CAAUjE,IAAV,CAAe,OAAf,CAAjC,CACrC,CACJ,CAJD,EAZoE,GAmBhEmE,CAAAA,CAAW,CAAG7E,CAAK,CAAC8E,aAAN,CAAsBN,CAAtB,CAA8BA,CAAK,CAACO,iBAAN,EAnBoB,CAoBhE9C,CAAO,CAAGtD,CAAC,CAACuD,MAAF,CAAS,CAACpB,OAAO,CAAE4D,CAAV,CAAT,CAAiC5D,CAAjC,CAA0Cd,CAA1C,CApBsD,CAqBhEgF,CAAS,CAAGlG,CAAS,CAACqD,MAAV,CACZ,oCADY,CAEZF,CAFY,EAIfG,IAJe,CAIV,SAASN,CAAT,CAAeO,CAAf,CAAmB,CAErBvD,CAAS,CAACmG,WAAV,CAAsB5B,CAAtB,CAA0CvB,CAA1C,CAAgDO,CAAhD,EAGAgB,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAAtB,CAGArE,CAAI,CAACiG,MAAL,CAAY7B,CAAkB,CAAC7C,GAAnB,EAAZ,EACA6C,CAAkB,CAAC8B,IAAnB,GAGA9B,CAAkB,CAAC/C,QAAnB,GAA8BmB,IAA9B,CAAmC,SAAS1B,CAAT,CAAgBqF,CAAhB,CAAsB,CACrDA,CAAI,CAAGzG,CAAC,CAACyG,CAAD,CAAR,CACA,GAAKtE,CAAO,CAACgE,aAAR,EAA4D,CAAC,CAApC,CAAAM,CAAI,CAACC,IAAL,GAAYC,OAAZ,CAAoBT,CAApB,CAA1B,EACK,CAAC/D,CAAO,CAACgE,aAAT,EAAiF,CAAC,CAAxD,CAAAM,CAAI,CAACC,IAAL,GAAYN,iBAAZ,GAAgCO,OAAhC,CAAwCT,CAAxC,CADnC,CAC+F,CAC3F5F,CAAI,CAACiG,MAAL,CAAYE,CAAI,CAAC5E,GAAL,EAAZ,EACA4E,CAAI,CAACD,IAAL,GACAV,CAAgB,GACnB,CALD,IAKO,CACHW,CAAI,CAACd,IAAL,GACArF,CAAI,CAACqF,IAAL,CAAUc,CAAI,CAAC5E,GAAL,EAAV,CACH,CACJ,CAXD,EAaA4C,CAAY,CAAC1C,IAAb,CAAkB,eAAlB,KACA,GAAIK,CAAc,CAACL,IAAf,CAAoB,aAApB,CAAJ,CAAwC,CAEpC2C,CAAkB,CAACvB,IAAnB,CAAwBf,CAAc,CAACL,IAAf,CAAoB,aAApB,CAAxB,CACH,CAHD,IAGO,IAAI+D,CAAJ,CAAsB,CAIzB,GAAI,CAAC3D,CAAO,CAACyE,IAAb,CAAmB,CACfpC,CAAY,CAAC,CAAD,CAAInD,CAAJ,CACf,CACJ,CAPM,IAOA,CAEHnB,CAAG,CAAC2G,UAAJ,CAAe,eAAf,CAAgC,MAAhC,EAAwCC,IAAxC,CAA6C,SAASC,CAAT,CAA2B,CACpErC,CAAkB,CAACvB,IAAnB,CAAwB4D,CAAxB,CACH,CAFD,CAGH,CAED,MAAOrC,CAAAA,CACV,CAhDe,EAiDfjB,IAjDe,CAiDV,UAAW,CACb,MAAOlB,CAAAA,CAAC,CAACC,IAAF,CAAOoB,WAAP,CAAmBvB,CAAnB,CACV,CAnDe,EAoDfwB,KApDe,CAoDTzD,CAAY,CAAC0D,SApDJ,CArBoD,CA2EpE,MAAOuC,CAAAA,CACV,CA7Z6D,CAya1DW,CAAU,CAAG,SAAS7E,CAAT,CAAkBd,CAAlB,CAAyBe,CAAzB,CAAyC,IAElDqC,CAAAA,CAAY,CAAGzE,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACiB,OAA9B,CAAD,CAFkC,CAIlDuD,CAAK,CAAGpB,CAAY,CAACwC,GAAb,EAJ0C,CAKlDL,CAAI,CAAGf,CAAK,CAACqB,KAAN,CAAY,GAAZ,CAL2C,CAMlDC,CAAK,GAN6C,CAQtDnH,CAAC,CAAC8C,IAAF,CAAO8D,CAAP,CAAa,SAASQ,CAAT,CAAmBC,CAAnB,CAAwB,CAEjCA,CAAG,CAAGA,CAAG,CAACC,IAAJ,EAAN,CACA,GAAY,EAAR,GAAAD,CAAJ,CAAgB,CACZ,GAAI,CAAClF,CAAO,CAACoF,QAAb,CAAuB,CACnBnF,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkCqB,IAAlC,CAAuC,UAAvC,IACH,CAEDZ,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkCmB,IAAlC,CAAuC,SAAS1B,CAAT,CAAgB2B,CAAhB,CAAqB,CACxD,GAAI/C,CAAC,CAAC+C,CAAD,CAAD,CAAOhB,IAAP,CAAY,OAAZ,GAAwBsF,CAA5B,CAAiC,CAC7BF,CAAK,GAAL,CACAnH,CAAC,CAAC+C,CAAD,CAAD,CAAOC,IAAP,CAAY,UAAZ,IACH,CACJ,CALD,EAOA,GAAI,CAACmE,CAAL,CAAY,CACR,GAAInB,CAAAA,CAAM,CAAGhG,CAAC,CAAC,UAAD,CAAd,CACAgG,CAAM,CAACwB,MAAP,CAAcjG,QAAQ,CAACkG,cAAT,CAAwBJ,CAAxB,CAAd,EACArB,CAAM,CAACjE,IAAP,CAAY,OAAZ,CAAqBsF,CAArB,EACAjF,CAAc,CAACoF,MAAf,CAAsBxB,CAAtB,EACAA,CAAM,CAAChD,IAAP,CAAY,UAAZ,KAEAgD,CAAM,CAACjE,IAAP,CAAY,eAAZ,IACH,CACJ,CACJ,CAzBD,EA2BA,MAAOG,CAAAA,CAAmB,CAACC,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CAAnB,CACNqB,IADM,CACD,UAAW,CAEbM,CAAY,CAAC3B,CAAD,CAGf,CANM,EAONqB,IAPM,CAOD,UAAW,CAEbgB,CAAY,CAACwC,GAAb,CAAiB,EAAjB,CAGH,CAZM,EAaNxD,IAbM,CAaD,UAAW,CAEb,MAAOiC,CAAAA,CAAgB,CAACrE,CAAD,CAC1B,CAhBM,CAiBV,CA7d6D,CAye1DqG,CAAiB,CAAG,SAASvF,CAAT,CAAkBd,CAAlB,CAAyBe,CAAzB,CAAyC,IAEzDqC,CAAAA,CAAY,CAAGzE,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACiB,OAA9B,CAAD,CAFyC,CAGzDoC,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAHmC,CAMzDL,CAAiB,CAAGI,CAAkB,CAAC/C,QAAnB,CAA4B,sBAA5B,EAAoDI,IAApD,CAAyD,YAAzD,CANqC,CAW7D,GAAI,CAACI,CAAO,CAACoF,QAAb,CAAuB,CACnBnF,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkCqB,IAAlC,CAAuC,UAAvC,IACH,CAEDZ,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkCmB,IAAlC,CAAuC,SAAS1B,CAAT,CAAgB2B,CAAhB,CAAqB,CACxD,GAAI/C,CAAC,CAAC+C,CAAD,CAAD,CAAOhB,IAAP,CAAY,OAAZ,GAAwBuC,CAA5B,CAA+C,CAC3CtE,CAAC,CAAC+C,CAAD,CAAD,CAAOC,IAAP,CAAY,UAAZ,IACH,CACJ,CAJD,EAMA,MAAOd,CAAAA,CAAmB,CAACC,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CAAnB,CACNqB,IADM,CACD,UAAW,CAEbM,CAAY,CAAC3B,CAAD,CAGf,CANM,EAONqB,IAPM,CAOD,UAAW,CACb,GAAItB,CAAO,CAACwF,wBAAZ,CAAsC,CAElClD,CAAY,CAACwC,GAAb,CAAiB,EAAjB,EAEA,MAAOvB,CAAAA,CAAgB,CAACrE,CAAD,CAC1B,CALD,IAKO,CAEHoD,CAAY,CAACmD,KAAb,GAEA,MAAOhC,CAAAA,CAAiB,CAACzD,CAAD,CAAUd,CAAV,CAAiBoD,CAAY,CAACwC,GAAb,EAAjB,CAAqC7E,CAArC,CAC3B,CACJ,CAnBM,CAoBV,CAlhB6D,CAgiB1DyF,CAAU,CAAG,SAASC,CAAT,CAAY3F,CAAZ,CAAqBd,CAArB,CAA4Be,CAA5B,CAA4C2F,CAA5C,CAAyD,IAClEC,CAAAA,CAAc,CAAGC,CAAmB,CAAC,YAAD,CAD8B,CAIlEC,CAAa,CAAGlI,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAAC8G,QAA9B,CAAD,CAAD,CAA2CC,MAA3C,EAJkD,CAKtE/H,CAAW,CAACgI,oCAAZ,CAAiDH,CAAjD,CAAgEF,CAAhE,EAGA,GAAInC,CAAAA,CAAK,CAAG7F,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAD,CAAmBrB,GAAnB,EAAZ,CAEAc,CAAW,CAACQ,SAAZ,CAAsBpG,CAAO,CAACqG,QAA9B,CAAwC3C,CAAxC,CAA+C,SAAS4C,CAAT,CAAkB,IAEzDC,CAAAA,CAAgB,CAAGX,CAAW,CAACY,cAAZ,CAA2BxG,CAAO,CAACqG,QAAnC,CAA6CC,CAA7C,CAFsC,CAGzDG,CAAc,CAAG,EAHwC,CAM7D,GAAI,CAACzG,CAAO,CAACoF,QAAb,CAAuB,CACnBnF,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkC4C,MAAlC,EACH,CACDnC,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkCmB,IAAlC,CAAuC,SAAS+F,CAAT,CAAsB7C,CAAtB,CAA8B,CACjEA,CAAM,CAAGhG,CAAC,CAACgG,CAAD,CAAV,CACA,GAAI,CAACA,CAAM,CAAChD,IAAP,CAAY,UAAZ,CAAL,CAA8B,CAC1BgD,CAAM,CAACzB,MAAP,EACH,CAFD,IAEO,CACHqE,CAAc,CAACxF,IAAf,CAA2B4C,CAAM,CAACjE,IAAP,CAAY,OAAZ,CAA3B,IACH,CACJ,CAPD,EASA,GAAI,CAACI,CAAO,CAACoF,QAAT,EAAkE,CAA7C,GAAAnF,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkCD,MAA3D,CAAyE,CAIrE,GAAIsE,CAAAA,CAAM,CAAGhG,CAAC,CAAC,UAAD,CAAd,CACAoC,CAAc,CAACoF,MAAf,CAAsBxB,CAAtB,CACH,CACD,GAAIhG,CAAC,CAAC8I,OAAF,CAAUJ,CAAV,CAAJ,CAAiC,CAE7B1I,CAAC,CAAC8C,IAAF,CAAO4F,CAAP,CAAyB,SAASK,CAAT,CAAsBC,CAAtB,CAA8B,CACnD,GAAqD,CAAC,CAAlD,GAAAJ,CAAc,CAACjC,OAAf,CAA8BqC,CAAM,CAAC3F,KAArC,IAAJ,CAAyD,CACrD,GAAI2C,CAAAA,CAAM,CAAGhG,CAAC,CAAC,UAAD,CAAd,CACAgG,CAAM,CAACwB,MAAP,CAAcwB,CAAM,CAAC/F,KAArB,EACA+C,CAAM,CAACjE,IAAP,CAAY,OAAZ,CAAqBiH,CAAM,CAAC3F,KAA5B,EACAjB,CAAc,CAACoF,MAAf,CAAsBxB,CAAtB,CACH,CACJ,CAPD,EAQA5D,CAAc,CAACL,IAAf,CAAoB,aAApB,CAAmC,EAAnC,CACH,CAXD,IAWO,CAEHK,CAAc,CAACL,IAAf,CAAoB,aAApB,CAAmC2G,CAAnC,CACH,CAEDV,CAAc,CAAC/F,OAAf,CAAuB2D,CAAiB,CAACzD,CAAD,CAAUd,CAAV,CAAiB,EAAjB,CAAqBe,CAArB,CAAxC,CACH,CA1CD,CA0CG,SAAS6G,CAAT,CAAgB,CACfjB,CAAc,CAACkB,MAAf,CAAsBD,CAAtB,CACH,CA5CD,EA8CA,MAAOjB,CAAAA,CACV,CAzlB6D,CAomB1DmB,CAAa,CAAG,SAAShH,CAAT,CAAkBd,CAAlB,CAAyBe,CAAzB,CAAyC,CAEzD,GAAIqC,CAAAA,CAAY,CAAGzE,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACiB,OAA9B,CAAD,CAApB,CAEAmC,CAAY,CAAC2E,EAAb,CAAgB,SAAhB,CAA2B,SAAStB,CAAT,CAAY,CACnC,GAAIuB,CAAAA,CAAgB,CAAGpB,CAAmB,CAAC,iBAAmB5G,CAAK,CAACiB,OAAzB,CAAmC,GAAnC,CAAyCwF,CAAC,CAACwB,OAA5C,CAA1C,CAEA,OAAQxB,CAAC,CAACwB,OAAV,EACI,IAAK/I,CAAAA,CAAI,CAACC,IAAV,CAEI,GAAI,CAAC2B,CAAO,CAACoH,eAAb,CAA8B,CAE1BF,CAAgB,CAACpH,OAAjB,GACA,QACH,CAJD,IAIO,IAA2C,MAAvC,GAAAwC,CAAY,CAAC1C,IAAb,CAAkB,eAAlB,CAAJ,CAAmD,CACtDsH,CAAgB,CAACpH,OAAjB,CAAyBmD,CAAgB,CAAC/D,CAAD,CAAzC,CACH,CAFM,IAEA,CAEH,GAAI,CAACoD,CAAY,CAACwC,GAAb,EAAD,EAAuB9E,CAAO,CAACqH,IAAnC,CAAyC,CACrCC,OAAO,CAAC,CAACtH,CAAO,CAACqH,IAAT,CAAD,CAAiB,SAASzB,CAAT,CAAsB,CAC1CsB,CAAgB,CAACpH,OAAjB,CAAyB4F,CAAU,CAACC,CAAD,CAAI3F,CAAJ,CAAad,CAAb,CAAoBe,CAApB,CAAoC2F,CAApC,CAAnC,CACH,CAFM,CAGV,CAJD,IAIO,CAEHsB,CAAgB,CAACpH,OAAjB,CAAyB2D,CAAiB,CAACzD,CAAD,CAAUd,CAAV,CAAiBoD,CAAY,CAACwC,GAAb,EAAjB,CAAqC7E,CAArC,CAA1C,CACH,CACJ,CAED0F,CAAC,CAAC4B,cAAF,GACA,SACJ,IAAKnJ,CAAAA,CAAI,CAACM,EAAV,CAEIwI,CAAgB,CAACpH,OAAjB,CAAyBwD,CAAoB,CAACpE,CAAD,CAA7C,EAGAyG,CAAC,CAAC4B,cAAF,GACA,SACJ,IAAKnJ,CAAAA,CAAI,CAACE,KAAV,CACI,GAAIiE,CAAAA,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAA1B,CACA,GAA4C,MAAvC,GAAAF,CAAY,CAAC1C,IAAb,CAAkB,eAAlB,CAAD,EACkE,CAA7D,CAAA2C,CAAkB,CAAC/C,QAAnB,CAA4B,sBAA5B,EAAoDD,MAD7D,CAC0E,CAEtE2H,CAAgB,CAACpH,OAAjB,CAAyByF,CAAiB,CAACvF,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CAA1C,CACH,CAJD,IAIO,IAAID,CAAO,CAACyE,IAAZ,CAAkB,CAErByC,CAAgB,CAACpH,OAAjB,CAAyB+E,CAAU,CAAC7E,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CAAnC,CACH,CAHM,IAGA,CACHiH,CAAgB,CAACpH,OAAjB,EACH,CAGD6F,CAAC,CAAC4B,cAAF,GACA,SACJ,IAAKnJ,CAAAA,CAAI,CAACI,MAAV,CACI,GAA2C,MAAvC,GAAA8D,CAAY,CAAC1C,IAAb,CAAkB,eAAlB,CAAJ,CAAmD,CAE/CsH,CAAgB,CAACpH,OAAjB,CAAyByD,CAAgB,CAACrE,CAAD,CAAzC,CACH,CAHD,IAGO,CACHgI,CAAgB,CAACpH,OAAjB,EACH,CAED6F,CAAC,CAAC4B,cAAF,GACA,SAvDR,CAyDAL,CAAgB,CAACpH,OAAjB,GACA,QACH,CA9DD,EAgEAwC,CAAY,CAAC2E,EAAb,CAAgB,UAAhB,CAA4B,SAAStB,CAAT,CAAY,CAEpC,GAAIA,CAAC,CAACwB,OAAF,GAAc/I,CAAI,CAACK,KAAvB,CAA8B,CAC1B,GAAIuB,CAAO,CAACyE,IAAZ,CAAkB,CAEdqB,CAAmB,CAAC,YAAcH,CAAC,CAACwB,OAAjB,CAAnB,CACCrH,OADD,CACS+E,CAAU,CAAC7E,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CADnB,CAEH,CAED0F,CAAC,CAAC4B,cAAF,GACA,QACH,CACD,QACH,CAbD,EAgBAjF,CAAY,CAACkF,OAAb,CAAqB,MAArB,EAA6BP,EAA7B,CAAgC,QAAhC,CAA0C,UAAW,CACjD,GAAIjH,CAAO,CAACyE,IAAZ,CAAkB,CAEdqB,CAAmB,CAAC,0BAAD,CAAnB,CACChG,OADD,CACS+E,CAAU,CAAC7E,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CADnB,CAEH,CAED,QACH,CARD,EASAqC,CAAY,CAAC2E,EAAb,CAAgB,MAAhB,CAAwB,UAAW,CAC/B,GAAIpB,CAAAA,CAAc,CAAGC,CAAmB,CAAC,wBAAD,CAAxC,CACA2B,MAAM,CAACC,UAAP,CAAkB,UAAW,IAErBC,CAAAA,CAAY,CAAG9J,CAAC,CAACuB,QAAQ,CAACwI,aAAV,CAFK,CAGrBC,CAAc,CAAGhK,CAAC,CAACgC,QAAF,EAHI,CASzB,GAAI8H,CAAY,CAACG,EAAb,CAAgB1I,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAhB,CAAJ,CAAmE,CAC/DF,CAAY,CAACmD,KAAb,EACH,CAFD,IAEO,IAAI,CAACkC,CAAY,CAACG,EAAb,CAAgBxF,CAAhB,CAAD,EAAkCzE,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACiB,OAA9B,CAAD,CAAD,CAA0CZ,MAAhF,CAAwF,CAC3F,GAAIS,CAAO,CAACyE,IAAZ,CAAkB,CACdoD,CAAc,CAACvG,IAAf,CAAoB,UAAW,CAC3B,MAAOuD,CAAAA,CAAU,CAAC7E,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CACpB,CAFD,EAGCyB,KAHD,EAIH,CACDmG,CAAc,CAACvG,IAAf,CAAoB,UAAW,CAC3B,MAAOiC,CAAAA,CAAgB,CAACrE,CAAD,CAC1B,CAFD,EAGCwC,KAHD,EAIH,CAEDmG,CAAc,CAACvG,IAAf,CAAoB,UAAW,CAC3B,MAAOuE,CAAAA,CAAc,CAAC/F,OAAf,EACV,CAFD,EAGC4B,KAHD,GAIAmG,CAAc,CAAC/H,OAAf,EACH,CA7BD,CA6BG,GA7BH,CA8BH,CAhCD,EAiCA,GAAIE,CAAO,CAACoH,eAAZ,CAA6B,CACzB,GAAIW,CAAAA,CAAY,CAAGlK,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAAC8I,WAA9B,CAAD,CAApB,CACAD,CAAY,CAACd,EAAb,CAAgB,OAAhB,CAAyB,SAAStB,CAAT,CAAY,CACjC,GAAIE,CAAAA,CAAc,CAAGC,CAAmB,CAAC,oCAAD,CAAxC,CAGAxD,CAAY,CAACmD,KAAb,GAGA,GAAI,CAACnD,CAAY,CAACwC,GAAb,EAAD,EAAuB9E,CAAO,CAACqH,IAAnC,CAAyC,CACrCC,OAAO,CAAC,CAACtH,CAAO,CAACqH,IAAT,CAAD,CAAiB,SAASzB,CAAT,CAAsB,CAC1CC,CAAc,CAAC/F,OAAf,CAAuB4F,CAAU,CAACC,CAAD,CAAI3F,CAAJ,CAAad,CAAb,CAAoBe,CAApB,CAAoC2F,CAApC,CAAjC,CACH,CAFM,CAGV,CAJD,IAIO,CAEHC,CAAc,CAAC/F,OAAf,CAAuB2D,CAAiB,CAACzD,CAAD,CAAUd,CAAV,CAAiBoD,CAAY,CAACwC,GAAb,EAAjB,CAAqC7E,CAArC,CAAxC,CACH,CACJ,CAfD,CAgBH,CAED,GAAIsC,CAAAA,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAA1B,CAEAD,CAAkB,CAAC0D,MAAnB,GAA4BpF,IAA5B,CAAiC,SAAjC,CAA4C,IAA5C,EAAkDoH,GAAlD,CAAsD,OAAtD,EACA1F,CAAkB,CAAC0D,MAAnB,GAA4BgB,EAA5B,CAA+B,OAA/B,YAA4C/H,CAAK,CAACsD,aAAlD,mBAAiF,SAASmD,CAAT,CAAY,IACrFE,CAAAA,CAAc,CAAGC,CAAmB,CAAC,0BAAD,CADiD,CAGrFrG,CAAO,CAAG5B,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAD,CAAmBqB,OAAnB,CAA2B,eAA3B,CAH2E,CAIrFjF,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAJ+D,CAMrFU,CAAO,CAAGX,CAAkB,CAAC/C,QAAnB,CAA4B,qBAA5B,EAAmDP,KAAnD,CAAyDQ,CAAzD,CAN2E,CASzF4C,CAAY,CAACa,CAAD,CAAUhE,CAAV,CAAZ,CACCoC,IADD,CACM,UAAW,CAEb,MAAOiE,CAAAA,CAAiB,CAACvF,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CAC3B,CAJD,EAKCqB,IALD,CAKM,UAAW,CACb,MAAOuE,CAAAA,CAAc,CAAC/F,OAAf,EACV,CAPD,EAQC4B,KARD,EASH,CAlBD,EAmBA,GAAIvC,CAAAA,CAAgB,CAAGtB,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAAxB,CAEAH,CAAgB,CAAC8H,EAAjB,CAAoB,OAApB,CAA6B,eAA7B,CAA8C,SAAStB,CAAT,CAAY,CACtD,GAAIE,CAAAA,CAAc,CAAGC,CAAmB,CAAC,0BAAD,CAAxC,CAGAD,CAAc,CAAC/F,OAAf,CAAuBmC,CAAY,CAACjC,CAAD,CAAUd,CAAV,CAAiBrB,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAlB,CAAqClG,CAArC,CAAnC,CACH,CALD,EAOAd,CAAgB,CAAC8H,EAAjB,CAAoB,OAApB,CAA6B,UAAW,IAEhC7D,CAAAA,CAAiB,CAAGvF,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAFW,CAIhCG,CAAO,CAAG2D,CAAiB,CAAC5D,QAAlB,CAA2B,yBAA3B,CAJsB,CAKpC,GAAI,CAACC,CAAO,CAACF,MAAb,CAAqB,CACjB,MAAOP,CAAAA,CAAiB,CAAC,CAAD,CAAIE,CAAJ,CAC3B,CACJ,CARD,EAUAC,CAAgB,CAAC8H,EAAjB,CAAoB,SAApB,CAA+B,SAAStB,CAAT,CAAY,CACvC,GAAIE,CAAAA,CAAc,CAAGC,CAAmB,CAAC,6BAA+BH,CAAC,CAACwB,OAAlC,CAAxC,CACA,OAAQxB,CAAC,CAACwB,OAAV,EACI,IAAK/I,CAAAA,CAAI,CAACQ,KAAV,CACA,IAAKR,CAAAA,CAAI,CAACC,IAAV,CAEIsH,CAAC,CAAC4B,cAAF,GAGA1B,CAAc,CAAC/F,OAAf,CAAuBuD,CAAqB,CAACnE,CAAD,CAA5C,EACA,SACJ,IAAKd,CAAAA,CAAI,CAACO,IAAV,CACA,IAAKP,CAAAA,CAAI,CAACM,EAAV,CAEIiH,CAAC,CAAC4B,cAAF,GAGA1B,CAAc,CAAC/F,OAAf,CAAuBqD,CAAyB,CAACjE,CAAD,CAAhD,EACA,SACJ,IAAKd,CAAAA,CAAI,CAACG,KAAV,CACA,IAAKH,CAAAA,CAAI,CAACE,KAAV,CAEI,GAAI4J,CAAAA,CAAY,CAAGrK,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACI,WAA9B,CAAD,CAAD,CAA8CE,QAA9C,CAAuD,yBAAvD,CAAnB,CACA,GAAI0I,CAAJ,CAAkB,CACdvC,CAAC,CAAC4B,cAAF,GAGA1B,CAAc,CAAC/F,OAAf,CAAuBmC,CAAY,CAACjC,CAAD,CAAUd,CAAV,CAAiBgJ,CAAjB,CAA+BjI,CAA/B,CAAnC,CACH,CACD,SA3BR,CA+BA4F,CAAc,CAAC/F,OAAf,GACA,QACH,CAnCD,EAqCA,GAAIE,CAAO,CAACoH,eAAZ,CAA6B,CAEzB9E,CAAY,CAAC2E,EAAb,CAAgB,OAAhB,CAAyB,SAAStB,CAAT,CAAY,CACjC,GAAIjC,CAAAA,CAAK,CAAG7F,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAD,CAAmBrB,GAAnB,EAAZ,CACAjH,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAD,CAAmBpF,IAAnB,CAAwB,YAAxB,CAAsC2C,CAAtC,CACH,CAHD,EAMA,GAAI1D,CAAO,CAACqH,IAAZ,CAAkB,CACdC,OAAO,CAAC,CAACtH,CAAO,CAACqH,IAAT,CAAD,CAAiB,SAASzB,CAAT,CAAsB,IAKtCuC,CAAAA,CAAe,CAAG,IALoB,CAMtCC,CAAU,GAN4B,CAOtClI,CAAU,CAAG,+BAPyB,CAQtCmI,CAAO,CAAG,SAAS1C,CAAT,CAAY,CAEtBwC,CAAe,CAAG,IAAlB,CAGAC,CAAU,GAAV,CAGA1C,CAAU,CAACC,CAAD,CAAI3F,CAAJ,CAAad,CAAb,CAAoBe,CAApB,CAAoC2F,CAApC,CAAV,CACCtE,IADD,CACM,UAAW,CAMb,GAAI,OAAS6G,CAAb,CAA8B,CAE1B/H,CAAC,CAACC,IAAF,CAAOoB,WAAP,CAAmBvB,CAAnB,CACH,CACDkI,CAAU,GAAV,CAEA,MAAOE,CAAAA,SAAS,CAAC,CAAD,CACnB,CAdD,EAeC5G,KAfD,CAeOzD,CAAY,CAAC0D,SAfpB,CAgBH,CAhCyC,CAmCtC4G,CAAgB,CAAG,SAAS5C,CAAT,CAAY,CAC/B8B,MAAM,CAACe,YAAP,CAAoBL,CAApB,EACA,GAAIC,CAAJ,CAAgB,CAGZD,CAAe,CAAGV,MAAM,CAACC,UAAP,CAAkBa,CAAgB,CAACE,IAAjB,CAAsB,IAAtB,CAA4B9C,CAA5B,CAAlB,CAAkD,GAAlD,CAAlB,CACA,MACH,CAED,GAAwB,IAApB,GAAAwC,CAAJ,CAA8B,CAG1B/H,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkBJ,CAAlB,CACH,CAKDiI,CAAe,CAAGV,MAAM,CAACC,UAAP,CAAkBW,CAAO,CAACI,IAAR,CAAa,IAAb,CAAmB9C,CAAnB,CAAlB,CAAyC,GAAzC,CACrB,CAtDyC,CAyD1CrD,CAAY,CAAC2E,EAAb,CAAgB,OAAhB,CAAyB,SAAStB,CAAT,CAAY,IAC7BjC,CAAAA,CAAK,CAAG7F,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAD,CAAmBrB,GAAnB,EADqB,CAE7B4D,CAAI,CAAG7K,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAD,CAAmBpF,IAAnB,CAAwB,YAAxB,CAFsB,CAIjC,GAAI2H,CAAI,GAAKhF,CAAb,CAAoB,CAChB6E,CAAgB,CAAC5C,CAAD,CACnB,CACD9H,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAD,CAAmBpF,IAAnB,CAAwB,YAAxB,CAAsC2C,CAAtC,CACH,CARD,CASH,CAlEM,CAmEV,CApED,IAoEO,CACHpB,CAAY,CAAC2E,EAAb,CAAgB,OAAhB,CAAyB,SAAStB,CAAT,CAAY,IAC7BjC,CAAAA,CAAK,CAAG7F,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAD,CAAmBrB,GAAnB,EADqB,CAE7B4D,CAAI,CAAG7K,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAD,CAAmBpF,IAAnB,CAAwB,YAAxB,CAFsB,CAQjC,GAAI2H,CAAI,GAAKhF,CAAb,CAAoB,CAChBD,CAAiB,CAACzD,CAAD,CAAUd,CAAV,CAAiBwE,CAAjB,CAAwBzD,CAAxB,CACpB,CACDpC,CAAC,CAAC8H,CAAC,CAACQ,aAAH,CAAD,CAAmBpF,IAAnB,CAAwB,YAAxB,CAAsC2C,CAAtC,CACH,CAZD,CAaH,CACJ,CACJ,CAh6B6D,CAw6B1DoC,CAAmB,CAAG,SAAS6C,CAAT,CAAc,CAChC,GAAIzI,CAAAA,CAAU,CAAG,qBAAuByI,CAAxC,CAEAvI,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkBJ,CAAlB,EAEA,GAAI2F,CAAAA,CAAc,CAAGhI,CAAC,CAACgC,QAAF,EAArB,CAEAgG,CAAc,CACbvE,IADD,CACM,UAAW,CACblB,CAAC,CAACC,IAAF,CAAOoB,WAAP,CAAmBvB,CAAnB,EAEA,MAAOoI,CAAAA,SAAS,CAAC,CAAD,CACnB,CALD,EAMC5G,KAND,CAMOzD,CAAY,CAAC0D,SANpB,EAQA,MAAOkE,CAAAA,CACd,CAx7B6D,CA07B9D,MAAmD,CAmB/C+C,OAAO,CAAE,iBAASvC,CAAT,CAAmB5B,CAAnB,CAAyB4C,CAAzB,CAA+BwB,CAA/B,CAA4C7E,CAA5C,CAA2DoD,CAA3D,CAA4E0B,CAA5E,CACStD,CADT,CACmCuD,CADnC,CACsD,IAEvD/I,CAAAA,CAAO,CAAG,CACVqG,QAAQ,CAAEA,CADA,CAEV5B,IAAI,GAFM,CAGV4C,IAAI,GAHM,CAIVwB,WAAW,CAAEA,CAJH,CAKV7E,aAAa,GALH,CAMVoD,eAAe,GANL,CAOV0B,iBAAiB,CAAEA,CAPT,CAQV9K,SAAS,CAAEH,CAAC,CAACuD,MAAF,CAAS,CACZ4H,KAAK,CAAE,8BADK,CAEZzI,KAAK,CAAE,wCAFK,CAGZ0I,MAAM,CAAE,+BAHI,CAIZC,SAAS,CAAE,kCAJC,CAKZtF,WAAW,CAAE,oCALD,CAAT,CAMJmF,CANI,CARD,CAF6C,CAkBvD7I,CAAU,CAAG,sBAAwBmG,CAlBkB,CAmB3DjG,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkBJ,CAAlB,EACA,GAAoB,WAAhB,QAAOuE,CAAAA,CAAX,CAAiC,CAC7BzE,CAAO,CAACyE,IAAR,CAAeA,CAClB,CACD,GAAoB,WAAhB,QAAO4C,CAAAA,CAAX,CAAiC,CAC7BrH,CAAO,CAACqH,IAAR,CAAeA,CAClB,CACD,GAA6B,WAAzB,QAAOrD,CAAAA,CAAX,CAA0C,CACtChE,CAAO,CAACgE,aAAR,CAAwBA,CAC3B,CACD,GAA+B,WAA3B,QAAOoD,CAAAA,CAAX,CAA4C,CACxCpH,CAAO,CAACoH,eAAR,CAA0BA,CAC7B,CACD,GAAiC,WAA7B,QAAO0B,CAAAA,CAAX,CAA8C,CAC1C/K,CAAG,CAAC2G,UAAJ,CAAe,aAAf,CAA8B,MAA9B,EAAsCC,IAAtC,CAA2C,SAASkC,CAAT,CAAiB,CACxD7G,CAAO,CAAC8I,iBAAR,CAA4BjC,CAC/B,CAFD,EAEGsC,IAFH,CAEQlL,CAAY,CAAC0D,SAFrB,CAGH,CAGD,GAAI1B,CAAAA,CAAc,CAAGpC,CAAC,CAACwI,CAAD,CAAtB,CACA,GAAI,CAACpG,CAAL,CAAqB,CACjBnC,CAAG,CAACsL,KAAJ,CAAU,uBAAyB/C,CAAnC,EACAjG,CAAC,CAACC,IAAF,CAAOoB,WAAP,CAAmBvB,CAAnB,EACA,QACH,CAED/B,CAAI,CAACqF,IAAL,CAAUvD,CAAc,CAACP,GAAf,EAAV,EACAO,CAAc,CAACoJ,GAAf,CAAmB,YAAnB,CAAiC,QAAjC,EAKA,GAAInK,CAAAA,CAAK,CAAG,CACR8G,QAAQ,CAAE/F,CAAc,CAACL,IAAf,CAAoB,IAApB,CADF,CAERO,OAAO,CAAE,2BAA6BtB,CAF9B,CAGR2D,aAAa,CAAE,iCAAmC3D,CAH1C,CAIRS,WAAW,CAAE,+BAAiCT,CAJtC,CAKRmJ,WAAW,CAAE,+BAAiCnJ,CALtC,CAAZ,CASAA,CAAQ,GAERmB,CAAO,CAACoF,QAAR,CAAmBnF,CAAc,CAACL,IAAf,CAAoB,UAApB,CAAnB,CACA,GAAI,CAACI,CAAO,CAACoF,QAAb,CAAuB,CAInBnF,CAAc,CAACqJ,OAAf,CAAuB,UAAvB,CACH,CAED,GAAwC,WAApC,QAAO9D,CAAAA,CAAX,CAAqD,CACjDxF,CAAO,CAACwF,wBAAR,CAAmCA,CACtC,CAFD,IAEO,CAEHxF,CAAO,CAACwF,wBAAR,CAAmC,CAACxF,CAAO,CAACoF,QAC/C,CA5E0D,GA8EvDmE,CAAAA,CAAa,CAAG1L,CAAC,CAAC,QAAUqB,CAAK,CAAC8G,QAAhB,CAA2B,GAA5B,CA9EsC,CAgFvDpC,CAAW,CAAG,EAhFyC,CAiF3D3D,CAAc,CAACT,QAAf,CAAwB,QAAxB,EAAkCmB,IAAlC,CAAuC,SAAS1B,CAAT,CAAgB4E,CAAhB,CAAwB,CAC3DD,CAAW,CAAC3E,CAAD,CAAX,CAAqB,CAAC6B,KAAK,CAAE+C,CAAM,CAACC,SAAf,CAA0B5C,KAAK,CAAErD,CAAC,CAACgG,CAAD,CAAD,CAAUjE,IAAV,CAAe,OAAf,CAAjC,CACxB,CAFD,EAKA,GAAIuB,CAAAA,CAAO,CAAGtD,CAAC,CAACuD,MAAF,CAAS,EAAT,CAAapB,CAAb,CAAsBd,CAAtB,CAAd,CACAiC,CAAO,CAACnB,OAAR,CAAkB4D,CAAlB,CACAzC,CAAO,CAACZ,KAAR,CAAgB,EAAhB,CAxF2D,GA2FvDiJ,CAAAA,CAAW,CAAG,EA3FyC,CA6FvDC,CAAY,CAAGzL,CAAS,CAACqD,MAAV,CAAiBrB,CAAO,CAAChC,SAAR,CAAkBiL,MAAnC,CAA2C,EAA3C,EAClB3H,IADkB,CACb,SAASN,CAAT,CAAe,CACjB,MAAOnD,CAAAA,CAAC,CAACmD,CAAD,CACX,CAHkB,CA7FwC,CAkGvD0I,CAAW,CAAG1L,CAAS,CAACqD,MAAV,CAAiBrB,CAAO,CAAChC,SAAR,CAAkBgL,KAAnC,CAA0C7H,CAA1C,EAAmDG,IAAnD,CAAwD,SAASN,CAAT,CAAeO,CAAf,CAAmB,CACzFiI,CAAW,EAAIjI,CAAf,CACA,MAAO1D,CAAAA,CAAC,CAACmD,CAAD,CACX,CAHiB,CAlGyC,CAuGvD2I,CAAc,CAAG3L,CAAS,CAACqD,MAAV,CAAiBrB,CAAO,CAAChC,SAAR,CAAkB4F,WAAnC,CAAgDzC,CAAhD,EAAyDG,IAAzD,CAA8D,SAASN,CAAT,CAAeO,CAAf,CAAmB,CAClGiI,CAAW,EAAIjI,CAAf,CACA,MAAO1D,CAAAA,CAAC,CAACmD,CAAD,CACX,CAHoB,CAvGsC,CA4GvD4I,CAAe,CAAG5L,CAAS,CAACqD,MAAV,CAAiBrB,CAAO,CAAChC,SAAR,CAAkBkL,SAAnC,CAA8C/H,CAA9C,EAAuDG,IAAvD,CAA4D,SAASN,CAAT,CAAeO,CAAf,CAAmB,CACjGiI,CAAW,EAAIjI,CAAf,CACA,MAAO1D,CAAAA,CAAC,CAACmD,CAAD,CACX,CAHqB,CA5GqC,CAiH3D,MAAOnD,CAAAA,CAAC,CAACgM,IAAF,CAAOJ,CAAP,CAAqBC,CAArB,CAAkCC,CAAlC,CAAkDC,CAAlD,EACNtI,IADM,CACD,SAAS2H,CAAT,CAAiBD,CAAjB,CAAwBpF,CAAxB,CAAqCsF,CAArC,CAAgD,CAClDjJ,CAAc,CAACuD,IAAf,GACA,GAAIsG,CAAAA,CAAS,CAAG7J,CAAc,CAACgG,MAAf,EAAhB,CAEA6D,CAAS,CAACzE,MAAV,CAAiB4D,CAAjB,EACAa,CAAS,CAACC,IAAV,CAAe,2CAAf,EAA0DC,WAA1D,CAAsEhB,CAAtE,EACAc,CAAS,CAACC,IAAV,CAAe,iDAAf,EAAgEC,WAAhE,CAA4EpG,CAA5E,EACAkG,CAAS,CAACC,IAAV,CAAe,+CAAf,EAA8DC,WAA9D,CAA0Ed,CAA1E,EAEAlL,CAAS,CAACiM,aAAV,CAAwBT,CAAxB,EAGAD,CAAa,CAAC3J,IAAd,CAAmB,KAAnB,CAA0BV,CAAK,CAACiB,OAAhC,EAEA6G,CAAa,CAAChH,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CAAb,CAEA,GAAIsC,CAAAA,CAAkB,CAAG1E,CAAC,CAACuB,QAAQ,CAACC,cAAT,CAAwBH,CAAK,CAACsD,aAA9B,CAAD,CAA1B,CAEAD,CAAkB,CAACiB,IAAnB,GACArF,CAAI,CAACqF,IAAL,CAAUjB,CAAkB,CAAC7C,GAAnB,EAAV,CAGH,CAvBM,EAwBN4B,IAxBM,CAwBD,UAAW,CAEb,MAAOvB,CAAAA,CAAmB,CAACC,CAAD,CAAUd,CAAV,CAAiBe,CAAjB,CAC7B,CA3BM,EA4BNqB,IA5BM,CA4BD,UAAW,CACb,MAAOlB,CAAAA,CAAC,CAACC,IAAF,CAAOoB,WAAP,CAAmBvB,CAAnB,CACV,CA9BM,EA+BNwB,KA/BM,CA+BA,SAASoF,CAAT,CAAgB,CACnB1G,CAAC,CAACC,IAAF,CAAOoB,WAAP,CAAmBvB,CAAnB,EACAjC,CAAY,CAAC0D,SAAb,CAAuBmF,CAAvB,CACH,CAlCM,CAmCV,CAxK8C,CA0KtD,CAtmCK,CAAN","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Autocomplete wrapper for select2 library.\n *\n * @module     core/form-autocomplete\n * @class      autocomplete\n * @package    core\n * @copyright  2015 Damyon Wiese <damyon@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.0\n */\n/* globals require: false */\ndefine(\n    ['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification', 'core/loadingicon', 'core/aria'],\nfunction($, log, str, templates, notification, LoadingIcon, Aria) {\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        // Count the visible items.\n        var length = selectionElement.children('[aria-selected=true]').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 = $(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\n        return $.Deferred().resolve();\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 = [];\n        var newSelection = $(document.getElementById(state.selectionId));\n        var activeId = newSelection.attr('aria-activedescendant');\n        var activeValue = false;\n\n        if (activeId) {\n            activeValue = $(document.getElementById(activeId)).attr('data-value');\n        }\n        originalSelect.children('option').each(function(index, ele) {\n            if ($(ele).prop('selected')) {\n                var label;\n                if ($(ele).data('html')) {\n                    label = $(ele).data('html');\n                } else {\n                    label = $(ele).html();\n                }\n                if (label !== '') {\n                    items.push({label: label, value: $(ele).attr('value')});\n                }\n            }\n        });\n        var context = $.extend({items: items}, 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            if (activeValue !== false) {\n                // Reselect any previously selected item.\n                newSelection.children('[aria-selected=true]').each(function(index, ele) {\n                    if ($(ele).attr('data-value') === activeValue) {\n                        activateSelection(index, state);\n                    }\n                });\n            }\n\n            return activeValue;\n        })\n        .then(function() {\n            return M.util.js_complete(pendingKey);\n        })\n        .catch(notification.exception);\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        if (typeof M.core_formchangechecker !== 'undefined') {\n            M.core_formchangechecker.set_form_changed();\n        }\n\n        // Note, jQuery .change() was not working here. Better to\n        // use plain JavaScript anyway.\n        originalSelect[0].dispatchEvent(new Event('change'));\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    var deselectItem = function(options, state, item, originalSelect) {\n        var selectedItemValue = $(item).attr('data-value');\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        // Rerender the selection list.\n        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        });\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     * 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        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n        // Activate the next one.\n        return activateItem(current + 1, 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        // Find the list of suggestions.\n        var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n        // Activate the previous one.\n        return activateItem(current - 1, 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 = [];\n        originalSelect.children('option').each(function(index, option) {\n            if ($(option).prop('selected') !== true) {\n                suggestions[suggestions.length] = {label: option.innerHTML, value: $(option).attr('value')};\n            }\n        });\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            suggestionsElement.show();\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    var createItem = function(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 = $('<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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            // Clear the input field.\n            inputElement.val('');\n\n            return;\n        })\n        .then(function() {\n            // Close the suggestions list.\n            return closeSuggestions(state);\n        });\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     * @return {Promise}\n     */\n    var selectCurrentItem = function(options, state, originalSelect) {\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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            if (options.closeSuggestionsOnSelect) {\n                // Clear the input element.\n                inputElement.val('');\n                // Close the list of suggestions.\n                return 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                return updateSuggestions(options, state, inputElement.val(), originalSelect);\n            }\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 currently selected.\n            if (!options.multiple) {\n                originalSelect.children('option').remove();\n            }\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 = $('<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 = $('<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                        // If the suggestion list has an active item, select it.\n                        pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect));\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                return selectCurrentItem(options, state, originalSelect);\n            })\n            .then(function() {\n                return pendingPromise.resolve();\n            })\n            .catch();\n        });\n        var selectionElement = $(document.getElementById(state.selectionId));\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        // When listbox is focused, focus on the first option if there is no focused option.\n        selectionElement.on('focus', function() {\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.length) {\n                return activateSelection(0, 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 false;\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 false;\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 false;\n            }\n\n            // Not handled. Resolve the promise.\n            pendingPromise.resolve();\n            return true;\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    return /** @alias module:core/form-autocomplete */ {\n        // Public variables and functions.\n        /**\n         * Turn a boring select box into an auto-complete beast.\n         *\n         * @method enhance\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} 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} 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        enhance: 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: placeholder,\n                caseSensitive: false,\n                showSuggestions: true,\n                noSelectionString: 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            Aria.hide(originalSelect.get());\n            originalSelect.css('visibility', 'hidden');\n\n            // Hide the original select.\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            };\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('<option>');\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 = [];\n            originalSelect.children('option').each(function(index, option) {\n                suggestions[index] = {label: option.innerHTML, value: $(option).attr('value')};\n            });\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 $.when(renderLayout, renderInput, renderDatalist, renderSelection)\n            .then(function(layout, input, suggestions, selection) {\n                originalSelect.hide();\n                var container = originalSelect.parent();\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"],"file":"form-autocomplete.min.js"}
\ No newline at end of file
diff --git a/lib/amd/src/form-autocomplete.js b/lib/amd/src/form-autocomplete.js
index 83dd16b1b89..72a6e579039 100644
--- a/lib/amd/src/form-autocomplete.js
+++ b/lib/amd/src/form-autocomplete.js
@@ -69,9 +69,11 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
         var itemId = state.selectionId + '-' + index;
 
         // Deselect all the selections.
-        selectionElement.children().attr('data-active-selection', false).attr('id', '');
+        selectionElement.children().attr('data-active-selection', null).attr('id', '');
+
         // Select only this suggestion and assign it the id.
         element.attr('data-active-selection', true).attr('id', itemId);
+
         // Tell the input field it has a new active descendant so the item is announced.
         selectionElement.attr('aria-activedescendant', itemId);
 
@@ -263,7 +265,7 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
         // Find the list of selections.
         var selectionsElement = $(document.getElementById(state.selectionId));
         // Find the active one.
-        var element = selectionsElement.children('[data-active-selection=true]');
+        var element = selectionsElement.children('[data-active-selection]');
         if (!element) {
             return activateSelection(0, state);
         }
@@ -286,7 +288,7 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
         var selectionsElement = $(document.getElementById(state.selectionId));
 
         // Find the active one.
-        var element = selectionsElement.children('[data-active-selection=true]');
+        var element = selectionsElement.children('[data-active-selection]');
         var current = 0;
 
         if (element) {
@@ -817,7 +819,7 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
             // Find the list of selections.
             var selectionsElement = $(document.getElementById(state.selectionId));
             // Find the active one.
-            var element = selectionsElement.children('[data-active-selection=true]');
+            var element = selectionsElement.children('[data-active-selection]');
             if (!element.length) {
                 return activateSelection(0, state);
             }
@@ -845,7 +847,7 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
                 case KEYS.SPACE:
                 case KEYS.ENTER:
                     // Get the item that is currently selected.
-                    var selectedItem = $(document.getElementById(state.selectionId)).children('[data-active-selection=true]');
+                    var selectedItem = $(document.getElementById(state.selectionId)).children('[data-active-selection]');
                     if (selectedItem) {
                         e.preventDefault();
 

From a88838c25f47bc158e6f4bcdada0fac62514c59e Mon Sep 17 00:00:00 2001
From: Andrew Nicols <andrew@nicols.co.uk>
Date: Mon, 2 Nov 2020 15:42:38 +0800
Subject: [PATCH 4/5] MDL-70075 core: Do not return a value in an event handler

Returning a value of `false` in an event handler has the effect of
calling event.preventDefault() and event.stopPropagation().

This is neither obvious, nor desirable in this situation.
---
 lib/amd/build/form-autocomplete.min.js     |  2 +-
 lib/amd/build/form-autocomplete.min.js.map |  2 +-
 lib/amd/src/form-autocomplete.js           | 10 +++++-----
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/amd/build/form-autocomplete.min.js b/lib/amd/build/form-autocomplete.min.js
index fa95f55fc1f..c9f2acaabb4 100644
--- a/lib/amd/build/form-autocomplete.min.js
+++ b/lib/amd/build/form-autocomplete.min.js
@@ -1,2 +1,2 @@
-define ("core/form-autocomplete",["jquery","core/log","core/str","core/templates","core/notification","core/loadingicon","core/aria"],function(a,b,c,d,f,g,h){var i={DOWN:40,ENTER:13,SPACE:32,ESCAPE:27,COMMA:44,UP:38,LEFT:37,RIGHT:39},j=Date.now(),k=function(b,c){var d=a(document.getElementById(c.selectionId)),e=d.children("[aria-selected=true]").length;b=b%e;while(0>b){b+=e}var f=a(d.children("[aria-selected=true]").get(b)),g=c.selectionId+"-"+b;d.children().attr("data-active-selection",null).attr("id","");f.attr("data-active-selection",!0).attr("id",g);d.attr("aria-activedescendant",g);return a.Deferred().resolve()},l=function(b,c,e){var g="form-autocomplete-updateSelectionList-"+c.inputId;M.util.js_pending(g);var h=[],i=a(document.getElementById(c.selectionId)),j=i.attr("aria-activedescendant"),l=!1;if(j){l=a(document.getElementById(j)).attr("data-value")}e.children("option").each(function(b,c){if(a(c).prop("selected")){var d;if(a(c).data("html")){d=a(c).data("html")}else{d=a(c).html()}if(""!==d){h.push({label:d,value:a(c).attr("value")})}}});var m=a.extend({items:h},b,c);return d.render(b.templates.items,m).then(function(b,e){d.replaceNodeContents(i,b,e);if(!1!==l){i.children("[aria-selected=true]").each(function(b,d){if(a(d).attr("data-value")===l){k(b,c)}})}return l}).then(function(){return M.util.js_complete(g)}).catch(f.exception)},m=function(a){if("undefined"!=typeof M.core_formchangechecker){M.core_formchangechecker.set_form_changed()}a[0].dispatchEvent(new Event("change"))},n=function(b,c,d,e){var f=a(d).attr("data-value");e.children("option").each(function(b,c){if(a(c).attr("value")==f){a(c).prop("selected",!1);if(a(c).attr("data-iscustom")){a(c).remove()}}});return l(b,c,e).then(function(){m(e)})},o=function(b,c){var d=a(document.getElementById(c.inputId)),e=a(document.getElementById(c.suggestionsId)),f=e.children(":not([aria-hidden])").length;b=b%f;while(0>b){b+=f}var g=a(e.children(":not([aria-hidden])").get(b)),h=a(e.children("[role=option]")).index(g),i=c.suggestionsId+"-"+h;e.children().attr("aria-selected",!1).attr("id","");g.attr("aria-selected",!0).attr("id",i);d.attr("aria-activedescendant",i);var j=g.offset().top-e.offset().top+e.scrollTop()-e.height()/2;return e.animate({scrollTop:j},100).promise()},p=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return o(e+1,b)},q=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]");if(!d){return k(0,b)}var e=c.children("[aria-selected=true]").index(d);return k(e-1,b)},r=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]"),e=0;if(d){e=c.children("[aria-selected=true]").index(d);e=e+1}else{e=0}return k(e,b)},s=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return o(e-1,b)},t=function(b){var c=a(document.getElementById(b.inputId)),d=a(document.getElementById(b.suggestionsId));if("true"===c.attr("aria-expanded")){c.attr("aria-expanded",!1)}c.attr("aria-activedescendant",b.selectionId);h.hide(d.get());d.hide();return a.Deferred().resolve()},u=function(b,e,g,i){var j="form-autocomplete-updateSuggestions-"+e.inputId;M.util.js_pending(j);var k=a(document.getElementById(e.inputId)),l=a(document.getElementById(e.suggestionsId)),m=!1,n=[];i.children("option").each(function(b,c){if(!0!==a(c).prop("selected")){n[n.length]={label:c.innerHTML,value:a(c).attr("value")}}});var p=e.caseSensitive?g:g.toLocaleLowerCase(),q=a.extend({options:n},b,e),r=d.render("core/form_autocomplete_suggestions",q).then(function(f,g){d.replaceNode(l,f,g);l=a(document.getElementById(e.suggestionsId));h.unhide(l.get());l.show();l.children().each(function(c,d){d=a(d);if(b.caseSensitive&&-1<d.text().indexOf(p)||!b.caseSensitive&&-1<d.text().toLocaleLowerCase().indexOf(p)){h.unhide(d.get());d.show();m=!0}else{d.hide();h.hide(d.get())}});k.attr("aria-expanded",!0);if(i.attr("data-notice")){l.html(i.attr("data-notice"))}else if(m){if(!b.tags){o(0,e)}}else{c.get_string("nosuggestions","form").done(function(a){l.html(a)})}return l}).then(function(){return M.util.js_complete(j)}).catch(f.exception);return r},v=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=e.val(),g=f.split(","),h=!1;a.each(g,function(c,e){e=e.trim();if(""!==e){if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==e){h=!0;a(c).prop("selected",!0)}});if(!h){var f=a("<option>");f.append(document.createTextNode(e));f.attr("value",e);d.append(f);f.prop("selected",!0);f.attr("data-iscustom",!0)}}});return l(b,c,d).then(function(){m(d)}).then(function(){e.val("")}).then(function(){return t(c)})},w=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=a(document.getElementById(c.suggestionsId)),g=f.children("[aria-selected=true]").attr("data-value");if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==g){a(c).prop("selected",!0)}});return l(b,c,d).then(function(){m(d)}).then(function(){if(b.closeSuggestionsOnSelect){e.val("");return t(c)}else{e.focus();return u(b,c,e.val(),d)}})},x=function(b,c,d,e,f){var h=z("updateAjax"),i=a(document.getElementById(d.selectId)).parent();g.addIconToContainerRemoveOnCompletion(i,h);var j=a(b.currentTarget).val();f.transport(c.selector,j,function(b){var g=f.processResults(c.selector,b),i=[];if(!c.multiple){e.children("option").remove()}e.children("option").each(function(b,c){c=a(c);if(!c.prop("selected")){c.remove()}else{i.push(c.attr("value")+"")}});if(!c.multiple&&0===e.children("option").length){var j=a("<option>");e.append(j)}if(a.isArray(g)){a.each(g,function(b,c){if(-1===i.indexOf(c.value+"")){var d=a("<option>");d.append(c.label);d.attr("value",c.value);e.append(d)}});e.attr("data-notice","")}else{e.attr("data-notice",g)}h.resolve(u(c,d,"",e))},function(a){h.reject(a)});return h},y=function(b,c,d){var g=a(document.getElementById(c.inputId));g.on("keydown",function(f){var e=z("addNavigation-"+c.inputId+"-"+f.keyCode);switch(f.keyCode){case i.DOWN:if(!b.showSuggestions){e.resolve();return!0}else if("true"===g.attr("aria-expanded")){e.resolve(p(c))}else{if(!g.val()&&b.ajax){require([b.ajax],function(a){e.resolve(x(f,b,c,d,a))})}else{e.resolve(u(b,c,g.val(),d))}}f.preventDefault();return!1;case i.UP:e.resolve(s(c));f.preventDefault();return!1;case i.ENTER:var h=a(document.getElementById(c.suggestionsId));if("true"===g.attr("aria-expanded")&&0<h.children("[aria-selected=true]").length){e.resolve(w(b,c,d))}else if(b.tags){e.resolve(v(b,c,d))}else{e.resolve()}f.preventDefault();return!1;case i.ESCAPE:if("true"===g.attr("aria-expanded")){e.resolve(t(c))}else{e.resolve()}f.preventDefault();return!1;}e.resolve();return!0});g.on("keypress",function(a){if(a.keyCode===i.COMMA){if(b.tags){z("keypress-"+a.keyCode).resolve(v(b,c,d))}a.preventDefault();return!1}return!0});g.closest("form").on("submit",function(){if(b.tags){z("form-autocomplete-submit").resolve(v(b,c,d))}return!0});g.on("blur",function(){var e=z("form-autocomplete-blur");window.setTimeout(function(){var f=a(document.activeElement),h=a.Deferred();if(f.is(document.getElementById(c.suggestionsId))){g.focus()}else if(!f.is(g)&&a(document.getElementById(c.inputId)).length){if(b.tags){h.then(function(){return v(b,c,d)}).catch()}h.then(function(){return t(c)}).catch()}h.then(function(){return e.resolve()}).catch();h.resolve()},500)});if(b.showSuggestions){var h=a(document.getElementById(c.downArrowId));h.on("click",function(a){var e=z("form-autocomplete-show-suggestions");g.focus();if(!g.val()&&b.ajax){require([b.ajax],function(f){e.resolve(x(a,b,c,d,f))})}else{e.resolve(u(b,c,g.val(),d))}})}var j=a(document.getElementById(c.suggestionsId));j.parent().prop("onclick",null).off("click");j.parent().on("click","#".concat(c.suggestionsId," [role=option]"),function(f){var e=z("form-autocomplete-parent"),g=a(f.currentTarget).closest("[role=option]"),h=a(document.getElementById(c.suggestionsId)),i=h.children(":not([aria-hidden])").index(g);o(i,c).then(function(){return w(b,c,d)}).then(function(){return e.resolve()}).catch()});var l=a(document.getElementById(c.selectionId));l.on("click","[role=option]",function(f){var e=z("form-autocomplete-clicks");e.resolve(n(b,c,a(f.currentTarget),d))});l.on("focus",function(){var b=a(document.getElementById(c.selectionId)),d=b.children("[data-active-selection]");if(!d.length){return k(0,c)}});l.on("keydown",function(f){var e=z("form-autocomplete-keydown-"+f.keyCode);switch(f.keyCode){case i.RIGHT:case i.DOWN:f.preventDefault();e.resolve(r(c));return!1;case i.LEFT:case i.UP:f.preventDefault();e.resolve(q(c));return!1;case i.SPACE:case i.ENTER:var g=a(document.getElementById(c.selectionId)).children("[data-active-selection]");if(g){f.preventDefault();e.resolve(n(b,c,g,d))}return!1;}e.resolve();return!0});if(b.showSuggestions){g.on("focus",function(b){var c=a(b.currentTarget).val();a(b.currentTarget).data("last-value",c)});if(b.ajax){require([b.ajax],function(h){var i=null,j=!1,k="autocomplete-throttledhandler",l=function(a){i=null;j=!0;x(a,b,c,d,h).then(function(){if(null===i){M.util.js_complete(k)}j=!1;return arguments[0]}).catch(f.exception)},m=function(a){window.clearTimeout(i);if(j){i=window.setTimeout(m.bind(this,a),100);return}if(null===i){M.util.js_pending(k)}i=window.setTimeout(l.bind(this,a),300)};g.on("input",function(b){var c=a(b.currentTarget).val(),d=a(b.currentTarget).data("last-value");if(d!==c){m(b)}a(b.currentTarget).data("last-value",c)})})}else{g.on("input",function(f){var e=a(f.currentTarget).val(),g=a(f.currentTarget).data("last-value");if(g!==e){u(b,c,e,d)}a(f.currentTarget).data("last-value",e)})}}},z=function(b){var c="form-autocomplete:"+b;M.util.js_pending(c);var d=a.Deferred();d.then(function(){M.util.js_complete(c);return arguments[0]}).catch(f.exception);return d};return{enhance:function enhance(e,g,i,k,m,n,o,p,q){var r={selector:e,tags:!1,ajax:!1,placeholder:k,caseSensitive:!1,showSuggestions:!0,noSelectionString:o,templates:a.extend({input:"core/form_autocomplete_input",items:"core/form_autocomplete_selection_items",layout:"core/form_autocomplete_layout",selection:"core/form_autocomplete_selection",suggestions:"core/form_autocomplete_suggestions"},q)},s="autocomplete-setup-"+e;M.util.js_pending(s);if("undefined"!=typeof g){r.tags=g}if("undefined"!=typeof i){r.ajax=i}if("undefined"!=typeof m){r.caseSensitive=m}if("undefined"!=typeof n){r.showSuggestions=n}if("undefined"==typeof o){c.get_string("noselection","form").done(function(a){r.noSelectionString=a}).fail(f.exception)}var t=a(e);if(!t){b.debug("Selector not found: "+e);M.util.js_complete(s);return!1}h.hide(t.get());t.css("visibility","hidden");var u={selectId:t.attr("id"),inputId:"form_autocomplete_input-"+j,suggestionsId:"form_autocomplete_suggestions-"+j,selectionId:"form_autocomplete_selection-"+j,downArrowId:"form_autocomplete_downarrow-"+j};j++;r.multiple=t.attr("multiple");if(!r.multiple){t.prepend("<option>")}if("undefined"!=typeof p){r.closeSuggestionsOnSelect=p}else{r.closeSuggestionsOnSelect=!r.multiple}var v=a("[for="+u.selectId+"]"),w=[];t.children("option").each(function(b,c){w[b]={label:c.innerHTML,value:a(c).attr("value")}});var x=a.extend({},r,u);x.options=w;x.items=[];var z="",A=d.render(r.templates.layout,{}).then(function(b){return a(b)}),B=d.render(r.templates.input,x).then(function(b,c){z+=c;return a(b)}),C=d.render(r.templates.suggestions,x).then(function(b,c){z+=c;return a(b)}),D=d.render(r.templates.selection,x).then(function(b,c){z+=c;return a(b)});return a.when(A,B,C,D).then(function(b,c,e,f){t.hide();var g=t.parent();g.append(b);g.find("[data-region=\"form_autocomplete-input\"]").replaceWith(c);g.find("[data-region=\"form_autocomplete-suggestions\"]").replaceWith(e);g.find("[data-region=\"form_autocomplete-selection\"]").replaceWith(f);d.runTemplateJS(z);v.attr("for",u.inputId);y(r,u,t);var i=a(document.getElementById(u.suggestionsId));i.hide();h.hide(i.get())}).then(function(){return l(r,u,t)}).then(function(){return M.util.js_complete(s)}).catch(function(a){M.util.js_complete(s);f.exception(a)})}}});
+define ("core/form-autocomplete",["jquery","core/log","core/str","core/templates","core/notification","core/loadingicon","core/aria"],function(a,b,c,d,f,g,h){var i={DOWN:40,ENTER:13,SPACE:32,ESCAPE:27,COMMA:44,UP:38,LEFT:37,RIGHT:39},j=Date.now(),k=function(b,c){var d=a(document.getElementById(c.selectionId)),e=d.children("[aria-selected=true]").length;b=b%e;while(0>b){b+=e}var f=a(d.children("[aria-selected=true]").get(b)),g=c.selectionId+"-"+b;d.children().attr("data-active-selection",null).attr("id","");f.attr("data-active-selection",!0).attr("id",g);d.attr("aria-activedescendant",g);return a.Deferred().resolve()},l=function(b,c,e){var g="form-autocomplete-updateSelectionList-"+c.inputId;M.util.js_pending(g);var h=[],i=a(document.getElementById(c.selectionId)),j=i.attr("aria-activedescendant"),l=!1;if(j){l=a(document.getElementById(j)).attr("data-value")}e.children("option").each(function(b,c){if(a(c).prop("selected")){var d;if(a(c).data("html")){d=a(c).data("html")}else{d=a(c).html()}if(""!==d){h.push({label:d,value:a(c).attr("value")})}}});var m=a.extend({items:h},b,c);return d.render(b.templates.items,m).then(function(b,e){d.replaceNodeContents(i,b,e);if(!1!==l){i.children("[aria-selected=true]").each(function(b,d){if(a(d).attr("data-value")===l){k(b,c)}})}return l}).then(function(){return M.util.js_complete(g)}).catch(f.exception)},m=function(a){if("undefined"!=typeof M.core_formchangechecker){M.core_formchangechecker.set_form_changed()}a[0].dispatchEvent(new Event("change"))},n=function(b,c,d,e){var f=a(d).attr("data-value");e.children("option").each(function(b,c){if(a(c).attr("value")==f){a(c).prop("selected",!1);if(a(c).attr("data-iscustom")){a(c).remove()}}});return l(b,c,e).then(function(){m(e)})},o=function(b,c){var d=a(document.getElementById(c.inputId)),e=a(document.getElementById(c.suggestionsId)),f=e.children(":not([aria-hidden])").length;b=b%f;while(0>b){b+=f}var g=a(e.children(":not([aria-hidden])").get(b)),h=a(e.children("[role=option]")).index(g),i=c.suggestionsId+"-"+h;e.children().attr("aria-selected",!1).attr("id","");g.attr("aria-selected",!0).attr("id",i);d.attr("aria-activedescendant",i);var j=g.offset().top-e.offset().top+e.scrollTop()-e.height()/2;return e.animate({scrollTop:j},100).promise()},p=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return o(e+1,b)},q=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]");if(!d){return k(0,b)}var e=c.children("[aria-selected=true]").index(d);return k(e-1,b)},r=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]"),e=0;if(d){e=c.children("[aria-selected=true]").index(d);e=e+1}else{e=0}return k(e,b)},s=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return o(e-1,b)},t=function(b){var c=a(document.getElementById(b.inputId)),d=a(document.getElementById(b.suggestionsId));if("true"===c.attr("aria-expanded")){c.attr("aria-expanded",!1)}c.attr("aria-activedescendant",b.selectionId);h.hide(d.get());d.hide();return a.Deferred().resolve()},u=function(b,e,g,i){var j="form-autocomplete-updateSuggestions-"+e.inputId;M.util.js_pending(j);var k=a(document.getElementById(e.inputId)),l=a(document.getElementById(e.suggestionsId)),m=!1,n=[];i.children("option").each(function(b,c){if(!0!==a(c).prop("selected")){n[n.length]={label:c.innerHTML,value:a(c).attr("value")}}});var p=e.caseSensitive?g:g.toLocaleLowerCase(),q=a.extend({options:n},b,e),r=d.render("core/form_autocomplete_suggestions",q).then(function(f,g){d.replaceNode(l,f,g);l=a(document.getElementById(e.suggestionsId));h.unhide(l.get());l.show();l.children().each(function(c,d){d=a(d);if(b.caseSensitive&&-1<d.text().indexOf(p)||!b.caseSensitive&&-1<d.text().toLocaleLowerCase().indexOf(p)){h.unhide(d.get());d.show();m=!0}else{d.hide();h.hide(d.get())}});k.attr("aria-expanded",!0);if(i.attr("data-notice")){l.html(i.attr("data-notice"))}else if(m){if(!b.tags){o(0,e)}}else{c.get_string("nosuggestions","form").done(function(a){l.html(a)})}return l}).then(function(){return M.util.js_complete(j)}).catch(f.exception);return r},v=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=e.val(),g=f.split(","),h=!1;a.each(g,function(c,e){e=e.trim();if(""!==e){if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==e){h=!0;a(c).prop("selected",!0)}});if(!h){var f=a("<option>");f.append(document.createTextNode(e));f.attr("value",e);d.append(f);f.prop("selected",!0);f.attr("data-iscustom",!0)}}});return l(b,c,d).then(function(){m(d)}).then(function(){e.val("")}).then(function(){return t(c)})},w=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=a(document.getElementById(c.suggestionsId)),g=f.children("[aria-selected=true]").attr("data-value");if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==g){a(c).prop("selected",!0)}});return l(b,c,d).then(function(){m(d)}).then(function(){if(b.closeSuggestionsOnSelect){e.val("");return t(c)}else{e.focus();return u(b,c,e.val(),d)}})},x=function(b,c,d,e,f){var h=z("updateAjax"),i=a(document.getElementById(d.selectId)).parent();g.addIconToContainerRemoveOnCompletion(i,h);var j=a(b.currentTarget).val();f.transport(c.selector,j,function(b){var g=f.processResults(c.selector,b),i=[];if(!c.multiple){e.children("option").remove()}e.children("option").each(function(b,c){c=a(c);if(!c.prop("selected")){c.remove()}else{i.push(c.attr("value")+"")}});if(!c.multiple&&0===e.children("option").length){var j=a("<option>");e.append(j)}if(a.isArray(g)){a.each(g,function(b,c){if(-1===i.indexOf(c.value+"")){var d=a("<option>");d.append(c.label);d.attr("value",c.value);e.append(d)}});e.attr("data-notice","")}else{e.attr("data-notice",g)}h.resolve(u(c,d,"",e))},function(a){h.reject(a)});return h},y=function(b,c,d){var g=a(document.getElementById(c.inputId));g.on("keydown",function(f){var e=z("addNavigation-"+c.inputId+"-"+f.keyCode);switch(f.keyCode){case i.DOWN:if(!b.showSuggestions){e.resolve();return!0}else if("true"===g.attr("aria-expanded")){e.resolve(p(c))}else{if(!g.val()&&b.ajax){require([b.ajax],function(a){e.resolve(x(f,b,c,d,a))})}else{e.resolve(u(b,c,g.val(),d))}}f.preventDefault();return!1;case i.UP:e.resolve(s(c));f.preventDefault();return!1;case i.ENTER:var h=a(document.getElementById(c.suggestionsId));if("true"===g.attr("aria-expanded")&&0<h.children("[aria-selected=true]").length){e.resolve(w(b,c,d))}else if(b.tags){e.resolve(v(b,c,d))}else{e.resolve()}f.preventDefault();return!1;case i.ESCAPE:if("true"===g.attr("aria-expanded")){e.resolve(t(c))}else{e.resolve()}f.preventDefault();return!1;}e.resolve();return!0});g.on("keypress",function(a){if(a.keyCode===i.COMMA){if(b.tags){z("keypress-"+a.keyCode).resolve(v(b,c,d))}a.preventDefault();return!1}return!0});g.closest("form").on("submit",function(){if(b.tags){z("form-autocomplete-submit").resolve(v(b,c,d))}return!0});g.on("blur",function(){var e=z("form-autocomplete-blur");window.setTimeout(function(){var f=a(document.activeElement),h=a.Deferred();if(f.is(document.getElementById(c.suggestionsId))){g.focus()}else if(!f.is(g)&&a(document.getElementById(c.inputId)).length){if(b.tags){h.then(function(){return v(b,c,d)}).catch()}h.then(function(){return t(c)}).catch()}h.then(function(){return e.resolve()}).catch();h.resolve()},500)});if(b.showSuggestions){var h=a(document.getElementById(c.downArrowId));h.on("click",function(a){var e=z("form-autocomplete-show-suggestions");g.focus();if(!g.val()&&b.ajax){require([b.ajax],function(f){e.resolve(x(a,b,c,d,f))})}else{e.resolve(u(b,c,g.val(),d))}})}var j=a(document.getElementById(c.suggestionsId));j.parent().prop("onclick",null).off("click");j.parent().on("click","#".concat(c.suggestionsId," [role=option]"),function(f){var e=z("form-autocomplete-parent"),g=a(f.currentTarget).closest("[role=option]"),h=a(document.getElementById(c.suggestionsId)),i=h.children(":not([aria-hidden])").index(g);o(i,c).then(function(){return w(b,c,d)}).then(function(){return e.resolve()}).catch()});var l=a(document.getElementById(c.selectionId));l.on("click","[role=option]",function(f){var e=z("form-autocomplete-clicks");e.resolve(n(b,c,a(f.currentTarget),d))});l.on("focus",function(){var b=a(document.getElementById(c.selectionId)),d=b.children("[data-active-selection]");if(!d.length){k(0,c)}});l.on("keydown",function(f){var e=z("form-autocomplete-keydown-"+f.keyCode);switch(f.keyCode){case i.RIGHT:case i.DOWN:f.preventDefault();e.resolve(r(c));return;case i.LEFT:case i.UP:f.preventDefault();e.resolve(q(c));return;case i.SPACE:case i.ENTER:var g=a(document.getElementById(c.selectionId)).children("[data-active-selection]");if(g){f.preventDefault();e.resolve(n(b,c,g,d))}return;}e.resolve()});if(b.showSuggestions){g.on("focus",function(b){var c=a(b.currentTarget).val();a(b.currentTarget).data("last-value",c)});if(b.ajax){require([b.ajax],function(h){var i=null,j=!1,k="autocomplete-throttledhandler",l=function(a){i=null;j=!0;x(a,b,c,d,h).then(function(){if(null===i){M.util.js_complete(k)}j=!1;return arguments[0]}).catch(f.exception)},m=function(a){window.clearTimeout(i);if(j){i=window.setTimeout(m.bind(this,a),100);return}if(null===i){M.util.js_pending(k)}i=window.setTimeout(l.bind(this,a),300)};g.on("input",function(b){var c=a(b.currentTarget).val(),d=a(b.currentTarget).data("last-value");if(d!==c){m(b)}a(b.currentTarget).data("last-value",c)})})}else{g.on("input",function(f){var e=a(f.currentTarget).val(),g=a(f.currentTarget).data("last-value");if(g!==e){u(b,c,e,d)}a(f.currentTarget).data("last-value",e)})}}},z=function(b){var c="form-autocomplete:"+b;M.util.js_pending(c);var d=a.Deferred();d.then(function(){M.util.js_complete(c);return arguments[0]}).catch(f.exception);return d};return{enhance:function enhance(e,g,i,k,m,n,o,p,q){var r={selector:e,tags:!1,ajax:!1,placeholder:k,caseSensitive:!1,showSuggestions:!0,noSelectionString:o,templates:a.extend({input:"core/form_autocomplete_input",items:"core/form_autocomplete_selection_items",layout:"core/form_autocomplete_layout",selection:"core/form_autocomplete_selection",suggestions:"core/form_autocomplete_suggestions"},q)},s="autocomplete-setup-"+e;M.util.js_pending(s);if("undefined"!=typeof g){r.tags=g}if("undefined"!=typeof i){r.ajax=i}if("undefined"!=typeof m){r.caseSensitive=m}if("undefined"!=typeof n){r.showSuggestions=n}if("undefined"==typeof o){c.get_string("noselection","form").done(function(a){r.noSelectionString=a}).fail(f.exception)}var t=a(e);if(!t){b.debug("Selector not found: "+e);M.util.js_complete(s);return!1}h.hide(t.get());t.css("visibility","hidden");var u={selectId:t.attr("id"),inputId:"form_autocomplete_input-"+j,suggestionsId:"form_autocomplete_suggestions-"+j,selectionId:"form_autocomplete_selection-"+j,downArrowId:"form_autocomplete_downarrow-"+j};j++;r.multiple=t.attr("multiple");if(!r.multiple){t.prepend("<option>")}if("undefined"!=typeof p){r.closeSuggestionsOnSelect=p}else{r.closeSuggestionsOnSelect=!r.multiple}var v=a("[for="+u.selectId+"]"),w=[];t.children("option").each(function(b,c){w[b]={label:c.innerHTML,value:a(c).attr("value")}});var x=a.extend({},r,u);x.options=w;x.items=[];var z="",A=d.render(r.templates.layout,{}).then(function(b){return a(b)}),B=d.render(r.templates.input,x).then(function(b,c){z+=c;return a(b)}),C=d.render(r.templates.suggestions,x).then(function(b,c){z+=c;return a(b)}),D=d.render(r.templates.selection,x).then(function(b,c){z+=c;return a(b)});return a.when(A,B,C,D).then(function(b,c,e,f){t.hide();var g=t.parent();g.append(b);g.find("[data-region=\"form_autocomplete-input\"]").replaceWith(c);g.find("[data-region=\"form_autocomplete-suggestions\"]").replaceWith(e);g.find("[data-region=\"form_autocomplete-selection\"]").replaceWith(f);d.runTemplateJS(z);v.attr("for",u.inputId);y(r,u,t);var i=a(document.getElementById(u.suggestionsId));i.hide();h.hide(i.get())}).then(function(){return l(r,u,t)}).then(function(){return M.util.js_complete(s)}).catch(function(a){M.util.js_complete(s);f.exception(a)})}}});
 //# sourceMappingURL=form-autocomplete.min.js.map
diff --git a/lib/amd/build/form-autocomplete.min.js.map b/lib/amd/build/form-autocomplete.min.js.map
index db1748537db..d4a4e0307ca 100644
--- a/lib/amd/build/form-autocomplete.min.js.map
+++ b/lib/amd/build/form-autocomplete.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/form-autocomplete.js"],"names":["define","$","log","str","templates","notification","LoadingIcon","Aria","KEYS","DOWN","ENTER","SPACE","ESCAPE","COMMA","UP","LEFT","RIGHT","uniqueId","Date","now","activateSelection","index","state","selectionElement","document","getElementById","selectionId","length","children","element","get","itemId","attr","Deferred","resolve","updateSelectionList","options","originalSelect","pendingKey","inputId","M","util","js_pending","items","newSelection","activeId","activeValue","each","ele","prop","label","data","html","push","value","context","extend","render","then","js","replaceNodeContents","js_complete","catch","exception","notifyChange","core_formchangechecker","set_form_changed","dispatchEvent","Event","deselectItem","item","selectedItemValue","remove","activateItem","inputElement","suggestionsElement","suggestionsId","globalIndex","scrollPos","offset","top","scrollTop","height","animate","promise","activateNextItem","current","activatePreviousSelection","selectionsElement","activateNextSelection","activatePreviousItem","closeSuggestions","hide","updateSuggestions","query","matchingElements","suggestions","option","innerHTML","searchquery","caseSensitive","toLocaleLowerCase","returnVal","replaceNode","unhide","show","node","text","indexOf","tags","get_string","done","nosuggestionsstr","createItem","val","split","found","tagindex","tag","trim","multiple","append","createTextNode","selectCurrentItem","closeSuggestionsOnSelect","focus","updateAjax","e","ajaxHandler","pendingPromise","addPendingJSPromise","parentElement","selectId","parent","addIconToContainerRemoveOnCompletion","currentTarget","transport","selector","results","processedResults","processResults","existingValues","optionIndex","isArray","resultIndex","result","error","reject","addNavigation","on","pendingJsPromise","keyCode","showSuggestions","ajax","require","preventDefault","closest","window","setTimeout","focusElement","activeElement","timeoutPromise","is","arrowElement","downArrowId","off","selectedItem","throttleTimeout","inProgress","handler","arguments","throttledHandler","clearTimeout","bind","last","key","enhance","placeholder","noSelectionString","templateOverrides","input","layout","selection","fail","debug","css","prepend","originalLabel","collectedjs","renderLayout","renderInput","renderDatalist","renderSelection","when","container","find","replaceWith","runTemplateJS"],"mappings":"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","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Autocomplete wrapper for select2 library.\n *\n * @module     core/form-autocomplete\n * @class      autocomplete\n * @package    core\n * @copyright  2015 Damyon Wiese <damyon@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.0\n */\n/* globals require: false */\ndefine(\n    ['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification', 'core/loadingicon', 'core/aria'],\nfunction($, log, str, templates, notification, LoadingIcon, Aria) {\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        // Count the visible items.\n        var length = selectionElement.children('[aria-selected=true]').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 = $(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\n        return $.Deferred().resolve();\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 = [];\n        var newSelection = $(document.getElementById(state.selectionId));\n        var activeId = newSelection.attr('aria-activedescendant');\n        var activeValue = false;\n\n        if (activeId) {\n            activeValue = $(document.getElementById(activeId)).attr('data-value');\n        }\n        originalSelect.children('option').each(function(index, ele) {\n            if ($(ele).prop('selected')) {\n                var label;\n                if ($(ele).data('html')) {\n                    label = $(ele).data('html');\n                } else {\n                    label = $(ele).html();\n                }\n                if (label !== '') {\n                    items.push({label: label, value: $(ele).attr('value')});\n                }\n            }\n        });\n        var context = $.extend({items: items}, 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            if (activeValue !== false) {\n                // Reselect any previously selected item.\n                newSelection.children('[aria-selected=true]').each(function(index, ele) {\n                    if ($(ele).attr('data-value') === activeValue) {\n                        activateSelection(index, state);\n                    }\n                });\n            }\n\n            return activeValue;\n        })\n        .then(function() {\n            return M.util.js_complete(pendingKey);\n        })\n        .catch(notification.exception);\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        if (typeof M.core_formchangechecker !== 'undefined') {\n            M.core_formchangechecker.set_form_changed();\n        }\n\n        // Note, jQuery .change() was not working here. Better to\n        // use plain JavaScript anyway.\n        originalSelect[0].dispatchEvent(new Event('change'));\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    var deselectItem = function(options, state, item, originalSelect) {\n        var selectedItemValue = $(item).attr('data-value');\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        // Rerender the selection list.\n        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        });\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     * 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        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n        // Activate the next one.\n        return activateItem(current + 1, 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        // Find the list of suggestions.\n        var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n        // Activate the previous one.\n        return activateItem(current - 1, 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 = [];\n        originalSelect.children('option').each(function(index, option) {\n            if ($(option).prop('selected') !== true) {\n                suggestions[suggestions.length] = {label: option.innerHTML, value: $(option).attr('value')};\n            }\n        });\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            suggestionsElement.show();\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    var createItem = function(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 = $('<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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            // Clear the input field.\n            inputElement.val('');\n\n            return;\n        })\n        .then(function() {\n            // Close the suggestions list.\n            return closeSuggestions(state);\n        });\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     * @return {Promise}\n     */\n    var selectCurrentItem = function(options, state, originalSelect) {\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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            if (options.closeSuggestionsOnSelect) {\n                // Clear the input element.\n                inputElement.val('');\n                // Close the list of suggestions.\n                return 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                return updateSuggestions(options, state, inputElement.val(), originalSelect);\n            }\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 currently selected.\n            if (!options.multiple) {\n                originalSelect.children('option').remove();\n            }\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 = $('<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 = $('<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                        // If the suggestion list has an active item, select it.\n                        pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect));\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                return selectCurrentItem(options, state, originalSelect);\n            })\n            .then(function() {\n                return pendingPromise.resolve();\n            })\n            .catch();\n        });\n        var selectionElement = $(document.getElementById(state.selectionId));\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        // When listbox is focused, focus on the first option if there is no focused option.\n        selectionElement.on('focus', function() {\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.length) {\n                return activateSelection(0, 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 false;\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 false;\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 false;\n            }\n\n            // Not handled. Resolve the promise.\n            pendingPromise.resolve();\n            return true;\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    return /** @alias module:core/form-autocomplete */ {\n        // Public variables and functions.\n        /**\n         * Turn a boring select box into an auto-complete beast.\n         *\n         * @method enhance\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} 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} 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        enhance: 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: placeholder,\n                caseSensitive: false,\n                showSuggestions: true,\n                noSelectionString: 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            Aria.hide(originalSelect.get());\n            originalSelect.css('visibility', 'hidden');\n\n            // Hide the original select.\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            };\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('<option>');\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 = [];\n            originalSelect.children('option').each(function(index, option) {\n                suggestions[index] = {label: option.innerHTML, value: $(option).attr('value')};\n            });\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 $.when(renderLayout, renderInput, renderDatalist, renderSelection)\n            .then(function(layout, input, suggestions, selection) {\n                originalSelect.hide();\n                var container = originalSelect.parent();\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"],"file":"form-autocomplete.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/form-autocomplete.js"],"names":["define","$","log","str","templates","notification","LoadingIcon","Aria","KEYS","DOWN","ENTER","SPACE","ESCAPE","COMMA","UP","LEFT","RIGHT","uniqueId","Date","now","activateSelection","index","state","selectionElement","document","getElementById","selectionId","length","children","element","get","itemId","attr","Deferred","resolve","updateSelectionList","options","originalSelect","pendingKey","inputId","M","util","js_pending","items","newSelection","activeId","activeValue","each","ele","prop","label","data","html","push","value","context","extend","render","then","js","replaceNodeContents","js_complete","catch","exception","notifyChange","core_formchangechecker","set_form_changed","dispatchEvent","Event","deselectItem","item","selectedItemValue","remove","activateItem","inputElement","suggestionsElement","suggestionsId","globalIndex","scrollPos","offset","top","scrollTop","height","animate","promise","activateNextItem","current","activatePreviousSelection","selectionsElement","activateNextSelection","activatePreviousItem","closeSuggestions","hide","updateSuggestions","query","matchingElements","suggestions","option","innerHTML","searchquery","caseSensitive","toLocaleLowerCase","returnVal","replaceNode","unhide","show","node","text","indexOf","tags","get_string","done","nosuggestionsstr","createItem","val","split","found","tagindex","tag","trim","multiple","append","createTextNode","selectCurrentItem","closeSuggestionsOnSelect","focus","updateAjax","e","ajaxHandler","pendingPromise","addPendingJSPromise","parentElement","selectId","parent","addIconToContainerRemoveOnCompletion","currentTarget","transport","selector","results","processedResults","processResults","existingValues","optionIndex","isArray","resultIndex","result","error","reject","addNavigation","on","pendingJsPromise","keyCode","showSuggestions","ajax","require","preventDefault","closest","window","setTimeout","focusElement","activeElement","timeoutPromise","is","arrowElement","downArrowId","off","selectedItem","throttleTimeout","inProgress","handler","arguments","throttledHandler","clearTimeout","bind","last","key","enhance","placeholder","noSelectionString","templateOverrides","input","layout","selection","fail","debug","css","prepend","originalLabel","collectedjs","renderLayout","renderInput","renderDatalist","renderSelection","when","container","find","replaceWith","runTemplateJS"],"mappings":"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","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Autocomplete wrapper for select2 library.\n *\n * @module     core/form-autocomplete\n * @class      autocomplete\n * @package    core\n * @copyright  2015 Damyon Wiese <damyon@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.0\n */\n/* globals require: false */\ndefine(\n    ['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification', 'core/loadingicon', 'core/aria'],\nfunction($, log, str, templates, notification, LoadingIcon, Aria) {\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        // Count the visible items.\n        var length = selectionElement.children('[aria-selected=true]').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 = $(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\n        return $.Deferred().resolve();\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 = [];\n        var newSelection = $(document.getElementById(state.selectionId));\n        var activeId = newSelection.attr('aria-activedescendant');\n        var activeValue = false;\n\n        if (activeId) {\n            activeValue = $(document.getElementById(activeId)).attr('data-value');\n        }\n        originalSelect.children('option').each(function(index, ele) {\n            if ($(ele).prop('selected')) {\n                var label;\n                if ($(ele).data('html')) {\n                    label = $(ele).data('html');\n                } else {\n                    label = $(ele).html();\n                }\n                if (label !== '') {\n                    items.push({label: label, value: $(ele).attr('value')});\n                }\n            }\n        });\n        var context = $.extend({items: items}, 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            if (activeValue !== false) {\n                // Reselect any previously selected item.\n                newSelection.children('[aria-selected=true]').each(function(index, ele) {\n                    if ($(ele).attr('data-value') === activeValue) {\n                        activateSelection(index, state);\n                    }\n                });\n            }\n\n            return activeValue;\n        })\n        .then(function() {\n            return M.util.js_complete(pendingKey);\n        })\n        .catch(notification.exception);\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        if (typeof M.core_formchangechecker !== 'undefined') {\n            M.core_formchangechecker.set_form_changed();\n        }\n\n        // Note, jQuery .change() was not working here. Better to\n        // use plain JavaScript anyway.\n        originalSelect[0].dispatchEvent(new Event('change'));\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    var deselectItem = function(options, state, item, originalSelect) {\n        var selectedItemValue = $(item).attr('data-value');\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        // Rerender the selection list.\n        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        });\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     * 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        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n        // Activate the next one.\n        return activateItem(current + 1, 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        // Find the list of suggestions.\n        var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n        // Activate the previous one.\n        return activateItem(current - 1, 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 = [];\n        originalSelect.children('option').each(function(index, option) {\n            if ($(option).prop('selected') !== true) {\n                suggestions[suggestions.length] = {label: option.innerHTML, value: $(option).attr('value')};\n            }\n        });\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            suggestionsElement.show();\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    var createItem = function(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 = $('<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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            // Clear the input field.\n            inputElement.val('');\n\n            return;\n        })\n        .then(function() {\n            // Close the suggestions list.\n            return closeSuggestions(state);\n        });\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     * @return {Promise}\n     */\n    var selectCurrentItem = function(options, state, originalSelect) {\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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            if (options.closeSuggestionsOnSelect) {\n                // Clear the input element.\n                inputElement.val('');\n                // Close the list of suggestions.\n                return 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                return updateSuggestions(options, state, inputElement.val(), originalSelect);\n            }\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 currently selected.\n            if (!options.multiple) {\n                originalSelect.children('option').remove();\n            }\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 = $('<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 = $('<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                        // If the suggestion list has an active item, select it.\n                        pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect));\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                return selectCurrentItem(options, state, originalSelect);\n            })\n            .then(function() {\n                return pendingPromise.resolve();\n            })\n            .catch();\n        });\n        var selectionElement = $(document.getElementById(state.selectionId));\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        // When listbox is focused, focus on the first option if there is no focused option.\n        selectionElement.on('focus', function() {\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.length) {\n                activateSelection(0, state);\n                return;\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    return /** @alias module:core/form-autocomplete */ {\n        // Public variables and functions.\n        /**\n         * Turn a boring select box into an auto-complete beast.\n         *\n         * @method enhance\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} 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} 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        enhance: 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: placeholder,\n                caseSensitive: false,\n                showSuggestions: true,\n                noSelectionString: 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            Aria.hide(originalSelect.get());\n            originalSelect.css('visibility', 'hidden');\n\n            // Hide the original select.\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            };\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('<option>');\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 = [];\n            originalSelect.children('option').each(function(index, option) {\n                suggestions[index] = {label: option.innerHTML, value: $(option).attr('value')};\n            });\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 $.when(renderLayout, renderInput, renderDatalist, renderSelection)\n            .then(function(layout, input, suggestions, selection) {\n                originalSelect.hide();\n                var container = originalSelect.parent();\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"],"file":"form-autocomplete.min.js"}
\ No newline at end of file
diff --git a/lib/amd/src/form-autocomplete.js b/lib/amd/src/form-autocomplete.js
index 72a6e579039..8c357fbc411 100644
--- a/lib/amd/src/form-autocomplete.js
+++ b/lib/amd/src/form-autocomplete.js
@@ -821,7 +821,8 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
             // Find the active one.
             var element = selectionsElement.children('[data-active-selection]');
             if (!element.length) {
-                return activateSelection(0, state);
+                activateSelection(0, state);
+                return;
             }
         });
         // Keyboard navigation for the selection list.
@@ -835,7 +836,7 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
 
                     // Choose the next selection item.
                     pendingPromise.resolve(activateNextSelection(state));
-                    return false;
+                    return;
                 case KEYS.LEFT:
                 case KEYS.UP:
                     // We handled this event, so prevent it.
@@ -843,7 +844,7 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
 
                     // Choose the previous selection item.
                     pendingPromise.resolve(activatePreviousSelection(state));
-                    return false;
+                    return;
                 case KEYS.SPACE:
                 case KEYS.ENTER:
                     // Get the item that is currently selected.
@@ -854,12 +855,11 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
                         // Unselect this item.
                         pendingPromise.resolve(deselectItem(options, state, selectedItem, originalSelect));
                     }
-                    return false;
+                    return;
             }
 
             // Not handled. Resolve the promise.
             pendingPromise.resolve();
-            return true;
         });
         // Whenever the input field changes, update the suggestion list.
         if (options.showSuggestions) {

From 7d786c79683d951a3e489082d09359f68ca290df Mon Sep 17 00:00:00 2001
From: Andrew Nicols <andrew@nicols.co.uk>
Date: Wed, 4 Nov 2020 11:24:04 +0800
Subject: [PATCH 5/5] MDL-70075 core: Autocomplete selection should always have
 an active item

Ensure that there is always one active element in the list of selected
autocomplete elements.

Without this we have issues beacuse clicking on the link makes the first
one active if one is not already active, and this turns a click event
into a drag event, which means that it is not deleted.
---
 lib/amd/build/form-autocomplete.min.js     |   2 +-
 lib/amd/build/form-autocomplete.min.js.map |   2 +-
 lib/amd/src/form-autocomplete.js           | 105 ++++++++++++++++-----
 3 files changed, 82 insertions(+), 27 deletions(-)

diff --git a/lib/amd/build/form-autocomplete.min.js b/lib/amd/build/form-autocomplete.min.js
index c9f2acaabb4..23e42cba9f7 100644
--- a/lib/amd/build/form-autocomplete.min.js
+++ b/lib/amd/build/form-autocomplete.min.js
@@ -1,2 +1,2 @@
-define ("core/form-autocomplete",["jquery","core/log","core/str","core/templates","core/notification","core/loadingicon","core/aria"],function(a,b,c,d,f,g,h){var i={DOWN:40,ENTER:13,SPACE:32,ESCAPE:27,COMMA:44,UP:38,LEFT:37,RIGHT:39},j=Date.now(),k=function(b,c){var d=a(document.getElementById(c.selectionId)),e=d.children("[aria-selected=true]").length;b=b%e;while(0>b){b+=e}var f=a(d.children("[aria-selected=true]").get(b)),g=c.selectionId+"-"+b;d.children().attr("data-active-selection",null).attr("id","");f.attr("data-active-selection",!0).attr("id",g);d.attr("aria-activedescendant",g);return a.Deferred().resolve()},l=function(b,c,e){var g="form-autocomplete-updateSelectionList-"+c.inputId;M.util.js_pending(g);var h=[],i=a(document.getElementById(c.selectionId)),j=i.attr("aria-activedescendant"),l=!1;if(j){l=a(document.getElementById(j)).attr("data-value")}e.children("option").each(function(b,c){if(a(c).prop("selected")){var d;if(a(c).data("html")){d=a(c).data("html")}else{d=a(c).html()}if(""!==d){h.push({label:d,value:a(c).attr("value")})}}});var m=a.extend({items:h},b,c);return d.render(b.templates.items,m).then(function(b,e){d.replaceNodeContents(i,b,e);if(!1!==l){i.children("[aria-selected=true]").each(function(b,d){if(a(d).attr("data-value")===l){k(b,c)}})}return l}).then(function(){return M.util.js_complete(g)}).catch(f.exception)},m=function(a){if("undefined"!=typeof M.core_formchangechecker){M.core_formchangechecker.set_form_changed()}a[0].dispatchEvent(new Event("change"))},n=function(b,c,d,e){var f=a(d).attr("data-value");e.children("option").each(function(b,c){if(a(c).attr("value")==f){a(c).prop("selected",!1);if(a(c).attr("data-iscustom")){a(c).remove()}}});return l(b,c,e).then(function(){m(e)})},o=function(b,c){var d=a(document.getElementById(c.inputId)),e=a(document.getElementById(c.suggestionsId)),f=e.children(":not([aria-hidden])").length;b=b%f;while(0>b){b+=f}var g=a(e.children(":not([aria-hidden])").get(b)),h=a(e.children("[role=option]")).index(g),i=c.suggestionsId+"-"+h;e.children().attr("aria-selected",!1).attr("id","");g.attr("aria-selected",!0).attr("id",i);d.attr("aria-activedescendant",i);var j=g.offset().top-e.offset().top+e.scrollTop()-e.height()/2;return e.animate({scrollTop:j},100).promise()},p=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return o(e+1,b)},q=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]");if(!d){return k(0,b)}var e=c.children("[aria-selected=true]").index(d);return k(e-1,b)},r=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]"),e=0;if(d){e=c.children("[aria-selected=true]").index(d);e=e+1}else{e=0}return k(e,b)},s=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return o(e-1,b)},t=function(b){var c=a(document.getElementById(b.inputId)),d=a(document.getElementById(b.suggestionsId));if("true"===c.attr("aria-expanded")){c.attr("aria-expanded",!1)}c.attr("aria-activedescendant",b.selectionId);h.hide(d.get());d.hide();return a.Deferred().resolve()},u=function(b,e,g,i){var j="form-autocomplete-updateSuggestions-"+e.inputId;M.util.js_pending(j);var k=a(document.getElementById(e.inputId)),l=a(document.getElementById(e.suggestionsId)),m=!1,n=[];i.children("option").each(function(b,c){if(!0!==a(c).prop("selected")){n[n.length]={label:c.innerHTML,value:a(c).attr("value")}}});var p=e.caseSensitive?g:g.toLocaleLowerCase(),q=a.extend({options:n},b,e),r=d.render("core/form_autocomplete_suggestions",q).then(function(f,g){d.replaceNode(l,f,g);l=a(document.getElementById(e.suggestionsId));h.unhide(l.get());l.show();l.children().each(function(c,d){d=a(d);if(b.caseSensitive&&-1<d.text().indexOf(p)||!b.caseSensitive&&-1<d.text().toLocaleLowerCase().indexOf(p)){h.unhide(d.get());d.show();m=!0}else{d.hide();h.hide(d.get())}});k.attr("aria-expanded",!0);if(i.attr("data-notice")){l.html(i.attr("data-notice"))}else if(m){if(!b.tags){o(0,e)}}else{c.get_string("nosuggestions","form").done(function(a){l.html(a)})}return l}).then(function(){return M.util.js_complete(j)}).catch(f.exception);return r},v=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=e.val(),g=f.split(","),h=!1;a.each(g,function(c,e){e=e.trim();if(""!==e){if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==e){h=!0;a(c).prop("selected",!0)}});if(!h){var f=a("<option>");f.append(document.createTextNode(e));f.attr("value",e);d.append(f);f.prop("selected",!0);f.attr("data-iscustom",!0)}}});return l(b,c,d).then(function(){m(d)}).then(function(){e.val("")}).then(function(){return t(c)})},w=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=a(document.getElementById(c.suggestionsId)),g=f.children("[aria-selected=true]").attr("data-value");if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==g){a(c).prop("selected",!0)}});return l(b,c,d).then(function(){m(d)}).then(function(){if(b.closeSuggestionsOnSelect){e.val("");return t(c)}else{e.focus();return u(b,c,e.val(),d)}})},x=function(b,c,d,e,f){var h=z("updateAjax"),i=a(document.getElementById(d.selectId)).parent();g.addIconToContainerRemoveOnCompletion(i,h);var j=a(b.currentTarget).val();f.transport(c.selector,j,function(b){var g=f.processResults(c.selector,b),i=[];if(!c.multiple){e.children("option").remove()}e.children("option").each(function(b,c){c=a(c);if(!c.prop("selected")){c.remove()}else{i.push(c.attr("value")+"")}});if(!c.multiple&&0===e.children("option").length){var j=a("<option>");e.append(j)}if(a.isArray(g)){a.each(g,function(b,c){if(-1===i.indexOf(c.value+"")){var d=a("<option>");d.append(c.label);d.attr("value",c.value);e.append(d)}});e.attr("data-notice","")}else{e.attr("data-notice",g)}h.resolve(u(c,d,"",e))},function(a){h.reject(a)});return h},y=function(b,c,d){var g=a(document.getElementById(c.inputId));g.on("keydown",function(f){var e=z("addNavigation-"+c.inputId+"-"+f.keyCode);switch(f.keyCode){case i.DOWN:if(!b.showSuggestions){e.resolve();return!0}else if("true"===g.attr("aria-expanded")){e.resolve(p(c))}else{if(!g.val()&&b.ajax){require([b.ajax],function(a){e.resolve(x(f,b,c,d,a))})}else{e.resolve(u(b,c,g.val(),d))}}f.preventDefault();return!1;case i.UP:e.resolve(s(c));f.preventDefault();return!1;case i.ENTER:var h=a(document.getElementById(c.suggestionsId));if("true"===g.attr("aria-expanded")&&0<h.children("[aria-selected=true]").length){e.resolve(w(b,c,d))}else if(b.tags){e.resolve(v(b,c,d))}else{e.resolve()}f.preventDefault();return!1;case i.ESCAPE:if("true"===g.attr("aria-expanded")){e.resolve(t(c))}else{e.resolve()}f.preventDefault();return!1;}e.resolve();return!0});g.on("keypress",function(a){if(a.keyCode===i.COMMA){if(b.tags){z("keypress-"+a.keyCode).resolve(v(b,c,d))}a.preventDefault();return!1}return!0});g.closest("form").on("submit",function(){if(b.tags){z("form-autocomplete-submit").resolve(v(b,c,d))}return!0});g.on("blur",function(){var e=z("form-autocomplete-blur");window.setTimeout(function(){var f=a(document.activeElement),h=a.Deferred();if(f.is(document.getElementById(c.suggestionsId))){g.focus()}else if(!f.is(g)&&a(document.getElementById(c.inputId)).length){if(b.tags){h.then(function(){return v(b,c,d)}).catch()}h.then(function(){return t(c)}).catch()}h.then(function(){return e.resolve()}).catch();h.resolve()},500)});if(b.showSuggestions){var h=a(document.getElementById(c.downArrowId));h.on("click",function(a){var e=z("form-autocomplete-show-suggestions");g.focus();if(!g.val()&&b.ajax){require([b.ajax],function(f){e.resolve(x(a,b,c,d,f))})}else{e.resolve(u(b,c,g.val(),d))}})}var j=a(document.getElementById(c.suggestionsId));j.parent().prop("onclick",null).off("click");j.parent().on("click","#".concat(c.suggestionsId," [role=option]"),function(f){var e=z("form-autocomplete-parent"),g=a(f.currentTarget).closest("[role=option]"),h=a(document.getElementById(c.suggestionsId)),i=h.children(":not([aria-hidden])").index(g);o(i,c).then(function(){return w(b,c,d)}).then(function(){return e.resolve()}).catch()});var l=a(document.getElementById(c.selectionId));l.on("click","[role=option]",function(f){var e=z("form-autocomplete-clicks");e.resolve(n(b,c,a(f.currentTarget),d))});l.on("focus",function(){var b=a(document.getElementById(c.selectionId)),d=b.children("[data-active-selection]");if(!d.length){k(0,c)}});l.on("keydown",function(f){var e=z("form-autocomplete-keydown-"+f.keyCode);switch(f.keyCode){case i.RIGHT:case i.DOWN:f.preventDefault();e.resolve(r(c));return;case i.LEFT:case i.UP:f.preventDefault();e.resolve(q(c));return;case i.SPACE:case i.ENTER:var g=a(document.getElementById(c.selectionId)).children("[data-active-selection]");if(g){f.preventDefault();e.resolve(n(b,c,g,d))}return;}e.resolve()});if(b.showSuggestions){g.on("focus",function(b){var c=a(b.currentTarget).val();a(b.currentTarget).data("last-value",c)});if(b.ajax){require([b.ajax],function(h){var i=null,j=!1,k="autocomplete-throttledhandler",l=function(a){i=null;j=!0;x(a,b,c,d,h).then(function(){if(null===i){M.util.js_complete(k)}j=!1;return arguments[0]}).catch(f.exception)},m=function(a){window.clearTimeout(i);if(j){i=window.setTimeout(m.bind(this,a),100);return}if(null===i){M.util.js_pending(k)}i=window.setTimeout(l.bind(this,a),300)};g.on("input",function(b){var c=a(b.currentTarget).val(),d=a(b.currentTarget).data("last-value");if(d!==c){m(b)}a(b.currentTarget).data("last-value",c)})})}else{g.on("input",function(f){var e=a(f.currentTarget).val(),g=a(f.currentTarget).data("last-value");if(g!==e){u(b,c,e,d)}a(f.currentTarget).data("last-value",e)})}}},z=function(b){var c="form-autocomplete:"+b;M.util.js_pending(c);var d=a.Deferred();d.then(function(){M.util.js_complete(c);return arguments[0]}).catch(f.exception);return d};return{enhance:function enhance(e,g,i,k,m,n,o,p,q){var r={selector:e,tags:!1,ajax:!1,placeholder:k,caseSensitive:!1,showSuggestions:!0,noSelectionString:o,templates:a.extend({input:"core/form_autocomplete_input",items:"core/form_autocomplete_selection_items",layout:"core/form_autocomplete_layout",selection:"core/form_autocomplete_selection",suggestions:"core/form_autocomplete_suggestions"},q)},s="autocomplete-setup-"+e;M.util.js_pending(s);if("undefined"!=typeof g){r.tags=g}if("undefined"!=typeof i){r.ajax=i}if("undefined"!=typeof m){r.caseSensitive=m}if("undefined"!=typeof n){r.showSuggestions=n}if("undefined"==typeof o){c.get_string("noselection","form").done(function(a){r.noSelectionString=a}).fail(f.exception)}var t=a(e);if(!t){b.debug("Selector not found: "+e);M.util.js_complete(s);return!1}h.hide(t.get());t.css("visibility","hidden");var u={selectId:t.attr("id"),inputId:"form_autocomplete_input-"+j,suggestionsId:"form_autocomplete_suggestions-"+j,selectionId:"form_autocomplete_selection-"+j,downArrowId:"form_autocomplete_downarrow-"+j};j++;r.multiple=t.attr("multiple");if(!r.multiple){t.prepend("<option>")}if("undefined"!=typeof p){r.closeSuggestionsOnSelect=p}else{r.closeSuggestionsOnSelect=!r.multiple}var v=a("[for="+u.selectId+"]"),w=[];t.children("option").each(function(b,c){w[b]={label:c.innerHTML,value:a(c).attr("value")}});var x=a.extend({},r,u);x.options=w;x.items=[];var z="",A=d.render(r.templates.layout,{}).then(function(b){return a(b)}),B=d.render(r.templates.input,x).then(function(b,c){z+=c;return a(b)}),C=d.render(r.templates.suggestions,x).then(function(b,c){z+=c;return a(b)}),D=d.render(r.templates.selection,x).then(function(b,c){z+=c;return a(b)});return a.when(A,B,C,D).then(function(b,c,e,f){t.hide();var g=t.parent();g.append(b);g.find("[data-region=\"form_autocomplete-input\"]").replaceWith(c);g.find("[data-region=\"form_autocomplete-suggestions\"]").replaceWith(e);g.find("[data-region=\"form_autocomplete-selection\"]").replaceWith(f);d.runTemplateJS(z);v.attr("for",u.inputId);y(r,u,t);var i=a(document.getElementById(u.suggestionsId));i.hide();h.hide(i.get())}).then(function(){return l(r,u,t)}).then(function(){return M.util.js_complete(s)}).catch(function(a){M.util.js_complete(s);f.exception(a)})}}});
+define ("core/form-autocomplete",["jquery","core/log","core/str","core/templates","core/notification","core/loadingicon","core/aria"],function(a,b,c,d,f,g,h){var i={DOWN:40,ENTER:13,SPACE:32,ESCAPE:27,COMMA:44,UP:38,LEFT:37,RIGHT:39},j=Date.now(),k=function(b,c){var d=a(document.getElementById(c.selectionId)),e=d.children("[aria-selected=true]").length;b=b%e;while(0>b){b+=e}var f=a(d.children("[aria-selected=true]").get(b)),g=c.selectionId+"-"+b;d.children().attr("data-active-selection",null).attr("id","");f.attr("data-active-selection",!0).attr("id",g);d.attr("aria-activedescendant",g);d.attr("data-active-value",f.attr("data-value"));return a.Deferred().resolve()},l=function(b){var c=a(document.getElementById(b.selectionId)),d=c.attr("aria-activedescendant");if(d){var e=a(document.getElementById(d));if(e.length){return e}}var f=c.attr("data-active-value");return c.find("[data-value=\""+f+"\"]")},m=function(b){var c=l(b),d=c.attr("data-value"),e=a(document.getElementById(b.selectionId));if(d){var f=e.find("[aria-selected=true]").index(c);if(-1!==f){k(f,b);return}}k(0,b)},n=function(b,c,e){var g="form-autocomplete-updateSelectionList-"+c.inputId;M.util.js_pending(g);var h=[],i=a(document.getElementById(c.selectionId));e.children("option").each(function(b,c){if(a(c).prop("selected")){var d;if(a(c).data("html")){d=a(c).data("html")}else{d=a(c).html()}if(""!==d){h.push({label:d,value:a(c).attr("value")})}}});if(!o(c,h)){M.util.js_complete(g);return Promise.resolve()}c.items=h;var j=a.extend(b,c);return d.render(b.templates.items,j).then(function(a,b){d.replaceNodeContents(i,a,b);m(c)}).then(function(){return M.util.js_complete(g)}).catch(f.exception)},o=function(a,b){if(a.items.length!==b.length){return!0}return 0<a.items.filter(function(a){return-1===b.indexOf(a)}).length},p=function(a){if("undefined"!=typeof M.core_formchangechecker){M.core_formchangechecker.set_form_changed()}a[0].dispatchEvent(new Event("change"))},q=function(b,c,d,e){var f=a(d).attr("data-value");e.children("option").each(function(b,c){if(a(c).attr("value")==f){a(c).prop("selected",!1);if(a(c).attr("data-iscustom")){a(c).remove()}}});return n(b,c,e).then(function(){p(e)})},r=function(b,c){var d=a(document.getElementById(c.inputId)),e=a(document.getElementById(c.suggestionsId)),f=e.children(":not([aria-hidden])").length;b=b%f;while(0>b){b+=f}var g=a(e.children(":not([aria-hidden])").get(b)),h=a(e.children("[role=option]")).index(g),i=c.suggestionsId+"-"+h;e.children().attr("aria-selected",!1).attr("id","");g.attr("aria-selected",!0).attr("id",i);d.attr("aria-activedescendant",i);var j=g.offset().top-e.offset().top+e.scrollTop()-e.height()/2;return e.animate({scrollTop:j},100).promise()},s=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return r(e+1,b)},t=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]");if(!d){return k(0,b)}var e=c.children("[aria-selected=true]").index(d);return k(e-1,b)},u=function(b){var c=a(document.getElementById(b.selectionId)),d=c.children("[data-active-selection]"),e=0;if(d){e=c.children("[aria-selected=true]").index(d);e=e+1}else{e=0}return k(e,b)},v=function(b){var c=a(document.getElementById(b.suggestionsId)),d=c.children("[aria-selected=true]"),e=c.children(":not([aria-hidden])").index(d);return r(e-1,b)},w=function(b){var c=a(document.getElementById(b.inputId)),d=a(document.getElementById(b.suggestionsId));if("true"===c.attr("aria-expanded")){c.attr("aria-expanded",!1)}c.attr("aria-activedescendant",b.selectionId);h.hide(d.get());d.hide();return a.Deferred().resolve()},x=function(b,e,g,i){var j="form-autocomplete-updateSuggestions-"+e.inputId;M.util.js_pending(j);var k=a(document.getElementById(e.inputId)),l=a(document.getElementById(e.suggestionsId)),m=!1,n=[];i.children("option").each(function(b,c){if(!0!==a(c).prop("selected")){n[n.length]={label:c.innerHTML,value:a(c).attr("value")}}});var o=e.caseSensitive?g:g.toLocaleLowerCase(),p=a.extend({options:n},b,e),q=d.render("core/form_autocomplete_suggestions",p).then(function(f,g){d.replaceNode(l,f,g);l=a(document.getElementById(e.suggestionsId));h.unhide(l.get());l.show();l.children().each(function(c,d){d=a(d);if(b.caseSensitive&&-1<d.text().indexOf(o)||!b.caseSensitive&&-1<d.text().toLocaleLowerCase().indexOf(o)){h.unhide(d.get());d.show();m=!0}else{d.hide();h.hide(d.get())}});k.attr("aria-expanded",!0);if(i.attr("data-notice")){l.html(i.attr("data-notice"))}else if(m){if(!b.tags){r(0,e)}}else{c.get_string("nosuggestions","form").done(function(a){l.html(a)})}return l}).then(function(){return M.util.js_complete(j)}).catch(f.exception);return q},y=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=e.val(),g=f.split(","),h=!1;a.each(g,function(c,e){e=e.trim();if(""!==e){if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==e){h=!0;a(c).prop("selected",!0)}});if(!h){var f=a("<option>");f.append(document.createTextNode(e));f.attr("value",e);d.append(f);f.prop("selected",!0);f.attr("data-iscustom",!0)}}});return n(b,c,d).then(function(){p(d)}).then(function(){e.val("")}).then(function(){return w(c)})},z=function(b,c,d){var e=a(document.getElementById(c.inputId)),f=a(document.getElementById(c.suggestionsId)),g=f.children("[aria-selected=true]").attr("data-value");if(!b.multiple){d.children("option").prop("selected",!1)}d.children("option").each(function(b,c){if(a(c).attr("value")==g){a(c).prop("selected",!0)}});return n(b,c,d).then(function(){p(d)}).then(function(){if(b.closeSuggestionsOnSelect){e.val("");return w(c)}else{e.focus();return x(b,c,e.val(),d)}})},A=function(b,c,d,e,f){var h=C("updateAjax"),i=a(document.getElementById(d.selectId)).parent();g.addIconToContainerRemoveOnCompletion(i,h);var j=a(b.currentTarget).val();f.transport(c.selector,j,function(b){var g=f.processResults(c.selector,b),i=[];if(!c.multiple){e.children("option").remove()}e.children("option").each(function(b,c){c=a(c);if(!c.prop("selected")){c.remove()}else{i.push(c.attr("value")+"")}});if(!c.multiple&&0===e.children("option").length){var j=a("<option>");e.append(j)}if(a.isArray(g)){a.each(g,function(b,c){if(-1===i.indexOf(c.value+"")){var d=a("<option>");d.append(c.label);d.attr("value",c.value);e.append(d)}});e.attr("data-notice","")}else{e.attr("data-notice",g)}h.resolve(x(c,d,"",e))},function(a){h.reject(a)});return h},B=function(b,c,d){var g=a(document.getElementById(c.inputId));g.on("keydown",function(f){var e=C("addNavigation-"+c.inputId+"-"+f.keyCode);switch(f.keyCode){case i.DOWN:if(!b.showSuggestions){e.resolve();return!0}else if("true"===g.attr("aria-expanded")){e.resolve(s(c))}else{if(!g.val()&&b.ajax){require([b.ajax],function(a){e.resolve(A(f,b,c,d,a))})}else{e.resolve(x(b,c,g.val(),d))}}f.preventDefault();return!1;case i.UP:e.resolve(v(c));f.preventDefault();return!1;case i.ENTER:var h=a(document.getElementById(c.suggestionsId));if("true"===g.attr("aria-expanded")&&0<h.children("[aria-selected=true]").length){e.resolve(z(b,c,d))}else if(b.tags){e.resolve(y(b,c,d))}else{e.resolve()}f.preventDefault();return!1;case i.ESCAPE:if("true"===g.attr("aria-expanded")){e.resolve(w(c))}else{e.resolve()}f.preventDefault();return!1;}e.resolve();return!0});g.on("keypress",function(a){if(a.keyCode===i.COMMA){if(b.tags){C("keypress-"+a.keyCode).resolve(y(b,c,d))}a.preventDefault();return!1}return!0});g.closest("form").on("submit",function(){if(b.tags){C("form-autocomplete-submit").resolve(y(b,c,d))}return!0});g.on("blur",function(){var e=C("form-autocomplete-blur");window.setTimeout(function(){var f=a(document.activeElement),h=a.Deferred();if(f.is(document.getElementById(c.suggestionsId))){g.focus()}else if(!f.is(g)&&a(document.getElementById(c.inputId)).length){if(b.tags){h.then(function(){return y(b,c,d)}).catch()}h.then(function(){return w(c)}).catch()}h.then(function(){return e.resolve()}).catch();h.resolve()},500)});if(b.showSuggestions){var h=a(document.getElementById(c.downArrowId));h.on("click",function(a){var e=C("form-autocomplete-show-suggestions");g.focus();if(!g.val()&&b.ajax){require([b.ajax],function(f){e.resolve(A(a,b,c,d,f))})}else{e.resolve(x(b,c,g.val(),d))}})}var j=a(document.getElementById(c.suggestionsId));j.parent().prop("onclick",null).off("click");j.parent().on("click","#".concat(c.suggestionsId," [role=option]"),function(f){var e=C("form-autocomplete-parent"),g=a(f.currentTarget).closest("[role=option]"),h=a(document.getElementById(c.suggestionsId)),i=h.children(":not([aria-hidden])").index(g);r(i,c).then(function(){return z(b,c,d)}).then(function(){return e.resolve()}).catch()});var k=a(document.getElementById(c.selectionId));k.on("click","[role=option]",function(f){var e=C("form-autocomplete-clicks");e.resolve(q(b,c,a(f.currentTarget),d))});k.on("focus",function(){m(c)});k.on("keydown",function(f){var e=C("form-autocomplete-keydown-"+f.keyCode);switch(f.keyCode){case i.RIGHT:case i.DOWN:f.preventDefault();e.resolve(u(c));return;case i.LEFT:case i.UP:f.preventDefault();e.resolve(t(c));return;case i.SPACE:case i.ENTER:var g=a(document.getElementById(c.selectionId)).children("[data-active-selection]");if(g){f.preventDefault();e.resolve(q(b,c,g,d))}return;}e.resolve()});if(b.showSuggestions){g.on("focus",function(b){var c=a(b.currentTarget).val();a(b.currentTarget).data("last-value",c)});if(b.ajax){require([b.ajax],function(h){var i=null,j=!1,k="autocomplete-throttledhandler",l=function(a){i=null;j=!0;A(a,b,c,d,h).then(function(){if(null===i){M.util.js_complete(k)}j=!1;return arguments[0]}).catch(f.exception)},m=function(a){window.clearTimeout(i);if(j){i=window.setTimeout(m.bind(this,a),100);return}if(null===i){M.util.js_pending(k)}i=window.setTimeout(l.bind(this,a),300)};g.on("input",function(b){var c=a(b.currentTarget).val(),d=a(b.currentTarget).data("last-value");if(d!==c){m(b)}a(b.currentTarget).data("last-value",c)})})}else{g.on("input",function(f){var e=a(f.currentTarget).val(),g=a(f.currentTarget).data("last-value");if(g!==e){x(b,c,e,d)}a(f.currentTarget).data("last-value",e)})}}},C=function(b){var c="form-autocomplete:"+b;M.util.js_pending(c);var d=a.Deferred();d.then(function(){M.util.js_complete(c);return arguments[0]}).catch(f.exception);return d};return{enhance:function enhance(e,g,i,k,l,m,o,p,q){var r={selector:e,tags:!1,ajax:!1,placeholder:k,caseSensitive:!1,showSuggestions:!0,noSelectionString:o,templates:a.extend({input:"core/form_autocomplete_input",items:"core/form_autocomplete_selection_items",layout:"core/form_autocomplete_layout",selection:"core/form_autocomplete_selection",suggestions:"core/form_autocomplete_suggestions"},q)},s="autocomplete-setup-"+e;M.util.js_pending(s);if("undefined"!=typeof g){r.tags=g}if("undefined"!=typeof i){r.ajax=i}if("undefined"!=typeof l){r.caseSensitive=l}if("undefined"!=typeof m){r.showSuggestions=m}if("undefined"==typeof o){c.get_string("noselection","form").done(function(a){r.noSelectionString=a}).fail(f.exception)}var t=a(e);if(!t){b.debug("Selector not found: "+e);M.util.js_complete(s);return!1}h.hide(t.get());t.css("visibility","hidden");var u={selectId:t.attr("id"),inputId:"form_autocomplete_input-"+j,suggestionsId:"form_autocomplete_suggestions-"+j,selectionId:"form_autocomplete_selection-"+j,downArrowId:"form_autocomplete_downarrow-"+j,items:[]};j++;r.multiple=t.attr("multiple");if(!r.multiple){t.prepend("<option>")}if("undefined"!=typeof p){r.closeSuggestionsOnSelect=p}else{r.closeSuggestionsOnSelect=!r.multiple}var v=a("[for="+u.selectId+"]"),w=[];t.children("option").each(function(b,c){w[b]={label:c.innerHTML,value:a(c).attr("value")}});var x=a.extend({},r,u);x.options=w;x.items=[];var y="",z=d.render(r.templates.layout,{}).then(function(b){return a(b)}),A=d.render(r.templates.input,x).then(function(b,c){y+=c;return a(b)}),C=d.render(r.templates.suggestions,x).then(function(b,c){y+=c;return a(b)}),D=d.render(r.templates.selection,x).then(function(b,c){y+=c;return a(b)});return a.when(z,A,C,D).then(function(b,c,e,f){t.hide();var g=t.parent();g.append(b);g.find("[data-region=\"form_autocomplete-input\"]").replaceWith(c);g.find("[data-region=\"form_autocomplete-suggestions\"]").replaceWith(e);g.find("[data-region=\"form_autocomplete-selection\"]").replaceWith(f);d.runTemplateJS(y);v.attr("for",u.inputId);B(r,u,t);var i=a(document.getElementById(u.suggestionsId));i.hide();h.hide(i.get())}).then(function(){return n(r,u,t)}).then(function(){return M.util.js_complete(s)}).catch(function(a){M.util.js_complete(s);f.exception(a)})}}});
 //# sourceMappingURL=form-autocomplete.min.js.map
diff --git a/lib/amd/build/form-autocomplete.min.js.map b/lib/amd/build/form-autocomplete.min.js.map
index d4a4e0307ca..5c1fe60e926 100644
--- a/lib/amd/build/form-autocomplete.min.js.map
+++ b/lib/amd/build/form-autocomplete.min.js.map
@@ -1 +1 @@
-{"version":3,"sources":["../src/form-autocomplete.js"],"names":["define","$","log","str","templates","notification","LoadingIcon","Aria","KEYS","DOWN","ENTER","SPACE","ESCAPE","COMMA","UP","LEFT","RIGHT","uniqueId","Date","now","activateSelection","index","state","selectionElement","document","getElementById","selectionId","length","children","element","get","itemId","attr","Deferred","resolve","updateSelectionList","options","originalSelect","pendingKey","inputId","M","util","js_pending","items","newSelection","activeId","activeValue","each","ele","prop","label","data","html","push","value","context","extend","render","then","js","replaceNodeContents","js_complete","catch","exception","notifyChange","core_formchangechecker","set_form_changed","dispatchEvent","Event","deselectItem","item","selectedItemValue","remove","activateItem","inputElement","suggestionsElement","suggestionsId","globalIndex","scrollPos","offset","top","scrollTop","height","animate","promise","activateNextItem","current","activatePreviousSelection","selectionsElement","activateNextSelection","activatePreviousItem","closeSuggestions","hide","updateSuggestions","query","matchingElements","suggestions","option","innerHTML","searchquery","caseSensitive","toLocaleLowerCase","returnVal","replaceNode","unhide","show","node","text","indexOf","tags","get_string","done","nosuggestionsstr","createItem","val","split","found","tagindex","tag","trim","multiple","append","createTextNode","selectCurrentItem","closeSuggestionsOnSelect","focus","updateAjax","e","ajaxHandler","pendingPromise","addPendingJSPromise","parentElement","selectId","parent","addIconToContainerRemoveOnCompletion","currentTarget","transport","selector","results","processedResults","processResults","existingValues","optionIndex","isArray","resultIndex","result","error","reject","addNavigation","on","pendingJsPromise","keyCode","showSuggestions","ajax","require","preventDefault","closest","window","setTimeout","focusElement","activeElement","timeoutPromise","is","arrowElement","downArrowId","off","selectedItem","throttleTimeout","inProgress","handler","arguments","throttledHandler","clearTimeout","bind","last","key","enhance","placeholder","noSelectionString","templateOverrides","input","layout","selection","fail","debug","css","prepend","originalLabel","collectedjs","renderLayout","renderInput","renderDatalist","renderSelection","when","container","find","replaceWith","runTemplateJS"],"mappings":"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","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Autocomplete wrapper for select2 library.\n *\n * @module     core/form-autocomplete\n * @class      autocomplete\n * @package    core\n * @copyright  2015 Damyon Wiese <damyon@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.0\n */\n/* globals require: false */\ndefine(\n    ['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification', 'core/loadingicon', 'core/aria'],\nfunction($, log, str, templates, notification, LoadingIcon, Aria) {\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        // Count the visible items.\n        var length = selectionElement.children('[aria-selected=true]').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 = $(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\n        return $.Deferred().resolve();\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 = [];\n        var newSelection = $(document.getElementById(state.selectionId));\n        var activeId = newSelection.attr('aria-activedescendant');\n        var activeValue = false;\n\n        if (activeId) {\n            activeValue = $(document.getElementById(activeId)).attr('data-value');\n        }\n        originalSelect.children('option').each(function(index, ele) {\n            if ($(ele).prop('selected')) {\n                var label;\n                if ($(ele).data('html')) {\n                    label = $(ele).data('html');\n                } else {\n                    label = $(ele).html();\n                }\n                if (label !== '') {\n                    items.push({label: label, value: $(ele).attr('value')});\n                }\n            }\n        });\n        var context = $.extend({items: items}, 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            if (activeValue !== false) {\n                // Reselect any previously selected item.\n                newSelection.children('[aria-selected=true]').each(function(index, ele) {\n                    if ($(ele).attr('data-value') === activeValue) {\n                        activateSelection(index, state);\n                    }\n                });\n            }\n\n            return activeValue;\n        })\n        .then(function() {\n            return M.util.js_complete(pendingKey);\n        })\n        .catch(notification.exception);\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        if (typeof M.core_formchangechecker !== 'undefined') {\n            M.core_formchangechecker.set_form_changed();\n        }\n\n        // Note, jQuery .change() was not working here. Better to\n        // use plain JavaScript anyway.\n        originalSelect[0].dispatchEvent(new Event('change'));\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    var deselectItem = function(options, state, item, originalSelect) {\n        var selectedItemValue = $(item).attr('data-value');\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        // Rerender the selection list.\n        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        });\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     * 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        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n        // Activate the next one.\n        return activateItem(current + 1, 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        // Find the list of suggestions.\n        var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n        // Activate the previous one.\n        return activateItem(current - 1, 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 = [];\n        originalSelect.children('option').each(function(index, option) {\n            if ($(option).prop('selected') !== true) {\n                suggestions[suggestions.length] = {label: option.innerHTML, value: $(option).attr('value')};\n            }\n        });\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            suggestionsElement.show();\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    var createItem = function(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 = $('<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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            // Clear the input field.\n            inputElement.val('');\n\n            return;\n        })\n        .then(function() {\n            // Close the suggestions list.\n            return closeSuggestions(state);\n        });\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     * @return {Promise}\n     */\n    var selectCurrentItem = function(options, state, originalSelect) {\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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            if (options.closeSuggestionsOnSelect) {\n                // Clear the input element.\n                inputElement.val('');\n                // Close the list of suggestions.\n                return 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                return updateSuggestions(options, state, inputElement.val(), originalSelect);\n            }\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 currently selected.\n            if (!options.multiple) {\n                originalSelect.children('option').remove();\n            }\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 = $('<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 = $('<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                        // If the suggestion list has an active item, select it.\n                        pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect));\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                return selectCurrentItem(options, state, originalSelect);\n            })\n            .then(function() {\n                return pendingPromise.resolve();\n            })\n            .catch();\n        });\n        var selectionElement = $(document.getElementById(state.selectionId));\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        // When listbox is focused, focus on the first option if there is no focused option.\n        selectionElement.on('focus', function() {\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.length) {\n                activateSelection(0, state);\n                return;\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    return /** @alias module:core/form-autocomplete */ {\n        // Public variables and functions.\n        /**\n         * Turn a boring select box into an auto-complete beast.\n         *\n         * @method enhance\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} 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} 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        enhance: 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: placeholder,\n                caseSensitive: false,\n                showSuggestions: true,\n                noSelectionString: 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            Aria.hide(originalSelect.get());\n            originalSelect.css('visibility', 'hidden');\n\n            // Hide the original select.\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            };\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('<option>');\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 = [];\n            originalSelect.children('option').each(function(index, option) {\n                suggestions[index] = {label: option.innerHTML, value: $(option).attr('value')};\n            });\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 $.when(renderLayout, renderInput, renderDatalist, renderSelection)\n            .then(function(layout, input, suggestions, selection) {\n                originalSelect.hide();\n                var container = originalSelect.parent();\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"],"file":"form-autocomplete.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../src/form-autocomplete.js"],"names":["define","$","log","str","templates","notification","LoadingIcon","Aria","KEYS","DOWN","ENTER","SPACE","ESCAPE","COMMA","UP","LEFT","RIGHT","uniqueId","Date","now","activateSelection","index","state","selectionElement","document","getElementById","selectionId","length","children","element","get","itemId","attr","Deferred","resolve","getActiveElementFromState","selectionRegion","activeId","activeElement","activeValue","find","updateActiveSelectionFromState","activeIndex","updateSelectionList","options","originalSelect","pendingKey","inputId","M","util","js_pending","items","newSelection","each","ele","prop","label","data","html","push","value","hasItemListChanged","js_complete","Promise","context","extend","render","then","js","replaceNodeContents","catch","exception","filter","item","indexOf","notifyChange","core_formchangechecker","set_form_changed","dispatchEvent","Event","deselectItem","selectedItemValue","remove","activateItem","inputElement","suggestionsElement","suggestionsId","globalIndex","scrollPos","offset","top","scrollTop","height","animate","promise","activateNextItem","current","activatePreviousSelection","selectionsElement","activateNextSelection","activatePreviousItem","closeSuggestions","hide","updateSuggestions","query","matchingElements","suggestions","option","innerHTML","searchquery","caseSensitive","toLocaleLowerCase","returnVal","replaceNode","unhide","show","node","text","tags","get_string","done","nosuggestionsstr","createItem","val","split","found","tagindex","tag","trim","multiple","append","createTextNode","selectCurrentItem","closeSuggestionsOnSelect","focus","updateAjax","e","ajaxHandler","pendingPromise","addPendingJSPromise","parentElement","selectId","parent","addIconToContainerRemoveOnCompletion","currentTarget","transport","selector","results","processedResults","processResults","existingValues","optionIndex","isArray","resultIndex","result","error","reject","addNavigation","on","pendingJsPromise","keyCode","showSuggestions","ajax","require","preventDefault","closest","window","setTimeout","focusElement","timeoutPromise","is","arrowElement","downArrowId","off","selectedItem","throttleTimeout","inProgress","handler","arguments","throttledHandler","clearTimeout","bind","last","key","enhance","placeholder","noSelectionString","templateOverrides","input","layout","selection","fail","debug","css","prepend","originalLabel","collectedjs","renderLayout","renderInput","renderDatalist","renderSelection","when","container","replaceWith","runTemplateJS"],"mappings":"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","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 <http://www.gnu.org/licenses/>.\n\n/**\n * Autocomplete wrapper for select2 library.\n *\n * @module     core/form-autocomplete\n * @class      autocomplete\n * @package    core\n * @copyright  2015 Damyon Wiese <damyon@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.0\n */\n/* globals require: false */\ndefine(\n    ['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification', 'core/loadingicon', 'core/aria'],\nfunction($, log, str, templates, notification, LoadingIcon, Aria) {\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        // Count the visible items.\n        var length = selectionElement.children('[aria-selected=true]').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 = $(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        var activeValue = selectionRegion.attr('data-active-value');\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 = [];\n        var newSelection = $(document.getElementById(state.selectionId));\n        originalSelect.children('option').each(function(index, ele) {\n            if ($(ele).prop('selected')) {\n                var label;\n                if ($(ele).data('html')) {\n                    label = $(ele).data('html');\n                } else {\n                    label = $(ele).html();\n                }\n                if (label !== '') {\n                    items.push({label: label, value: $(ele).attr('value')});\n                }\n            }\n        });\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     */\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        if (typeof M.core_formchangechecker !== 'undefined') {\n            M.core_formchangechecker.set_form_changed();\n        }\n\n        // Note, jQuery .change() was not working here. Better to\n        // use plain JavaScript anyway.\n        originalSelect[0].dispatchEvent(new Event('change'));\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    var deselectItem = function(options, state, item, originalSelect) {\n        var selectedItemValue = $(item).attr('data-value');\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        // Rerender the selection list.\n        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        });\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     * 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        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n        // Activate the next one.\n        return activateItem(current + 1, 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        // Find the list of suggestions.\n        var suggestionsElement = $(document.getElementById(state.suggestionsId));\n\n        // Find the active one.\n        var element = suggestionsElement.children('[aria-selected=true]');\n\n        // Find it's index.\n        var current = suggestionsElement.children(':not([aria-hidden])').index(element);\n\n        // Activate the previous one.\n        return activateItem(current - 1, 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 = [];\n        originalSelect.children('option').each(function(index, option) {\n            if ($(option).prop('selected') !== true) {\n                suggestions[suggestions.length] = {label: option.innerHTML, value: $(option).attr('value')};\n            }\n        });\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            suggestionsElement.show();\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    var createItem = function(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 = $('<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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            // Clear the input field.\n            inputElement.val('');\n\n            return;\n        })\n        .then(function() {\n            // Close the suggestions list.\n            return closeSuggestions(state);\n        });\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     * @return {Promise}\n     */\n    var selectCurrentItem = function(options, state, originalSelect) {\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        return updateSelectionList(options, state, originalSelect)\n        .then(function() {\n            // Notify that the selection changed.\n            notifyChange(originalSelect);\n\n            return;\n        })\n        .then(function() {\n            if (options.closeSuggestionsOnSelect) {\n                // Clear the input element.\n                inputElement.val('');\n                // Close the list of suggestions.\n                return 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                return updateSuggestions(options, state, inputElement.val(), originalSelect);\n            }\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 currently selected.\n            if (!options.multiple) {\n                originalSelect.children('option').remove();\n            }\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 = $('<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 = $('<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                        // If the suggestion list has an active item, select it.\n                        pendingJsPromise.resolve(selectCurrentItem(options, state, originalSelect));\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                return selectCurrentItem(options, state, originalSelect);\n            })\n            .then(function() {\n                return pendingPromise.resolve();\n            })\n            .catch();\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    return /** @alias module:core/form-autocomplete */ {\n        // Public variables and functions.\n        /**\n         * Turn a boring select box into an auto-complete beast.\n         *\n         * @method enhance\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} 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} 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        enhance: 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: placeholder,\n                caseSensitive: false,\n                showSuggestions: true,\n                noSelectionString: 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            Aria.hide(originalSelect.get());\n            originalSelect.css('visibility', 'hidden');\n\n            // Hide the original select.\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            };\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('<option>');\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 = [];\n            originalSelect.children('option').each(function(index, option) {\n                suggestions[index] = {label: option.innerHTML, value: $(option).attr('value')};\n            });\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 $.when(renderLayout, renderInput, renderDatalist, renderSelection)\n            .then(function(layout, input, suggestions, selection) {\n                originalSelect.hide();\n                var container = originalSelect.parent();\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"],"file":"form-autocomplete.min.js"}
\ No newline at end of file
diff --git a/lib/amd/src/form-autocomplete.js b/lib/amd/src/form-autocomplete.js
index 8c357fbc411..f7f0f211a04 100644
--- a/lib/amd/src/form-autocomplete.js
+++ b/lib/amd/src/form-autocomplete.js
@@ -76,10 +76,58 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
 
         // Tell the input field it has a new active descendant so the item is announced.
         selectionElement.attr('aria-activedescendant', itemId);
+        selectionElement.attr('data-active-value', element.attr('data-value'));
 
         return $.Deferred().resolve();
     };
 
+    /**
+     * Get the actively selected element from the state object.
+     *
+     * @param   {Object} state
+     * @returns {jQuery}
+     */
+    var getActiveElementFromState = function(state) {
+        var selectionRegion = $(document.getElementById(state.selectionId));
+        var activeId = selectionRegion.attr('aria-activedescendant');
+
+        if (activeId) {
+            var activeElement = $(document.getElementById(activeId));
+            if (activeElement.length) {
+                // The active descendent still exists.
+                return activeElement;
+            }
+        }
+
+        var activeValue = selectionRegion.attr('data-active-value');
+        return selectionRegion.find('[data-value="' + activeValue + '"]');
+    };
+
+    /**
+     * Update the active selection from the given state object.
+     *
+     * @param   {Object} state
+     */
+    var updateActiveSelectionFromState = function(state) {
+        var activeElement = getActiveElementFromState(state);
+        var activeValue = activeElement.attr('data-value');
+
+        var selectionRegion = $(document.getElementById(state.selectionId));
+        if (activeValue) {
+            // Find the index of the currently selected index.
+            var activeIndex = selectionRegion.find('[aria-selected=true]').index(activeElement);
+
+            if (activeIndex !== -1) {
+                activateSelection(activeIndex, state);
+                return;
+            }
+        }
+
+        // Either the active index was not set, or it could not be found.
+        // Select the first value instead.
+        activateSelection(0, state);
+    };
+
     /**
      * Update the element that shows the currently selected items.
      *
@@ -97,12 +145,6 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
         // Build up a valid context to re-render the template.
         var items = [];
         var newSelection = $(document.getElementById(state.selectionId));
-        var activeId = newSelection.attr('aria-activedescendant');
-        var activeValue = false;
-
-        if (activeId) {
-            activeValue = $(document.getElementById(activeId)).attr('data-value');
-        }
         originalSelect.children('option').each(function(index, ele) {
             if ($(ele).prop('selected')) {
                 var label;
@@ -116,23 +158,24 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
                 }
             }
         });
-        var context = $.extend({items: items}, options, state);
+
+        if (!hasItemListChanged(state, items)) {
+            M.util.js_complete(pendingKey);
+            return Promise.resolve();
+        }
+
+        state.items = items;
+
+        var context = $.extend(options, state);
         // Render the template.
         return templates.render(options.templates.items, context)
         .then(function(html, js) {
             // Add it to the page.
             templates.replaceNodeContents(newSelection, html, js);
 
-            if (activeValue !== false) {
-                // Reselect any previously selected item.
-                newSelection.children('[aria-selected=true]').each(function(index, ele) {
-                    if ($(ele).attr('data-value') === activeValue) {
-                        activateSelection(index, state);
-                    }
-                });
-            }
+            updateActiveSelectionFromState(state);
 
-            return activeValue;
+            return;
         })
         .then(function() {
             return M.util.js_complete(pendingKey);
@@ -140,6 +183,21 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
         .catch(notification.exception);
     };
 
+    /**
+     * Check whether the list of items stored in the state has changed.
+     *
+     * @param   {Object} state
+     * @param   {Array} items
+     */
+    var hasItemListChanged = function(state, items) {
+        if (state.items.length !== items.length) {
+            return true;
+        }
+
+        // Check for any items in the state items which are not present in the new items list.
+        return state.items.filter(item => items.indexOf(item) === -1).length > 0;
+    };
+
     /**
      * Notify of a change in the selection.
      *
@@ -807,6 +865,7 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
             .catch();
         });
         var selectionElement = $(document.getElementById(state.selectionId));
+
         // Handle clicks on the selected items (will unselect an item).
         selectionElement.on('click', '[role=option]', function(e) {
             var pendingPromise = addPendingJSPromise('form-autocomplete-clicks');
@@ -814,17 +873,12 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
             // Remove it from the selection.
             pendingPromise.resolve(deselectItem(options, state, $(e.currentTarget), originalSelect));
         });
+
         // When listbox is focused, focus on the first option if there is no focused option.
         selectionElement.on('focus', function() {
-            // Find the list of selections.
-            var selectionsElement = $(document.getElementById(state.selectionId));
-            // Find the active one.
-            var element = selectionsElement.children('[data-active-selection]');
-            if (!element.length) {
-                activateSelection(0, state);
-                return;
-            }
+            updateActiveSelectionFromState(state);
         });
+
         // Keyboard navigation for the selection list.
         selectionElement.on('keydown', function(e) {
             var pendingPromise = addPendingJSPromise('form-autocomplete-keydown-' + e.keyCode);
@@ -1057,7 +1111,8 @@ function($, log, str, templates, notification, LoadingIcon, Aria) {
                 inputId: 'form_autocomplete_input-' + uniqueId,
                 suggestionsId: 'form_autocomplete_suggestions-' + uniqueId,
                 selectionId: 'form_autocomplete_selection-' + uniqueId,
-                downArrowId: 'form_autocomplete_downarrow-' + uniqueId
+                downArrowId: 'form_autocomplete_downarrow-' + uniqueId,
+                items: [],
             };
 
             // Increment the unique counter so we don't get duplicates ever.