1!function(t){var e={};function n(i){if(e[i])return e[i].exports;var s=e[i]={i:i,l:!1,exports:{}};return t[i].call(s.exports,s,s.exports,n),s.l=!0,s.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var s in t)n.d(i,s,function(e){return t[e]}.bind(null,s));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=0)}({
1"./JavaScript/Frontend/components/filter.js": 2/*!**************************************************!*\ 3 !*** ./JavaScript/Frontend/components/filter.js ***! 4 \**************************************************/ 5/*! exports provided: Filter */function(module,__webpack_exports__,__webpack_require__){"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Filter\", function() { return Filter; });\n/* harmony import */ var _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utility/urlUtility */ \"./JavaScript/Frontend/utility/urlUtility.js\");\n/* harmony import */ var _utility_loaderUtility__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utility/loaderUtility */ \"./JavaScript/Frontend/utility/loaderUtility.js\");\n/* harmony import */ var _utility_arrayUtility__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utility/arrayUtility */ \"./JavaScript/Frontend/utility/arrayUtility.js\");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\nvar Filter = /*#__PURE__*/function () {\n function Filter(pluginContainer) {\n _classCallCheck(this, Filter);\n this.identifier = {\n container: '.in2studyfinder',\n filterContainer: '.js-in2studyfinder-filter',\n showFilterButton: '.js-in2studyfinder-filter-button-show',\n hideFilterButton: '.js-in2studyfinder-filter-button-reset',\n filterSectionContainer: '.js-in2studyfinder-filter-section-container',\n filterOptionContainer: '.js-in2studyfinder-filter-options',\n filterSection: '.js-in2studyfinder-filter-section',\n filterCheckbox: '.js-in2studyfinder-checkbox',\n filterShowAllCheckbox: '.js-in2studyfinder-checkbox-all',\n filterRadio: '.js-in2studyfinder-radio',\n filterLegend: '.js-in2studyfinder-filter-legend',\n hideElement: '.u-in2studyfinder-hide'\n };\n this.filter = [];\n this.studyfinderElement = pluginContainer;\n this.filterElement = pluginContainer.querySelector(this.identifier.filterContainer);\n this.openFilterOnLoad = true;\n }\n _createClass(Filter, [{\n key: \"init\",\n value: function init() {\n this.setEventListener();\n this.prepareFilter();\n var hashArguments = _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__[\"UrlUtility\"].getHashArgumentsFromUrl();\n if (hashArguments.length > 0) {\n this.updateFilterByHashArguments(hashArguments);\n }\n }\n }, {\n key: \"update\",\n value: function update(studyfinderElement) {\n this.filterElement = studyfinderElement.querySelector(this.identifier.filterContainer);\n this.setEventListener();\n this.prepareFilter();\n }\n }, {\n key: \"setEventListener\",\n value: function setEventListener() {\n // hide filter button\n this.filterElement.querySelector(this.identifier.hideFilterButton).addEventListener('click', function (event) {\n if (this.filter.length === 0) {\n this.toggleFilterVisibility();\n } else {\n this.resetAllFilter(event);\n this.call();\n }\n }.bind(this));\n\n // show filter button\n this.filterElement.querySelector(this.identifier.showFilterButton).addEventListener('click', function (event) {\n this.toggleFilterVisibility(event);\n }.bind(this));\n this.filterElement.querySelectorAll(this.identifier.filterSection).forEac
5h(function (fieldSet) {\n // visibility toggle of filter sections\n fieldSet.querySelector(this.identifier.filterLegend).addEventListener('click', function (event) {\n event.target.nextElementSibling.classList.toggle(this.identifier.hideElement.substring(1));\n }.bind(this));\n\n // tab navigation for filter\n fieldSet.addEventListener('keypress', function (event) {\n if (event.which === 13) {\n event.target.querySelector(this.identifier.filterLegend).click();\n }\n }.bind(this));\n }.bind(this));\n\n // set eventListener for filter checkboxes\n this.setFilterCheckboxEventListener();\n }\n }, {\n key: \"prepareFilter\",\n value: function prepareFilter() {\n this.prepareCheckboxes();\n\n // open selected filter sections\n if (this.filter.length > 0 && this.openFilterOnLoad) {\n this.toggleFilterVisibility();\n this.filter.forEach(function (filterName) {\n var filterFieldset = this.filterElement.querySelector('[data-filtergroup=\"' + filterName + '\"]');\n var filter = filterFieldset.querySelector(this.identifier.filterOptionContainer);\n filter.classList.toggle(this.identifier.hideElement.substring(1));\n }.bind(this));\n }\n }\n }, {\n key: \"prepareCheckboxes\",\n value: function prepareCheckboxes() {\n this.filterElement.querySelectorAll(this.identifier.filterOptionContainer).forEach(function (filterOptionContainer) {\n var filterStatus = this.isFilterSet(filterOptionContainer);\n if (filterStatus) {\n if (this.filter.indexOf(filterOptionContainer.closest('[data-filtergroup]').getAttribute('data-filtergroup')) === -1) {\n this.filter.push(filterOptionContainer.closest('[data-filtergroup]').getAttribute('data-filtergroup'));\n }\n var showAllCheckbox = filterOptionContainer.querySelector(this.identifier.filterShowAllCheckbox);\n showAllCheckbox.checked = false;\n showAllCheckbox.disabled = false;\n } else {\n var index = this.filter.indexOf(filterOptionContainer.closest('[data-filtergroup]').getAttribute('data-filtergroup'));\n if (index !== -1) {\n this.filter.splice(index, 1);\n }\n }\n }.bind(this));\n }\n }, {\n key: \"call\",\n value: function call(paginationPage) {\n var _this = this;\n var pid = this.filterElement.querySelector('input[name=\"tx_in2studyfinder_pi1[pluginInformation][pid]\"]').value;\n var language = this.filterElement.querySelector('input[name=\"tx_in2studyfinder_pi1[pluginInformation][languageUid]\"]').value;\n var paginationArgument = '';\n var instanceId = this.studyfinderElement.getAttribute('data-in2studyfinder-instance-id');\n if (typeof paginationPage === 'undefined') {\n paginationPage = 1;\n }\n if (typeof paginationPage !== 'undefined') {\n paginationArgument = '&tx_in2studyfinder_pi1[studyCoursesForPage][currentPage]=' + paginationPage;\n }\n _utility_loaderUtility__WEBPACK_IMPORTED_MODULE_1__[\"LoaderUtility\"].enableLoader();\n fetch('/index.php?id=' + pid + '&L=' + language + '&type=1308171055' + paginationArgument, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded'\n },\n body: _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__[\"UrlUtility\"].serialize(this.filterElement)\n }).then(function (response) {\n return response.text();\n }).then(function (html) {\n _this.setSelectedFilterToUrl(paginationPage);\n var tempElement = document.createElement('div');\n tempElement.innerHTML = html;\n _this.studyfinderElement.innerHTML = tempElement.querySelector(_this.identifier.container).innerHTML;\n _utility_loaderUtility__WEBPACK_IMPORTED_MODULE_1__[\"LoaderUtility\"].disableLoader();\n window.in2studyfinder.getInstance(instanceId).update(_this.studyfinderElement);\n });\n }\n }, {\n key: \"setSelectedFilterToUrl\",\n value: function setSelectedFilterToUrl(paginationPage) {\n var selectionString = '';\n var filterFieldSets = this.filterElement.querySelectorAll(this.identifier.filterSection);
5\n filterFieldSets.forEach(function (filterFieldSet) {\n var selectedOptions = filterFieldSet.querySelectorAll(this.identifier.filterCheckbox + ':checked, ' + this.identifier.filterRadio + ':checked');\n if (selectedOptions.length > 0) {\n selectionString += filterFieldSet.getAttribute('data-filtergroup') + '=';\n for (var j = 0; j < selectedOptions.length; j++) {\n selectionString += selectedOptions[j].value + '+';\n }\n if (selectedOptions.length >= 1) {\n selectionString = selectionString.substring(0, selectionString.length - 1);\n }\n selectionString += '&';\n }\n }.bind(this));\n selectionString = selectionString.slice(0, -1);\n if (paginationPage && parseInt(paginationPage) > 1) {\n selectionString += 'page=' + paginationPage;\n }\n if (selectionString !== '') {\n selectionString = '#' + selectionString;\n }\n var url = location.protocol + '//' + location.host + location.pathname + (location.search ? location.search : '') + selectionString;\n history.pushState({}, '', url);\n }\n }, {\n key: \"updateFilterByHashArguments\",\n value: function updateFilterByHashArguments(hashArguments) {\n var page = 1;\n hashArguments.forEach(function (hashArgument) {\n // if argument page is set\n if (hashArgument.name === 'page') {\n page = hashArgument.values[0];\n } else {\n if (this.filterElement.querySelector('[data-filtergroup=\"' + hashArgument.name + '\"]') !== null) {\n // set the selected filters\n var filterFieldset = this.filterElement.querySelector('[data-filtergroup=\"' + hashArgument.name + '\"]');\n var checkboxes = filterFieldset.querySelectorAll('input[type=checkbox],input[type=radio]');\n var status = false;\n for (var j = 0; j < checkboxes.length; j++) {\n if (_utility_arrayUtility__WEBPACK_IMPORTED_MODULE_2__[\"ArrayUtility\"].isInArray(checkboxes[j].value, hashArgument.values)) {\n checkboxes[j].checked = true;\n status = true;\n }\n }\n if (status) {\n filterFieldset.querySelector(this.identifier.filterShowAllCheckbox).checked = false;\n }\n }\n }\n }.bind(this));\n this.call(page);\n }\n }, {\n key: \"setFilterCheckboxEventListener\",\n value: function setFilterCheckboxEventListener() {\n this.filterElement.querySelector(this.identifier.filterSectionContainer).addEventListener('click', function (evt) {\n var target = evt.target;\n if (target.tagName === 'INPUT') {\n // if a show all checkbox is clicked\n if (target.classList.contains(this.identifier.filterShowAllCheckbox.substring(1))) {\n this.onClick(evt);\n var filterContainer = target.closest(this.identifier.filterOptionContainer);\n this.resetFilter(filterContainer);\n }\n\n // if a specific filter checkbox is clicked\n if (target.classList.contains(this.identifier.filterCheckbox.substring(1)) || target.classList.contains(this.identifier.filterRadio.substring(1))) {\n var showAllCheckbox = target.closest(this.identifier.filterOptionContainer).querySelector(this.identifier.filterShowAllCheckbox);\n this.onClick(evt);\n showAllCheckbox.checked = false;\n showAllCheckbox.disabled = false;\n }\n this.call();\n }\n }.bind(this));\n }\n }, {\n key: \"toggleFilterVisibility\",\n value: function toggleFilterVisibility() {\n // toggle fieldset Visibility\n var filterFieldSets = this.filterElement.querySelectorAll(this.identifier.filterSection);\n for (var i = 0; i < filterFieldSets.length; i++) {\n filterFieldSets[i].classList.toggle(this.identifier.hideElement.substring(1));\n }\n\n // toggle button Visibility\n this.filterElement.querySelector(this.identifier.showFilterButton).classList.toggle(this.identifier.hideElement.substring(1));\n this.filterElement.querySelector(this.identifier.hideFilterButton).classList.toggle(this.identifier.hideElement.substring(1));\n }\n }, {\n key: \"resetAllFilter\",\n value: function resetAllFilter() {\n var filterSection = this.filterElement.querySelectorAll(this.identifier.filterSection);\n for (var i = 0; i < filterSection.length;
5 i++) {\n this.resetFilter(filterSection[i]);\n }\n }\n }, {\n key: \"resetFilter\",\n value: function resetFilter(filterSection) {\n var showAllCheckbox = filterSection.querySelector(this.identifier.filterShowAllCheckbox);\n var checkboxes = filterSection.querySelectorAll(this.identifier.filterCheckbox);\n showAllCheckbox.checked = true;\n showAllCheckbox.disabled = true;\n for (var i = 0; i < checkboxes.length; i++) {\n checkboxes[i].checked = false;\n }\n var index = this.filter.indexOf(filterSection.getAttribute('data-filtergroup'));\n if (index !== -1) {\n this.filter.splice(index, 1);\n }\n }\n\n /**\n * checks if a given filter element is set\n *\n * @param filterOptionContainer\n * @returns {boolean}\n */\n }, {\n key: \"isFilterSet\",\n value: function isFilterSet(filterOptionContainer) {\n var status = false;\n var filterCheckboxes = filterOptionContainer.querySelectorAll(this.identifier.filterCheckbox + ', ' + this.identifier.filterRadio);\n for (var i = 0; i < filterCheckboxes.length; i++) {\n if (filterCheckboxes[i].checked) {\n status = true;\n }\n }\n return status;\n }\n }, {\n key: \"onClick\",\n value: function onClick() {}\n }]);\n return Filter;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/components/filter.js?")},
5"./JavaScript/Frontend/components/instance.js": 6/*!****************************************************!*\ 7 !*** ./JavaScript/Frontend/components/instance.js ***! 8 \****************************************************/ 9/*! exports provided: Instance */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Instance", function() { return Instance; });\n/* harmony import */ var _pagination__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./pagination */ "./JavaScript/Frontend/components/pagination.js");\n/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./filter */ "./JavaScript/Frontend/components/filter.js");\n/* harmony import */ var _quickselect__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./quickselect */ "./JavaScript/Frontend/components/quickselect.js");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }\n\n\n\nvar Instance = /*#__PURE__*/function () {\n function Instance(element) {\n _classCallCheck(this, Instance);\n this.identifier = {\n paginationContainer: \'.js-in2studyfinder-pagebrowser\',\n filterContainer: \'.js-in2studyfinder-filter\',\n quickSelectContainer: \'.js-in2studyfinder-select\'\n };\n this.hasPagination = false;\n this.pagination = null;\n this.hasFilter = false;\n this.filter = null;\n this.hasQuickselect = false;\n this.quickselect = null;\n this.element = element;\n }\n _createClass(Instance, [{\n key: "init",\n value: function init() {\n if (this.element.querySelector(this.identifier.paginationContainer) !== null) {\n this.hasPagination = true;\n this.pagination = new _pagination__WEBPACK_IMPORTED_MODULE_0__["Pagination"](this.element);\n this.pagination.init();\n }\n if (this.element.querySelector(this.identifier.filterContainer) !== null) {\n this.hasFilter = true;\n this.filter = new _filter__WEBPACK_IMPORTED_MODULE_1__["Filter"](this.element);\n this.filter.init();\n }\n if (this.element.querySelector(this.identifier.quickSelectContainer) !== null) {\n this.hasQuickselect = true;\n this.quickselect = new _quickselect__WEBPACK_IMPORTED_MODULE_2__["Quickselect"](this.element);\n this.quickselect.init();\n }\n }\n }, {\n key: "update",\n value: function update(studyfinderElement) {\n this.element = studyfinderElement;\n if (this.element.querySelector(this.identifier.paginationContainer) !== null) {\n this.pagination.update(studyfinderElement);\n }\n if (this.element.querySelector(this.identifier.filterContainer) !== null) {\n this.filter.update(studyfinderElement);\n }\n if (this.element.querySelector(this.identifier.quickSelectContainer) !== null) {\n this.quickselect.update(studyfinderElement);\n }\n this.onUpdate();\n }\n }, {\n key: "onUpdate",\n value: function onUpdate() {}\n }]);\n return Instance;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/components/instance.js?')},
9"./JavaScript/Frontend/components/pagination.js": 10/*!******************************************************!*\ 11 !*** ./JavaScript/Frontend/components/pagination.js ***! 12 \******************************************************/ 13/*! exports provided: Pagination */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Pagination", function() { return Pagination; });\n/* harmony import */ var _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utility/urlUtility */ "./JavaScript/Frontend/utility/urlUtility.js");\n/* harmony import */ var _utility_loaderUtility__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utility/loaderUtility */ "./JavaScript/Frontend/utility/loaderUtility.js");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }\n\n\nvar Pagination = /*#__PURE__*/function () {\n function Pagination(studyfinderElement) {\n _classCallCheck(this, Pagination);\n this.identifier = {\n container: \'.in2studyfinder\',\n paginationContainer: \'.js-in2studyfinder-pagebrowser\',\n paginationLink: \'.js-in2studyfinder-pagination-link\'\n };\n this.studyfinderElement = studyfinderElement;\n this.paginationElement = studyfinderElement.querySelector(this.identifier.paginationContainer);\n }\n _createClass(Pagination, [{\n key: "init",\n value: function init() {\n this.paginationElement.querySelectorAll(this.identifier.paginationLink).forEach(function (item) {\n item.addEventListener(\'click\', function (event) {\n this.onClick(event);\n this.call(event);\n }.bind(this));\n }.bind(this));\n }\n }, {\n key: "update",\n value: function update(studyfinderElement) {\n this.studyfinderElement = studyfinderElement;\n this.paginationElement = studyfinderElement.querySelector(this.identifier.paginationContainer);\n this.paginationElement.querySelectorAll(this.identifier.paginationLink).forEach(function (item) {\n item.addEventListener(\'click\', function (event) {\n this.onClick(event);\n this.call(event);\n }.bind(this));\n }.bind(this));\n }\n }, {\n key: "call",\n value: function call(event) {\n var _this = this;\n event.preventDefault();\n var targetPage = event.target.getAttribute(\'data-target-page\');\n var url = event.target.href;\n var instanceId = this.studyfinderElement.getAttribute(\'data-in2studyfinder-instance-id\');\n _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__["UrlUtility"].addOrUpdateHash(\'page\', [targetPage]);\n if (window.in2studyfinder.getInstance(instanceId).hasFilter) {\n window.in2studyfinder.getInstance(instanceId).filter.call(targetPage);\n } else {\n _utility_loaderUtility__WEBPACK_IMPORTED_MODULE_1__["LoaderUtility"].enableLoader();\n fetch(url, {\n method: \'POST\',\n headers: {\n \'Content-Type\': \'application/x-www-form-urlencoded\'\n }\n }).then(function (response) {\n return response.text();\n }).then(function (html) {\n var tempElement = document.createElement(\'div\');\n tempElement.innerHTML = html;\n _this.studyfinderElement.innerHTML = tempElement.querySelector(_this.identifier.container).innerHTML;\n _utility_loaderUtility__WEBPACK_IMPORTED_MODULE_1__["LoaderUtility"].disableLoader();\n window.in2studyfinder.getInstance(instanceId).update(_this.studyfinderElement);\n });\n }\n }\n }, {\n key: "onClick",\n value: function onClick() {}\n }]);\n return Pagination;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/components/pagination.js?')},
13"./JavaScript/Frontend/components/quickselect.js": 14/*!*******************************************************!*\ 15 !*** ./JavaScript/Frontend/components/quickselect.js ***! 16 \*******************************************************/ 17/*! exports provided: Quickselect */function(module,__webpack_exports__,__webpack_require__){"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Quickselect\", function() { return Quickselect; });\n/* harmony import */ var tom_select__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tom-select */ \"./node_modules/tom-select/dist/js/tom-select.complete.js\");\n/* harmony import */ var tom_select__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(tom_select__WEBPACK_IMPORTED_MODULE_0__);\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar Quickselect = /*#__PURE__*/function () {\n function Quickselect(studyfinderContainer) {\n _classCallCheck(this, Quickselect);\n this.identifier = {\n quicksearchContainer: '.js-in2studyfinder-quick-search',\n select: '.js-in2studyfinder-select'\n };\n this.settings = {\n maxOptions: null,\n searchField: ['text', 'keywords'],\n onDropdownOpen: function onDropdownOpen() {\n this.clear(); // prevents the \"preselect\" bug of firefox 106\n },\n\n onItemAdd: function onItemAdd(value, item) {\n var url = item.getAttribute('data-url');\n if (url.length) {\n window.location.href = url;\n }\n },\n render: {\n item: function item(data, escape) {\n return '<div title=\"' + escape(data.text) + '\" data-url=\"' + data.url + '\">' + escape(data.text) + '</div>';\n },\n no_results: function no_results(data, escape) {\n var lang = document.querySelector('html').getAttribute('lang');\n var message = 'No results found';\n if (lang === 'de' || 'de-DE') {\n message = 'Keine Ergebnisse gefunden';\n }\n return '<div class=\"no-results\">' + message + '</div>';\n }\n }\n };\n this.tomSelect = null;\n this.in2studyfinderContainer = studyfinderContainer;\n }\n _createClass(Quickselect, [{\n key: \"init\",\n value: function init() {\n this.tomSelect = new tom_select__WEBPACK_IMPORTED_MODULE_0___default.a(this.in2studyfinderContainer.querySelector(this.identifier.select), this.settings);\n }\n }, {\n key: \"update\",\n value: function update(studyfinderContainer) {\n this.in2studyfinderContainer = studyfinderContainer;\n if (this.tomSelect !== null) {\n this.tomSelect.destroy();\n }\n this.init();\n }\n }]);\n return Quickselect;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/components/quickselect.js?")},
17"./JavaScript/Frontend/in2studyfinder/in2studyfinder.js": 18/*!**************************************************************!*\ 19 !*** ./JavaScript/Frontend/in2studyfinder/in2studyfinder.js ***! 20 \**************************************************************/ 21/*! exports provided: In2studyfinder */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "In2studyfinder", function() { return In2studyfinder; });\n/* harmony import */ var _components_instance__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/instance */ "./JavaScript/Frontend/components/instance.js");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }\n\nvar In2studyfinder = /*#__PURE__*/function () {\n function In2studyfinder() {\n _classCallCheck(this, In2studyfinder);\n this.identifier = {\n container: \'.in2studyfinder\'\n };\n this.instances = [];\n }\n _createClass(In2studyfinder, [{\n key: "init",\n value: function init() {\n document.querySelectorAll(this.identifier.container).forEach(function (item, index) {\n item.classList.replace(\'no-js\', \'js\');\n item.setAttribute(\'data-in2studyfinder-instance-id\', index);\n this.instances[index] = new _components_instance__WEBPACK_IMPORTED_MODULE_0__["Instance"](item);\n this.instances[index].init();\n }.bind(this));\n }\n }, {\n key: "getInstance",\n value: function getInstance(instanceId) {\n if (this.instances[instanceId] !== undefined) {\n return this.instances[instanceId];\n }\n return null;\n }\n }]);\n return In2studyfinder;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/in2studyfinder/in2studyfinder.js?')},
21"./JavaScript/Frontend/main.js": 22/*!*************************************!*\ 23 !*** ./JavaScript/Frontend/main.js ***! 24 \*************************************/ 25/*! no exports provided */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _in2studyfinder_in2studyfinder__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./in2studyfinder/in2studyfinder */ "./JavaScript/Frontend/in2studyfinder/in2studyfinder.js");\n\nif (document.querySelector(\'.in2studyfinder\') !== null) {\n var in2studyfinder = new _in2studyfinder_in2studyfinder__WEBPACK_IMPORTED_MODULE_0__["In2studyfinder"]();\n in2studyfinder.init();\n window.in2studyfinder = in2studyfinder;\n}\n\n//# sourceURL=webpack:///./JavaScript/Frontend/main.js?')},
25"./JavaScript/Frontend/utility/arrayUtility.js": 26/*!*****************************************************!*\ 27 !*** ./JavaScript/Frontend/utility/arrayUtility.js ***! 28 \*****************************************************/ 29/*! exports provided: ArrayUtility */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayUtility", function() { return ArrayUtility; });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }\nvar ArrayUtility = /*#__PURE__*/function () {\n function ArrayUtility() {\n _classCallCheck(this, ArrayUtility);\n }\n _createClass(ArrayUtility, null, [{\n key: "isInArray",\n value:\n /**\n *\n * @param value\n * @param array\n * @returns {boolean}\n */\n function isInArray(value, array) {\n return array.indexOf(value) > -1;\n }\n }, {\n key: "containsObjectWithKey",\n value:\n /**\n *\n * @param array\n * @param key\n * @param value\n * @returns {int} the array key of the object. -1 if no match is found\n */\n function containsObjectWithKey(array, key, value) {\n if (Array.isArray(array)) {\n for (var i = 0; i <= array.length - 1; i++) {\n if (array[i] instanceof Object) {\n if (array[i].hasOwnProperty(key) && array[i][key] === value) {\n return i;\n }\n }\n }\n }\n return -1;\n }\n }]);\n return ArrayUtility;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/utility/arrayUtility.js?')},
29"./JavaScript/Frontend/utility/loaderUtility.js": 30/*!******************************************************!*\ 31 !*** ./JavaScript/Frontend/utility/loaderUtility.js ***! 32 \******************************************************/ 33/*! exports provided: LoaderUtility */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoaderUtility", function() { return LoaderUtility; });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }\nvar LoaderUtility = /*#__PURE__*/function () {\n function LoaderUtility() {\n _classCallCheck(this, LoaderUtility);\n }\n _createClass(LoaderUtility, null, [{\n key: "enableLoader",\n value: function enableLoader() {\n document.querySelector(this.identifier.loader).classList.add(this.identifier.loaderActive.substring(1));\n }\n }, {\n key: "disableLoader",\n value: function disableLoader() {\n if (document.querySelector(this.identifier.loaderActive) !== null) {\n document.querySelector(this.identifier.loaderActive).classList.remove(this.identifier.loaderActive.substring(1));\n }\n }\n }]);\n return LoaderUtility;\n}();\nLoaderUtility.identifier = {\n loader: \'.in2studyfinder-loader\',\n loaderActive: \'.in2studyfinder-loader--active\'\n};\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/utility/loaderUtility.js?')},
33"./JavaScript/Frontend/utility/urlUtility.js": 34/*!***************************************************!*\ 35 !*** ./JavaScript/Frontend/utility/urlUtility.js ***! 36 \***************************************************/ 37/*! exports provided: UrlUtility */function(module,__webpack_exports__,__webpack_require__){"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UrlUtility\", function() { return UrlUtility; });\n/* harmony import */ var _arrayUtility__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./arrayUtility */ \"./JavaScript/Frontend/utility/arrayUtility.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar UrlUtility = /*#__PURE__*/function () {\n function UrlUtility() {\n _classCallCheck(this, UrlUtility);\n }\n _createClass(UrlUtility, null, [{\n key: \"removeParameterFromUrl\",\n value:\n /**\n * initialized all functions\n *\n * @return {void}\n */\n function removeParameterFromUrl(url, parameter) {\n var urlParts = url.split('?');\n if (urlParts.length >= 2) {\n var prefix = encodeURIComponent(parameter) + '=';\n var pars = urlParts[1].split(/[&;]/g);\n\n //reverse iteration as may be destructive\n for (var i = pars.length; i-- > 0;) {\n //idiom for string.startsWith\n if (pars[i].lastIndexOf(prefix, 0) !== -1) {\n pars.splice(i, 1);\n }\n }\n url = urlParts[0] + (pars.length > 0 ? '?' + pars.join('&') : \"\");\n return url;\n } else {\n return url;\n }\n }\n }, {\n key: \"getParameterFromUrl\",\n value: function getParameterFromUrl(url, parameter) {\n var parts = url.split('?'),\n value = '';\n if (parts.length >= 2) {\n var queryString = parts[1];\n queryString = '&' + queryString;\n var prefix = encodeURIComponent(parameter) + '=';\n var parameters = queryString.split(/[&;]/g);\n for (var i = parameters.length; i-- > 0;) {\n if (parameters[i].lastIndexOf(prefix, 0) !== -1) {\n value = parameters[i].split('=')[1];\n break;\n }\n }\n }\n return value;\n }\n }, {\n key: \"addOrUpdateHash\",\n value:\n /**\n *\n * @param {string} attribute\n * @param {array} values\n */\n function addOrUpdateHash(attribute, values) {\n var hashArguments = this.getHashArgumentsFromUrl();\n if (hashArguments.length > 0) {\n var key = _arrayUtility__WEBPACK_IMPORTED_MODULE_0__[\"ArrayUtility\"].containsObjectWithKey(hashArguments, 'name', attribute);\n if (key >= 0) {\n hashArguments[key]['values'] = values;\n }\n } else {\n hashArguments[0] = {\n name: attribute,\n values: values\n };\n }\n var hash = '#';\n // write hash\n for (var i = 0; i <= hashArguments.length - 1; i++) {\n if (i === hashArguments.length - 1) {\n hash += hashArguments[i].name + '=' + hashArguments[i].values.join();\n } else {\n hash += hashArguments[i].name + '=' + hashArguments[i].values.join() + '&';\n }\n }\n window.location.hash = hash;\n }\n }, {\n key: \"addAttributeToUrl\",\n value:\n /**\n *\n * @param url\n * @param attribute\n * @param value\n * @returns {string|*}\n */\n function addAttributeToUrl(url, attribute, value) {\n var divider = '?';\n if (url.indexOf('?') !== -1) {\n divider = '&';\n }\n url += divider + attribute + '=' + value;\n return url;\n }\n }, {\n key: \"serialize\",\n value:\n /**\n * Serialize a given Form\n *\n * @param form\n * @returns {string}\n */\n function serialize(form) {\n var field,\n s = [];\n if (_typeof(form) === 'object' && form.nodeName === 'FORM') {\n var len = form.elements.length;\n for (var i = 0; i < len;
37 i++) {\n field = form.elements[i];\n if (field.name && !field.disabled && field.type !== 'file' && field.type !== 'reset' && field.type !== 'submit' && field.type !== 'button') {\n if (field.type === 'select-multiple') {\n for (var j = form.elements[i].options.length - 1; j >= 0; j--) {\n if (field.options[j].selected) {\n s[s.length] = encodeURIComponent(field.name) + '=' + encodeURIComponent(field.options[j].value);\n }\n }\n } else if (field.type !== 'checkbox' && field.type !== 'radio' || field.checked) {\n s[s.length] = encodeURIComponent(field.name) + '=' + encodeURIComponent(field.value);\n }\n }\n }\n }\n return s.join('&').replace(/%20/g, '+');\n }\n }, {\n key: \"getHashArgumentsFromUrl\",\n value:\n /**\n * @return array\n */\n function getHashArgumentsFromUrl() {\n if (window.location.hash) {\n var hash = window.location.hash.split('#')[1];\n var argumentArray = hash.split(/[&;]/g);\n var hashArguments = [];\n for (var i = 0; i < argumentArray.length; i++) {\n var singleArgument = argumentArray[i].split(/[=;]/g);\n if (singleArgument.length === 2) {\n var values = singleArgument[1].split(/[+;]/g);\n hashArguments[i] = {\n name: singleArgument[0],\n values: values\n };\n }\n }\n return hashArguments;\n }\n return [];\n }\n }]);\n return UrlUtility;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/utility/urlUtility.js?")},
37"./Sass/backend.scss": 38/*!***************************!*\ 39 !*** ./Sass/backend.scss ***! 40 \***************************/ 41/*! exports provided: default */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (__webpack_require__.p + "../Public/Css/backend.css");\n\n//# sourceURL=webpack:///./Sass/backend.scss?')},
41"./Sass/demo.scss": 42/*!************************!*\ 43 !*** ./Sass/demo.scss ***! 44 \************************/ 45/*! exports provided: default */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (__webpack_require__.p + "../Public/Css/demo.css");\n\n//# sourceURL=webpack:///./Sass/demo.scss?')},
45"./Sass/style.scss": 46/*!*************************!*\ 47 !*** ./Sass/style.scss ***! 48 \*************************/ 49/*! exports provided: default */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (__webpack_require__.p + "../Public/Css/style.css");\n\n//# sourceURL=webpack:///./Sass/style.scss?')},
vendor: 157,728 bytes, lines 49-53
49"./node_modules/tom-select/dist/js/tom-select.complete.js": 50/*!****************************************************************!*\ 51 !*** ./node_modules/tom-select/dist/js/tom-select.complete.js ***! 52 \****************************************************************/ 53/*! no static exports found */function(module,exports,__webpack_require__){eval("/**\n* Tom Select v2.2.2\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n*/\n\n(function (global, factory) {\n\t true ? module.exports = factory() :\n\tundefined;\n})(this, (function () { 'use strict';\n\n\t/**\n\t * MicroEvent - to make any js object an event emitter\n\t *\n\t * - pure javascript - server compatible, browser compatible\n\t * - dont rely on the browser doms\n\t * - super simple - you get it immediatly, no mistery, no magic involved\n\t *\n\t * @author Jerome Etienne (https://github.com/jeromeetienne)\n\t */\n\n\t/**\n\t * Execute callback for each event in space separated list of event names\n\t *\n\t */\n\tfunction forEvents(events, callback) {\n\t events.split(/\\s+/).forEach(event => {\n\t callback(event);\n\t });\n\t}\n\n\tclass MicroEvent {\n\t constructor() {\n\t this._events = void 0;\n\t this._events = {};\n\t }\n\n\t on(events, fct) {\n\t forEvents(events, event => {\n\t const event_array = this._events[event] || [];\n\t event_array.push(fct);\n\t this._events[event] = event_array;\n\t });\n\t }\n\n\t off(events, fct) {\n\t var n = arguments.length;\n\n\t if (n === 0) {\n\t this._events = {};\n\t return;\n\t }\n\n\t forEvents(events, event => {\n\t if (n === 1) {\n\t delete this._events[event];\n\t return;\n\t }\n\n\t const event_array = this._events[event];\n\t if (event_array === undefined) return;\n\t event_array.splice(event_array.indexOf(fct), 1);\n\t this._events[event] = event_array;\n\t });\n\t }\n\n\t trigger(events, ...args) {\n\t var self = this;\n\t forEvents(events, event => {\n\t const event_array = self._events[event];\n\t if (event_array === undefined) return;\n\t event_array.forEach(fct => {\n\t fct.apply(self, args);\n\t });\n\t });\n\t }\n\n\t}\n\n\t/**\n\t * microplugin.js\n\t * Copyright (c) 2013 Brian Reavis & contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t * @author Brian Reavis <[email protected]>\n\t */\n\tfunction MicroPlugin(Interface) {\n\t Interface.plugins = {};\n\t return class extends Interface {\n\t constructor(...args) {\n\t super(...args);\n\t this.plugins = {\n\t names: [],\n\t settings: {},\n\t requested: {},\n\t loaded: {}\n\t };\n\t }\n\n\t /**\n\t * Registers a plugin.\n\t *\n\t * @param {function} fn\n\t */\n\t static define(name, fn) {\n\t Interface.plugins[name] = {\n\t 'name': name,\n\t 'fn': fn\n\t };\n\t }\n\t /**\n\t * Initializes the listed plugins (with options).\n\t * Acceptable formats:\n\t *\n\t * List (without options):\n\t * ['a', 'b', 'c']\n\t *\n\t * List (with options):\n\t * [{'name': 'a', options: {}}, {'name': 'b', options: {}}]\n\t *\n\t * Hash (with options):\n\t * {'a': { ... }, 'b': { ... }, 'c': { ... }}\n\t *\n\t * @param {array|object} plugins\n\t */\n\n\n\t initializePlugins(plugins) {\n\t var key, name;\n\t const self = this;\n\t const queue = [];\n\n\t if (Array.isArray(plugins)) {\n\t plugins.forEach(plugin => {\n\t if (typeof plugin === 'string') {\n\t queue.push(plugin);\n\t } else {\n\t self.plugins.settings[plugin.name] = plugin.options;\n\t queue.push(plugin.name);\n\t }\n\t });\n\t } else if (plugins) {\n\t for (key in plugins) {\n\t if (plugins.hasOwnProperty(key)) {\n\t self.plugins.settings[key] = plugins[key];\n\t queue.push(key);\n\t }\n\t }\n\t }\n\n\t while (name = queue.shift()) {\n\t self.require(name);\n\t }\n\t }\n\n\t loadPlugin(name) {\n\t var self = this;\n\t var plugins = self.plugins;\n\t var plugin = Interface.plugins[name];\n\n\t if (!Interface.plugins.hasOwnProperty(name)) {\n\t throw new Error('Unable to find \"' + name + '\" plugin');\n\t }\n\n\t plugins.requested[name] = true;\n\t plugins.loaded[name] = plugin.fn.apply(self, [self.plugins.settings[name] || {}]);\n\t plugins.names.push(name);\n\t }\n\t /**\n\t * Initializes a plugin.\n\t *\n\t */\n\n\n\t require(name) {\n\t var self = this;\n\t var plugins = self.plugins;\n\n\t if (!self.plugins.loaded.hasOwnProperty(name)) {\n\t if (plugins.requested[name]) {\n\t throw new Error('Plugin has circular dependency (\"' + name + '\")');\n\t }\n\n\t self.loadPlugin(name);\n\t }\n\n\t return plugins.loaded[name];\n\t }\n\n\t };\n\t}\n\n\t/*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */\n\t/**\n\t * Convert array of strings to a regular expression\n\t *\tex ['ab','a'] => (?:ab|a)\n\t * \tex ['a','b'] => [ab]\n\t * @param {string[]} chars\n\t * @return {string}\n\t */\n\tconst arrayToPattern = chars => {\n\t chars = chars.filter(Boolean);\n\n\t if (chars.length < 2) {\n\t return chars[0] || '';\n\t }\n\n\t return maxValueLength(chars) == 1 ? '[' + chars.join('') + ']' : '(?:' + chars.join('|') + ')';\n\t};\n\t/**\n\t * @param {string[]} array\n\t * @return {string}\n\t */\n\n\tconst sequencePattern = array => {\n\t if (!hasDuplicates(array)) {\n\t return array.join('');\n\t }\n\n\t let pattern = '';\n\t let prev_char_count = 0;\n\n\t const prev_pattern = () => {\n\t if (prev_char_count > 1) {\n\t pattern += '{' + prev_char_count + '}';\n\t }\n\t };\n\n\t array.forEach((char, i) => {\n\t if (char === array[i - 1]) {\n\t prev_char_count++;\n\t return;\n\t }\n\n\t prev_pattern();\n\t pattern += char;\n\t prev_char_count = 1;\n\t });\n\t prev_pattern();\n\t return pattern;\n\t};\n\t/**\n\t * Convert array of strings to a regular expression\n\t *\tex ['ab','a'] => (?:ab|a)\n\t * \tex ['a','b'] => [ab]\n\t * @param {Set<string>} chars\n\t * @return {string}\n\t */\n\n\tconst setToPattern = chars => {\n\t let array = toArray(chars);\n\t return arrayToPattern(array);\n\t};\n\t/**\n\t *\n\t * https://stackoverflow.com/questions/7376598/in-javascript-how-do-i-check-if-an-array-has-duplicate-values\n\t * @param {any[]} array\n\t */\n\n\tconst hasDuplicates = array => {\n\t return new Set(array).size !== array.length;\n\t};\n\t/**\n\t * https://stackoverflow.com/questions/63006601/why-does-u-throw-an-invalid-escape-error\n\t * @param {string} str\n\t * @return {string}\n\t */\n\n\tconst escape_regex = str => {\n\t return (str + '').replace(/([\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\|\\}\\\\])/gu, '\\\\$1');\n\t};\n\t/**\n\t * Return the max length of array values\n\t * @param {string[]} array\n\t *\n\t */\n\n\tconst maxValueLength = array => {\n\t return array.reduce((longest, value) => Math.max(longest, unicodeLength(value)), 0);\n\t};\n\t/**\n\t * @param {string} str\n\t */\n\n\tconst unicodeLength = str => {\n\t return toArray(str).length;\n\t};\n\t/**\n\t * @param {any} p\n\t * @return {any[]}\n\t */\n\n\tconst toArray = p => Array.from(p);\n\n\t/*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */\n\t/**\n\t * Get all possible combinations of substrings that add up to the given string\n\t * https://stackoverflow.com/questions/30169587/find-all-the-combination-of-substrings-that-add-up-to-the-given-string\n\t * @param {string} input\n\t * @return {string[][]}\n\t */\n\tconst allSubstrings = input => {\n\t if (input.length === 1) return [[input]];\n\t /** @type {string[][]} */\n\n\t let result = [];\n\t const start = input.substring(1);\n\t const suba = allSubstrings(start);\n\t suba.forEach(function (subresult) {\n\t let tmp = subresult.slice(0);\n\t tmp[0] = input.charAt(0) + tmp[0];\n\t result.push(tmp);\n\t tmp = subresult.slice(0);\n\t tmp.unshift(input.charAt(0));\n\t result.push(tmp);\n\t });\n\t return result;\n\t};\n\n\t/*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */\n\n\t/**\n\t * @typedef {{[key:string]:string}} TUnicodeMap\n\t * @typedef {{[key:string]:Set<string>}} TUnicodeSets\n\t * @typedef {[[number,number]]} TCodePoints\n\t * @typedef {{folded:string,composed:string,code_point:number}} TCodePointObj\n\t * @typedef {{start:number,end:number,length:number,substr:string}} TSequencePart\n\t */\n\t/** @type {TCodePoints} */\n\n\tconst code_points = [[0, 65535]];\n\tconst accent_pat = '[\\u0300-\\u036F\\u{b7}\\u{2be}\\u{2bc}]';\n\t/** @type {TUnicodeMap} */\n\n\tlet unicode_map;\n\t/** @type {RegExp} */\n\n\tlet multi_char_reg;\n\tconst max_char_length = 3;\n\t/** @type {TUnicodeMap} */\n\n\tconst latin_convert = {};\n\t/** @type {TUnicodeMap} */\n\n\tconst latin_condensed = {\n\t '/': 'ââ',\n\t '0': 'ß',\n\t \"a\": \"â±¥ÉÉ\",\n\t \"aa\": \"ê³\",\n\t \"ae\": \"æǽǣ\",\n\t \"ao\": \"êµ\",\n\t \"au\": \"ê·\",\n\t \"av\": \"ê¹ê»\",\n\t \"ay\": \"ê½\",\n\t \"b\": \"ÆÉÆ\",\n\t \"c\": \"ê¿ÆÈ¼â\",\n\t \"d\": \"ÄÉÉá´ Æê®·Ôɦ\",\n\t \"e\": \"ÉÇá´É\",\n\t \"f\": \"ê¼Æ\",\n\t \"g\": \"Ç¥É ê¡áµ¹ê¿É¢\",\n\t \"h\": \"ħⱨⱶɥ\",\n\t \"i\": \"ɨı\",\n\t \"j\": \"ÉÈ·\",\n\t \"k\": \"Æâ±ªêêê ê£\",\n\t \"l\": \"ÅÆÉ«â±¡êêêÉ\",\n\t \"m\": \"ɱɯϻ\",\n\t \"n\": \"ê¥ÆÉ²êá´Ð»Ô\",\n\t \"o\": \"øǿÉɵêêá´\",\n\t \"oe\": \"Å\",\n\t \"oi\": \"Æ£\",\n\t \"oo\": \"ê\",\n\t \"ou\": \"È£\",\n\t \"p\": \"ƥᵽêêêÏ\",\n\t \"q\": \"êêÉ\",\n\t \"r\": \"Éɽêê§ê\",\n\t \"s\": \"ÃÈ¿ê©ê Ê\",\n\t \"t\": \"ŧÆÊⱦê\",\n\t \"th\": \"þ\",\n\t \"tz\": \"ê©\",\n\t \"u\": \"Ê\",\n\t \"v\": \"ÊêÊ\",\n\t \"vy\": \"ê¡\",\n\t \"w\": \"â±³\",\n\t \"y\": \"Æ´Éỿ\",\n\t \"z\": \"ƶȥÉⱬê£\",\n\t \"hv\": \"Æ\"\n\t};\n\n\tfor (let latin in latin_condensed) {\n\t let unicode = latin_condensed[latin] || '';\n\n\t for (let i = 0; i < unicode.length; i++) {\n\t let char = unicode.substring(i, i + 1);\n\t latin_convert[char] = latin;\n\t }\n\t}\n\n\tconst convert_pat = new RegExp(Object.keys(latin_convert).join('|') + '|' + accent_pat, 'gu');\n\t/**\n\t * Initialize the unicode_map from the give code point ranges\n\t *\n\t * @param {TCodePoints=} _code_points\n\t */\n\n\tconst initialize = _code_points => {\n\t if (unicode_map !== undefined) return;\n\t unicode_map = generateMap(_code_points || code_points);\n\t};\n\t/**\n\t * Helper method for normalize a string\n\t * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize\n\t * @param {string} str\n\t * @param {string} form\n\t */\n\n\tconst normalize = (str, form = 'NFKD') => str.normalize(form);\n\t/**\n\t * Remove accents without reordering string\n\t * calling str.normalize('NFKD') on \\u{594}\\u{595}\\u{596} becomes \\u{596}\\u{594}\\u{595}\n\t * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703\n\t * @param {string} str\n\t * @return {string}\n\t */\n\n\tconst asciifold = str => {\n\t return toArray(str).reduce(\n\t /**\n\t * @param {string} result\n\t * @param {string} char\n\t */\n\t (result, char) => {\n\t return result + _asciifold(char);\n\t }, '');\n\t};\n\t/**\n\t * @param {string} str\n\t * @return {string}\n\t */\n\n\tconst _asciifold = str => {\n\t str = normalize(str).toLowerCase().replace(convert_pat, (\n\t /** @type {string} */\n\t char) => {\n\t return latin_convert[char] || '';\n\t }); //return str;\n\n\t return normalize(str, 'NFC');\n\t};\n\t/**\n\t * Generate a list of unicode variants from the list of code points\n\t * @param {TCodePoints} code_points\n\t * @yield {TCodePointObj}\n\t */\n\n\tfunction* generator(code_points) {\n\t for (const [code_point_min, code_point_max] of code_points) {\n\t for (let i = code_point_min; i <= code_point_max; i++) {\n\t let composed = String.fromCharCode(i);\n\t let folded = asciifold(composed);\n\n\t if (folded == composed.toLowerCase()) {\n\t continue;\n\t } // skip when folded is a string longer than 3 characters long\n\t // bc the resulting regex patterns will be long\n\t // eg:\n\t // folded صÙ٠اÙÙ٠عÙÙÙ ÙØ³ÙÙ length 18 code point 65018\n\t // folded Ø¬Ù Ø¬ÙØ§ÙÙ length 8 code point 65019\n\n\n\t if (folded.length > max_char_length) {\n\t continue;\n\t }\n\n\t if (folded.length == 0) {\n\t continue;\n\t }\n\n\t yield {\n\t folded: folded,\n\t composed: composed,\n\t code_point: i\n\t };\n\t }\n\t }\n\t}\n\t/**\n\t * Generate a unicode map from the list of code points\n\t * @param {TCodePoints} code_points\n\t * @return {TUnicodeSets}\n\t */\n\n\tconst generateSets = code_points => {\n\t /** @type {{[key:string]:Set<string>}} */\n\t const unicode_sets = {};\n\t /**\n\t * @param {string} folded\n\t * @param {string} to_add\n\t */\n\n\t const addMatching = (folded, to_add) => {\n\t /** @type {Set<string>} */\n\t const folded_set = unicode_sets[folded] || new Set();\n\t const patt = new RegExp('^' + setToPattern(folded_set) + '$', 'iu');\n\n\t if (to_add.match(patt)) {\n\t return;\n\t }\n\n\t folded_set.add(escape_regex(to_add));\n\t unicode_sets[folded] = folded_set;\n\t };\n\n\t for (let value of generator(code_points)) {\n\t addMatching(value.folded, value.folded);\n\t addMatching(value.folded, value.composed);\n\t }\n\n\t return unicode_sets;\n\t};\n\t/**\n\t * Generate a unicode map from the list of code points\n\t * ae => (?:(?:ae|Ã|Ǽ|Ç¢)|(?:A|â¶|A...)(?:E|É|âº...))\n\t *\n\t * @param {TCodePoints} code_points\n\t * @return {TUnicodeMap}\n\t */\n\n\tconst generateMap = code_points => {\n\t /** @type {TUnicodeSets} */\n\t const unicode_sets = generateSets(code_points);\n\t /** @type {TUnicodeMap} */\n\n\t const unicode_map = {};\n\t /** @type {string[]} */\n\n\t let multi_char = [];\n\n\t for (let folded in unicode_sets) {\n\t let set = unicode_sets[folded];\n\n\t if (set) {\n\t unicode_map[folded] = setToPattern(set);\n\t }\n\n\t if (folded.length > 1) {\n\t multi_char.push(escape_regex(folded));\n\t }\n\t }\n\n\t multi_char.sort((a, b) => b.length - a.length);\n\t const multi_char_patt = arrayToPattern(multi_char);\n\t multi_char_reg = new RegExp('^' + multi_char_patt, 'u');\n\t return unicode_map;\n\t};\n\t/**\n\t * Map each element of an array from it's folded value to all possible unicode matches\n\t * @param {string[]} strings\n\t * @param {number} min_replacement\n\t * @return {string}\n\t */\n\n\tconst mapSequence = (strings, min_replacement = 1) => {\n\t let chars_replaced = 0;\n\t strings = strings.map(str => {\n\t if (unicode_map[str]) {\n\t chars_replaced += str.length;\n\t }\n\n\t return unicode_map[str] || str;\n\t });\n\n\t if (chars_replaced >= min_replacement) {\n\t return sequencePattern(strings);\n\t }\n\n\t return '';\n\t};\n\t/**\n\t * Convert a short string and split it into all possible patterns\n\t * Keep a pattern only if min_replacement is met\n\t *\n\t * 'abc'\n\t * \t\t=> [['abc'],['ab','c'],['a','bc'],['a','b','c']]\n\t *\t\t=> ['abc-pattern','ab-c-pattern'...]\n\t *\n\t *\n\t * @param {string} str\n\t * @param {number} min_replacement\n\t * @return {string}\n\t */\n\n\tconst substringsToPattern = (str, min_replacement = 1) => {\n\t min_replacement = Math.max(min_replacement, str.length - 1);\n\t return arrayToPattern(allSubstrings(str).map(sub_pat => {\n\t return mapSequence(sub_pat, min_replacement);\n\t }));\n\t};\n\t/**\n\t * Convert an array of sequences into a pattern\n\t * [{start:0,end:3,length:3,substr:'iii'}...] => (?:iii...)\n\t *\n\t * @param {Sequence[]} sequences\n\t * @param {boolean} all\n\t */\n\n\tconst sequencesToPattern = (sequences, all = true) => {\n\t let min_replacement = sequences.length > 1 ? 1 : 0;\n\t return arrayToPattern(sequences.map(sequence => {\n\t let seq = [];\n\t const len = all ? sequence.length() : sequence.length() - 1;\n\n\t for (let j = 0; j < len; j++) {\n\t seq.push(substringsToPattern(sequence.substrs[j] || '', min_replacement));\n\t }\n\n\t return sequencePattern(seq);\n\t }));\n\t};\n\t/**\n\t * Return true if the sequence is already in the sequences\n\t * @param {Sequence} needle_seq\n\t * @param {Sequence[]} sequences\n\t */\n\n\n\tconst inSequences = (needle_seq, sequences) => {\n\t for (const seq of sequences) {\n\t if (seq.start != needle_seq.start || seq.end != needle_seq.end) {\n\t continue;\n\t }\n\n\t if (seq.substrs.join('') !== needle_seq.substrs.join('')) {\n\t continue;\n\t }\n\n\t let needle_parts = needle_seq.parts;\n\t /**\n\t * @param {TSequencePart} part\n\t */\n\n\t const filter = part => {\n\t for (const needle_part of needle_parts) {\n\t if (needle_part.start === part.start && needle_part.substr === part.substr) {\n\t return false;\n\t }\n\n\t if (part.length == 1 || needle_part.length == 1) {\n\t continue;\n\t } // check for overlapping parts\n\t // a = ['::=','==']\n\t // b = ['::','===']\n\t // a = ['r','sm']\n\t // b = ['rs','m']\n\n\n\t if (part.start < needle_part.start && part.end > needle_part.start) {\n\t return true;\n\t }\n\n\t if (needle_part.start < part.start && needle_part.end > part.start) {\n\t return true;\n\t }\n\t }\n\n\t return false;\n\t };\n\n\t let filtered = seq.parts.filter(filter);\n\n\t if (filtered.length > 0) {\n\t continue;\n\t }\n\n\t return true;\n\t }\n\n\t return false;\n\t};\n\n\tclass Sequence {\n\t constructor() {\n\t /** @type {TSequencePart[]} */\n\t this.parts = [];\n\t /** @type {string[]} */\n\n\t this.substrs = [];\n\t this.start = 0;\n\t this.end = 0;\n\t }\n\t /**\n\t * @param {TSequencePart|undefined} part\n\t */\n\n\n\t add(part) {\n\t if (part) {\n\t this.parts.push(part);\n\t this.substrs.push(part.substr);\n\t this.start = Math.min(part.start, this.start);\n\t this.end = Math.max(part.end, this.end);\n\t }\n\t }\n\n\t last() {\n\t return this.parts[this.parts.length - 1];\n\t }\n\n\t length() {\n\t return this.parts.length;\n\t }\n\t /**\n\t * @param {number} position\n\t * @param {TSequencePart} last_piece\n\t */\n\n\n\t clone(position, last_piece) {\n\t let clone = new Sequence();\n\t let parts = JSON.parse(JSON.stringify(this.parts));\n\t let last_part = parts.pop();\n\n\t for (const part of parts) {\n\t clone.add(part);\n\t }\n\n\t let last_substr = last_piece.substr.substring(0, position - last_part.start);\n\t let clone_last_len = last_substr.length;\n\t clone.add({\n\t start: last_part.start,\n\t end: last_part.start + clone_last_len,\n\t length: clone_last_len,\n\t substr: last_substr\n\t });\n\t return clone;\n\t }\n\n\t}\n\t/**\n\t * Expand a regular expression pattern to include unicode variants\n\t * \teg /a/ becomes /aâï½áºÃ áâầấẫẩãÄÄằắẵẳȧǡäÇảåǻÇÈÈạáºáº·á¸Ä â±¥ÉÉAâ¶ï¼¡ÃÃÃẦẤẪẨÃÄÄáº°áº®áº´áº²È¦Ç ÃÇẢà ǺÇÈÈẠẬẶá¸ÄȺⱯ/\n\t *\n\t * Issue:\n\t * ïºïº [ 'ïº = \\\\u{fe8a}', 'ïº = \\\\u{fe8b}' ]\n\t *\tbecomes:\tÙÙÙÙ [ 'Ù = \\\\u{64a}', 'Ù = \\\\u{654}', 'Ù = \\\\u{64a}', 'Ù = \\\\u{654}' ]\n\t *\n\t *\tİIJ = IIJ = â ¡J\n\t *\n\t * \t1/2/4\n\t *\n\t * @param {string} str\n\t * @return {string|undefined}\n\t */\n\n\n\tconst getPattern = str => {\n\t initialize();\n\t str = asciifold(str);\n\t let pattern = '';\n\t let sequences = [new Sequence()];\n\n\t for (let i = 0; i < str.length; i++) {\n\t let substr = str.substring(i);\n\t let match = substr.match(multi_char_reg);\n\t const char = str.substring(i, i + 1);\n\t const match_str = match ? match[0] : null; // loop through sequences\n\t // add either the char or multi_match\n\n\t let overlapping = [];\n\t let added_types = new Set();\n\n\t for (const sequence of sequences) {\n\t const last_piece = sequence.last();\n\n\t if (!last_piece || last_piece.length == 1 || last_piece.end <= i) {\n\t // if we have a multi match\n\t if (match_str) {\n\t const len = match_str.length;\n\t sequence.add({\n\t start: i,\n\t end: i + len,\n\t length: len,\n\t substr: match_str\n\t });\n\t added_types.add('1');\n\t } else {\n\t sequence.add({\n\t start: i,\n\t end: i + 1,\n\t length: 1,\n\t substr: char\n\t });\n\t added_types.add('2');\n\t }\n\t } else if (match_str) {\n\t let clone = sequence.clone(i, last_piece);\n\t const len = match_str.length;\n\t clone.add({\n\t start: i,\n\t end: i + len,\n\t length: len,\n\t substr: match_str\n\t });\n\t overlapping.push(clone);\n\t } else {\n\t // don't add char\n\t // adding would create invalid patterns: 234 => [2,34,4]\n\t added_types.add('3');\n\t }\n\t } // if we have overlapping\n\n\n\t if (overlapping.length > 0) {\n\t // ['ii','iii'] before ['i','i','iii']\n\t overlapping = overlapping.sort((a, b) => {\n\t return a.length() - b.length();\n\t });\n\n\t for (let clone of overlapping) {\n\t // don't add if we already have an equivalent sequence\n\t if (inSequences(clone, sequences)) {\n\t continue;\n\t }\n\n\t sequences.push(clone);\n\t }\n\n\t continue;\n\t } // if we haven't done anything unique\n\t // clean up the patterns\n\t // helps keep patterns smaller\n\t // if str = 'râ¨ã§aarss', pattern will be 446 instead of 655\n\n\n\t if (i > 0 && added_types.size == 1 && !added_types.has('3')) {\n\t pattern += sequencesToPattern(sequences, false);\n\t let new_seq = new Sequence();\n\t const old_seq = sequences[0];\n\n\t if (old_seq) {\n\t new_seq.add(old_seq.last());\n\t }\n\n\t sequences = [new_seq];\n\t }\n\t }\n\n\t pattern += sequencesToPattern(sequences, true);\n\t return pattern;\n\t};\n\n\t/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */\n\n\t/**\n\t * A property getter resolving dot-notation\n\t * @param {Object} obj The root object to fetch property on\n\t * @param {String} name The optionally dotted property name to fetch\n\t * @return {Object} The resolved property value\n\t */\n\tconst getAttr = (obj, name) => {\n\t if (!obj) return;\n\t return obj[name];\n\t};\n\t/**\n\t * A property getter resolving dot-notation\n\t * @param {Object} obj The root object to fetch property on\n\t * @param {String} name The optionally dotted property name to fetch\n\t * @return {Object} The resolved property value\n\t */\n\n\tconst getAttrNesting = (obj, name) => {\n\t if (!obj) return;\n\t var part,\n\t names = name.split(\".\");\n\n\t while ((part = names.shift()) && (obj = obj[part]));\n\n\t return obj;\n\t};\n\t/**\n\t * Calculates how close of a match the\n\t * given value is against a search token.\n\t *\n\t */\n\n\tconst scoreValue = (value, token, weight) => {\n\t var score, pos;\n\t if (!value) return 0;\n\t value = value + '';\n\t if (token.regex == null) return 0;\n\t pos = value.search(token.regex);\n\t if (pos === -1) return 0;\n\t score = token.string.length / value.length;\n\t if (pos === 0) score += 0.5;\n\t return score * weight;\n\t};\n\t/**\n\t * Cast object property to an array if it exists and has a value\n\t *\n\t */\n\n\tconst propToArray = (obj, key) => {\n\t var value = obj[key];\n\t if (typeof value == 'function') return value;\n\n\t if (value && !Array.isArray(value)) {\n\t obj[key] = [value];\n\t }\n\t};\n\t/**\n\t * Iterates over arrays and hashes.\n\t *\n\t * ```\n\t * iterate(this.items, function(item, id) {\n\t * // invoked for each item\n\t * });\n\t * ```\n\t *\n\t */\n\n\tconst iterate$1 = (object, callback) => {\n\t if (Array.isArray(object)) {\n\t object.forEach(callback);\n\t } else {\n\t for (var key in object) {\n\t if (object.hasOwnProperty(key)) {\n\t callback(object[key], key);\n\t }\n\t }\n\t }\n\t};\n\tconst cmp = (a, b) => {\n\t if (typeof a === 'number' && typeof b === 'number') {\n\t return a > b ? 1 : a < b ? -1 : 0;\n\t }\n\n\t a = asciifold(a + '').toLowerCase();\n\t b = asciifold(b + '').toLowerCase();\n\t if (a > b) return 1;\n\t if (b > a) return -1;\n\t return 0;\n\t};\n\n\t/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */\n\n\t/**\n\t * sifter.js\n\t * Copyright (c) 2013â2020 Brian Reavis & contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t * @author Brian Reavis <[email protected]>\n\t */\n\n\tclass Sifter {\n\t // []|{};\n\n\t /**\n\t * Textually searches arrays and hashes of objects\n\t * by property (or multiple properties). Designed\n\t * specifically for autocomplete.\n\t *\n\t */\n\t constructor(items, settings) {\n\t this.items = void 0;\n\t this.settings = void 0;\n\t this.items = items;\n\t this.settings = settings || {\n\t diacritics: true\n\t };\n\t }\n\n\t /**\n\t * Splits a search string into an array of individual\n\t * regexps to be used to match results.\n\t *\n\t */\n\t tokenize(query, respect_word_boundaries, weights) {\n\t if (!query || !query.length) return [];\n\t const tokens = [];\n\t const words = query.split(/\\s+/);\n\t var field_regex;\n\n\t if (weights) {\n\t field_regex = new RegExp('^(' + Object.keys(weights).map(escape_regex).join('|') + ')\\:(.*)$');\n\t }\n\n\t words.forEach(word => {\n\t let field_match;\n\t let field = null;\n\t let regex = null; // look for \"field:query\" tokens\n\n\t if (field_regex && (field_match = word.match(field_regex))) {\n\t field = field_match[1];\n\t word = field_match[2];\n\t }\n\n\t if (word.length > 0) {\n\t if (this.settings.diacritics) {\n\t regex = getPattern(word) || null;\n\t } else {\n\t regex = escape_regex(word);\n\t }\n\n\t if (regex && respect_word_boundaries) regex = \"\\\\b\" + regex;\n\t }\n\n\t tokens.push({\n\t string: word,\n\t regex: regex ? new RegExp(regex, 'iu') : null,\n\t field: field\n\t });\n\t });\n\t return tokens;\n\t }\n\n\t /**\n\t * Returns a function to be used to score individual results.\n\t *\n\t * Good matches will have a higher score than poor matches.\n\t * If an item is not a match, 0 will be returned by the function.\n\t *\n\t * @returns {T.ScoreFn}\n\t */\n\t getScoreFunction(query, options) {\n\t var search = this.prepareSearch(query, options);\n\t return this._getScoreFunction(search);\n\t }\n\t /**\n\t * @returns {T.ScoreFn}\n\t *\n\t */\n\n\n\t _getScoreFunction(search) {\n\t const tokens = search.tokens,\n\t token_count = tokens.length;\n\n\t if (!token_count) {\n\t return function () {\n\t return 0;\n\t };\n\t }\n\n\t const fields = search.options.fields,\n\t weights = search.weights,\n\t field_count = fields.length,\n\t getAttrFn = search.getAttrFn;\n\n\t if (!field_count) {\n\t return function () {\n\t return 1;\n\t };\n\t }\n\t /**\n\t * Calculates the score of an object\n\t * against the search query.\n\t *\n\t */\n\n\n\t const scoreObject = function () {\n\t if (field_count === 1) {\n\t return function (token, data) {\n\t const field = fields[0].field;\n\t return scoreValue(getAttrFn(data, field), token, weights[field] || 1);\n\t };\n\t }\n\n\t return function (token, data) {\n\t var sum = 0; // is the token specific to a field?\n\n\t if (token.field) {\n\t const value = getAttrFn(data, token.field);\n\n\t if (!token.regex && value) {\n\t sum += 1 / field_count;\n\t } else {\n\t sum += scoreValue(value, token, 1);\n\t }\n\t } else {\n\t iterate$1(weights, (weight, field) => {\n\t sum += scoreValue(getAttrFn(data, field), token, weight);\n\t });\n\t }\n\n\t return sum / field_count;\n\t };\n\t }();\n\n\t if (token_count === 1) {\n\t return function (data) {\n\t return scoreObject(tokens[0], data);\n\t };\n\t }\n\n\t if (search.options.conjunction === 'and') {\n\t return function (data) {\n\t var score,\n\t sum = 0;\n\n\t for (let token of tokens) {\n\t score = scoreObject(token, data);\n\t if (score <= 0) return 0;\n\t sum += score;\n\t }\n\n\t return sum / token_count;\n\t };\n\t } else {\n\t return function (data) {\n\t var sum = 0;\n\t iterate$1(tokens, token => {\n\t sum += scoreObject(token, data);\n\t });\n\t return sum / token_count;\n\t };\n\t }\n\t }\n\n\t /**\n\t * Returns a function that can be used to compare two\n\t * results, for sorting purposes. If no sorting should\n\t * be performed, `null` will be returned.\n\t *\n\t * @return function(a,b)\n\t */\n\t getSortFunction(query, options) {\n\t var search = this.prepareSearch(query, options);\n\t return this._getSortFunction(search);\n\t }\n\n\t _getSortFunction(search) {\n\t var implicit_score,\n\t sort_flds = [];\n\t const self = this,\n\t options = search.options,\n\t sort = !search.query && options.sort_empty ? options.sort_empty : options.sort;\n\n\t if (typeof sort == 'function') {\n\t return sort.bind(this);\n\t }\n\t /**\n\t * Fetches the specified sort field value\n\t * from a search result item.\n\t *\n\t */\n\n\n\t const get_field = function get_field(name, result) {\n\t if (name === '$score') return result.score;\n\t return search.getAttrFn(self.items[result.id], name);\n\t }; // parse options\n\n\n\t if (sort) {\n\t for (let s of sort) {\n\t if (search.query || s.field !== '$score') {\n\t sort_flds.push(s);\n\t }\n\t }\n\t } // the \"$score\" field is implied to be the primary\n\t // sort field, unless it's manually specified\n\n\n\t if (search.query) {\n\t implicit_score = true;\n\n\t for (let fld of sort_flds) {\n\t if (fld.field === '$score') {\n\t implicit_score = false;\n\t break;\n\t }\n\t }\n\n\t if (implicit_score) {\n\t sort_flds.unshift({\n\t field: '$score',\n\t direction: 'desc'\n\t });\n\t } // without a search.query, all items will have the same score\n\n\t } else {\n\t sort_flds = sort_flds.filter(fld => fld.field !== '$score');\n\t } // build function\n\n\n\t const sort_flds_count = sort_flds.length;\n\n\t if (!sort_flds_count) {\n\t return null;\n\t }\n\n\t return function (a, b) {\n\t var result, field;\n\n\t for (let sort_fld of sort_flds) {\n\t field = sort_fld.field;\n\t let multiplier = sort_fld.direction === 'desc' ? -1 : 1;\n\t result = multiplier * cmp(get_field(field, a), get_field(field, b));\n\t if (result) return result;\n\t }\n\n\t return 0;\n\t };\n\t }\n\n\t /**\n\t * Parses a search query and returns an object\n\t * with tokens and fields ready to be populated\n\t * with results.\n\t *\n\t */\n\t prepareSearch(query, optsUser) {\n\t const weights = {};\n\t var options = Object.assign({}, optsUser);\n\t propToArray(options, 'sort');\n\t propToArray(options, 'sort_empty'); // convert fields to new format\n\n\t if (options.fields) {\n\t propToArray(options, 'fields');\n\t const fields = [];\n\t options.fields.forEach(field => {\n\t if (typeof field == 'string') {\n\t field = {\n\t field: field,\n\t weight: 1\n\t };\n\t }\n\n\t fields.push(field);\n\t weights[field.field] = 'weight' in field ? field.weight : 1;\n\t });\n\t options.fields = fields;\n\t }\n\n\t return {\n\t options: options,\n\t query: query.toLowerCase().trim(),\n\t tokens: this.tokenize(query, options.respect_word_boundaries, weights),\n\t total: 0,\n\t items: [],\n\t weights: weights,\n\t getAttrFn: options.nesting ? getAttrNesting : getAttr\n\t };\n\t }\n\n\t /**\n\t * Searches through all items and returns a sorted array of matches.\n\t *\n\t */\n\t search(query, options) {\n\t var self = this,\n\t score,\n\t search;\n\t search = this.prepareSearch(query, options);\n\t options = search.options;\n\t query = search.query; // generate result scoring function\n\n\t const fn_score = options.score || self._getScoreFunction(search); // perform search and sort\n\n\n\t if (query.length) {\n\t iterate$1(self.items, (item, id) => {\n\t score = fn_score(item);\n\n\t if (options.filter === false || score > 0) {\n\t search.items.push({\n\t 'score': score,\n\t 'id': id\n\t });\n\t }\n\t });\n\t } else {\n\t iterate$1(self.items, (_, id) => {\n\t search.items.push({\n\t 'score': 1,\n\t 'id': id\n\t });\n\t });\n\t }\n\n\t const fn_sort = self._getSortFunction(search);\n\n\t if (fn_sort) search.items.sort(fn_sort); // apply limits\n\n\t search.total = search.items.length;\n\n\t if (typeof options.limit === 'number') {\n\t search.items = search.items.slice(0, options.limit);\n\t }\n\n\t return search;\n\t }\n\n\t}\n\n\t/**\n\t * Iterates over arrays and hashes.\n\t *\n\t * ```\n\t * iterate(this.items, function(item, id) {\n\t * // invoked for each item\n\t * });\n\t * ```\n\t *\n\t */\n\n\tconst iterate = (object, callback) => {\n\t if (Array.isArray(object)) {\n\t object.forEach(callback);\n\t } else {\n\t for (var key in object) {\n\t if (object.hasOwnProperty(key)) {\n\t callback(object[key], key);\n\t }\n\t }\n\t }\n\t};\n\n\t/**\n\t * Return a dom element from either a dom query string, jQuery object, a dom element or html string\n\t * https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518\n\t *\n\t * param query should be {}\n\t */\n\n\tconst getDom = query => {\n\t if (query.jquery) {\n\t return query[0];\n\t }\n\n\t if (query instanceof HTMLElement) {\n\t return query;\n\t }\n\n\t if (isHtmlString(query)) {\n\t var tpl = document.createElement('template');\n\t tpl.innerHTML = query.trim(); // Never return a text node of whitespace as the result\n\n\t return tpl.content.firstChild;\n\t }\n\n\t return document.querySelector(query);\n\t};\n\tconst isHtmlString = arg => {\n\t if (typeof arg === 'string' && arg.indexOf('<') > -1) {\n\t return true;\n\t }\n\n\t return false;\n\t};\n\tconst escapeQuery = query => {\n\t return query.replace(/['\"\\\\]/g, '\\\\$&');\n\t};\n\t/**\n\t * Dispatch an event\n\t *\n\t */\n\n\tconst triggerEvent = (dom_el, event_name) => {\n\t var event = document.createEvent('HTMLEvents');\n\t event.initEvent(event_name, true, false);\n\t dom_el.dispatchEvent(event);\n\t};\n\t/**\n\t * Apply CSS rules to a dom element\n\t *\n\t */\n\n\tconst applyCSS = (dom_el, css) => {\n\t Object.assign(dom_el.style, css);\n\t};\n\t/**\n\t * Add css classes\n\t *\n\t */\n\n\tconst addClasses = (elmts, ...classes) => {\n\t var norm_classes = classesArray(classes);\n\t elmts = castAsArray(elmts);\n\t elmts.map(el => {\n\t norm_classes.map(cls => {\n\t el.classList.add(cls);\n\t });\n\t });\n\t};\n\t/**\n\t * Remove css classes\n\t *\n\t */\n\n\tconst removeClasses = (elmts, ...classes) => {\n\t var norm_classes = classesArray(classes);\n\t elmts = castAsArray(elmts);\n\t elmts.map(el => {\n\t norm_classes.map(cls => {\n\t el.classList.remove(cls);\n\t });\n\t });\n\t};\n\t/**\n\t * Return arguments\n\t *\n\t */\n\n\tconst classesArray = args => {\n\t var classes = [];\n\t iterate(args, _classes => {\n\t if (typeof _classes === 'string') {\n\t _classes = _classes.trim().split(/[\\11\\12\\14\\15\\40]/);\n\t }\n\n\t if (Array.isArray(_classes)) {\n\t classes = classes.concat(_classes);\n\t }\n\t });\n\t return classes.filter(Boolean);\n\t};\n\t/**\n\t * Create an array from arg if it's not already an array\n\t *\n\t */\n\n\tconst castAsArray = arg => {\n\t if (!Array.isArray(arg)) {\n\t arg = [arg];\n\t }\n\n\t return arg;\n\t};\n\t/**\n\t * Get the closest node to the evt.target matching the selector\n\t * Stops at wrapper\n\t *\n\t */\n\n\tconst parentMatch = (target, selector, wrapper) => {\n\t if (wrapper && !wrapper.contains(target)) {\n\t return;\n\t }\n\n\t while (target && target.matches) {\n\t if (target.matches(selector)) {\n\t return target;\n\t }\n\n\t target = target.parentNode;\n\t }\n\t};\n\t/**\n\t * Get the first or last item from an array\n\t *\n\t * > 0 - right (last)\n\t * <= 0 - left (first)\n\t *\n\t */\n\n\tconst getTail = (list, direction = 0) => {\n\t if (direction > 0) {\n\t return list[list.length - 1];\n\t }\n\n\t return list[0];\n\t};\n\t/**\n\t * Return true if an object is empty\n\t *\n\t */\n\n\tconst isEmptyObject = obj => {\n\t return Object.keys(obj).length === 0;\n\t};\n\t/**\n\t * Get the index of an element amongst sibling nodes of the same type\n\t *\n\t */\n\n\tconst nodeIndex = (el, amongst) => {\n\t if (!el) return -1;\n\t amongst = amongst || el.nodeName;\n\t var i = 0;\n\n\t while (el = el.previousElementSibling) {\n\t if (el.matches(amongst)) {\n\t i++;\n\t }\n\t }\n\n\t return i;\n\t};\n\t/**\n\t * Set attributes of an element\n\t *\n\t */\n\n\tconst setAttr = (el, attrs) => {\n\t iterate(attrs, (val, attr) => {\n\t if (val == null) {\n\t el.removeAttribute(attr);\n\t } else {\n\t el.setAttribute(attr, '' + val);\n\t }\n\t });\n\t};\n\t/**\n\t * Replace a node\n\t */\n\n\tconst replaceNode = (existing, replacement) => {\n\t if (existing.parentNode) existing.parentNode.replaceChild(replacement, existing);\n\t};\n\n\t/**\n\t * highlight v3 | MIT license | Johann Burkard <[email protected]>\n\t * Highlights arbitrary terms in a node.\n\t *\n\t * - Modified by Marshal <[email protected]> 2011-6-24 (added regex)\n\t * - Modified by Brian Reavis <[email protected]> 2012-8-27 (cleanup)\n\t */\n\tconst highlight = (element, regex) => {\n\t if (regex === null) return; // convet string to regex\n\n\t if (typeof regex === 'string') {\n\t if (!regex.length) return;\n\t regex = new RegExp(regex, 'i');\n\t } // Wrap matching part of text node with highlighting <span>, e.g.\n\t // Soccer -> <span class=\"highlight\">Soc</span>cer for regex = /soc/i\n\n\n\t const highlightText = node => {\n\t var match = node.data.match(regex);\n\n\t if (match && node.data.length > 0) {\n\t var spannode = document.createElement('span');\n\t spannode.className = 'highlight';\n\t var middlebit = node.splitText(match.index);\n\t middlebit.splitText(match[0].length);\n\t var middleclone = middlebit.cloneNode(true);\n\t spannode.appendChild(middleclone);\n\t replaceNode(middlebit, spannode);\n\t return 1;\n\t }\n\n\t return 0;\n\t }; // Recurse element node, looking for child text nodes to highlight, unless element\n\t // is childless, <script>, <style>, or already highlighted: <span class=\"hightlight\">\n\n\n\t const highlightChildren = node => {\n\t if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName) && (node.className !== 'highlight' || node.tagName !== 'SPAN')) {\n\t Array.from(node.childNodes).forEach(element => {\n\t highlightRecursive(element);\n\t });\n\t }\n\t };\n\n\t const highlightRecursive = node => {\n\t if (node.nodeType === 3) {\n\t return highlightText(node);\n\t }\n\n\t highlightChildren(node);\n\t return 0;\n\t };\n\n\t highlightRecursive(element);\n\t};\n\t/**\n\t * removeHighlight fn copied from highlight v5 and\n\t * edited to remove with(), pass js strict mode, and use without jquery\n\t */\n\n\tconst removeHighlight = el => {\n\t var elements = el.querySelectorAll(\"span.highlight\");\n\t Array.prototype.forEach.call(elements, function (el) {\n\t var parent = el.parentNode;\n\t parent.replaceChild(el.firstChild, el);\n\t parent.normalize();\n\t });\n\t};\n\n\tconst KEY_A = 65;\n\tconst KEY_RETURN = 13;\n\tconst KEY_ESC = 27;\n\tconst KEY_LEFT = 37;\n\tconst KEY_UP = 38;\n\tconst KEY_RIGHT = 39;\n\tconst KEY_DOWN = 40;\n\tconst KEY_BACKSPACE = 8;\n\tconst KEY_DELETE = 46;\n\tconst KEY_TAB = 9;\n\tconst IS_MAC = typeof navigator === 'undefined' ? false : /Mac/.test(navigator.userAgent);\n\tconst KEY_SHORTCUT = IS_MAC ? 'metaKey' : 'ctrlKey'; // ctrl key or apple key for ma\n\n\tvar defaults = {\n\t options: [],\n\t optgroups: [],\n\t plugins: [],\n\t delimiter: ',',\n\t splitOn: null,\n\t // regexp or string for splitting up values from a paste command\n\t persist: true,\n\t diacritics: true,\n\t create: null,\n\t createOnBlur: false,\n\t createFilter: null,\n\t highlight: true,\n\t openOnFocus: true,\n\t shouldOpen: null,\n\t maxOptions: 50,\n\t maxItems: null,\n\t hideSelected: null,\n\t duplicates: false,\n\t addPrecedence: false,\n\t selectOnTab: false,\n\t preload: null,\n\t allowEmptyOption: false,\n\t //closeAfterSelect: false,\n\t loadThrottle: 300,\n\t loadingClass: 'loading',\n\t dataAttr: null,\n\t //'data-data',\n\t optgroupField: 'optgroup',\n\t valueField: 'value',\n\t labelField: 'text',\n\t disabledField: 'disabled',\n\t optgroupLabelField: 'label',\n\t optgroupValueField: 'value',\n\t lockOptgroupOrder: false,\n\t sortField: '$order',\n\t searchField: ['text'],\n\t searchConjunction: 'and',\n\t mode: null,\n\t wrapperClass: 'ts-wrapper',\n\t controlClass: 'ts-control',\n\t dropdownClass: 'ts-dropdown',\n\t dropdownContentClass: 'ts-dropdown-content',\n\t itemClass: 'item',\n\t optionClass: 'option',\n\t dropdownParent: null,\n\t controlInput: '<input type=\"text\" autocomplete=\"off\" size=\"1\" />',\n\t copyClassesToDropdown: false,\n\t placeholder: null,\n\t hidePlaceholder: null,\n\t shouldLoad: function (query) {\n\t return query.length > 0;\n\t },\n\n\t /*\n\t load : null, // function(query, callback) { ... }\n\t score : null, // function(search) { ... }\n\t onInitialize : null, // function() { ... }\n\t onChange : null, // function(value) { ... }\n\t onItemAdd : null, // function(value, $item) { ... }\n\t onItemRemove : null, // function(value) { ... }\n\t onClear : null, // function() { ... }\n\t onOptionAdd : null, // function(value, data) { ... }\n\t onOptionRemove : null, // function(value) { ... }\n\t onOptionClear : null, // function() { ... }\n\t onOptionGroupAdd : null, // function(id, data) { ... }\n\t onOptionGroupRemove : null, // function(id) { ... }\n\t onOptionGroupClear : null, // function() { ... }\n\t onDropdownOpen : null, // function(dropdown) { ... }\n\t onDropdownClose : null, // function(dropdown) { ... }\n\t onType : null, // function(str) { ... }\n\t onDelete : null, // function(values) { ... }\n\t */\n\t render: {\n\t /*\n\t item: null,\n\t optgroup: null,\n\t optgroup_header: null,\n\t option: null,\n\t option_create: null\n\t */\n\t }\n\t};\n\n\t/**\n\t * Converts a scalar to its best string representation\n\t * for hash keys and HTML attribute values.\n\t *\n\t * Transformations:\n\t * 'str' -> 'str'\n\t * null -> ''\n\t * undefined -> ''\n\t * true -> '1'\n\t * false -> '0'\n\t * 0 -> '0'\n\t * 1 -> '1'\n\t *\n\t */\n\tconst hash_key = value => {\n\t if (typeof value === 'undefined' || value === null) return null;\n\t return get_hash(value);\n\t};\n\tconst get_hash = value => {\n\t if (typeof value === 'boolean') return value ? '1' : '0';\n\t return value + '';\n\t};\n\t/**\n\t * Escapes a string for use within HTML.\n\t *\n\t */\n\n\tconst escape_html = str => {\n\t return (str + '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n\t};\n\t/**\n\t * Debounce the user provided load function\n\t *\n\t */\n\n\tconst loadDebounce = (fn, delay) => {\n\t var timeout;\n\t return function (value, callback) {\n\t var self = this;\n\n\t if (timeout) {\n\t self.loading = Math.max(self.loading - 1, 0);\n\t clearTimeout(timeout);\n\t }\n\n\t timeout = setTimeout(function () {\n\t timeout = null;\n\t self.loadedSearches[value] = true;\n\t fn.call(self, value, callback);\n\t }, delay);\n\t };\n\t};\n\t/**\n\t * Debounce all fired events types listed in `types`\n\t * while executing the provided `fn`.\n\t *\n\t */\n\n\tconst debounce_events = (self, types, fn) => {\n\t var type;\n\t var trigger = self.trigger;\n\t var event_args = {}; // override trigger method\n\n\t self.trigger = function () {\n\t var type = arguments[0];\n\n\t if (types.indexOf(type) !== -1) {\n\t event_args[type] = arguments;\n\t } else {\n\t return trigger.apply(self, arguments);\n\t }\n\t }; // invoke provided function\n\n\n\t fn.apply(self, []);\n\t self.trigger = trigger; // trigger queued events\n\n\t for (type of types) {\n\t if (type in event_args) {\n\t trigger.apply(self, event_args[type]);\n\t }\n\t }\n\t};\n\t/**\n\t * Determines the current selection within a text input control.\n\t * Returns an object containing:\n\t * - start\n\t * - length\n\t *\n\t */\n\n\tconst getSelection = input => {\n\t return {\n\t start: input.selectionStart || 0,\n\t length: (input.selectionEnd || 0) - (input.selectionStart || 0)\n\t };\n\t};\n\t/**\n\t * Prevent default\n\t *\n\t */\n\n\tconst preventDefault = (evt, stop = false) => {\n\t if (evt) {\n\t evt.preventDefault();\n\n\t if (stop) {\n\t evt.stopPropagation();\n\t }\n\t }\n\t};\n\t/**\n\t * Add event helper\n\t *\n\t */\n\n\tconst addEvent = (target, type, callback, options) => {\n\t target.addEventListener(type, callback, options);\n\t};\n\t/**\n\t * Return true if the requested key is down\n\t * Will return false if more than one control character is pressed ( when [ctrl+shift+a] != [ctrl+a] )\n\t * The current evt may not always set ( eg calling advanceSelection() )\n\t *\n\t */\n\n\tconst isKeyDown = (key_name, evt) => {\n\t if (!evt) {\n\t return false;\n\t }\n\n\t if (!evt[key_name]) {\n\t return false;\n\t }\n\n\t var count = (evt.altKey ? 1 : 0) + (evt.ctrlKey ? 1 : 0) + (evt.shiftKey ? 1 : 0) + (evt.metaKey ? 1 : 0);\n\n\t if (count === 1) {\n\t return true;\n\t }\n\n\t return false;\n\t};\n\t/**\n\t * Get the id of an element\n\t * If the id attribute is not set, set the attribute with the given id\n\t *\n\t */\n\n\tconst getId = (el, id) => {\n\t const existing_id = el.getAttribute('id');\n\n\t if (existing_id) {\n\t return existing_id;\n\t }\n\n\t el.setAttribute('id', id);\n\t return id;\n\t};\n\t/**\n\t * Returns a string with backslashes added before characters that need to be escaped.\n\t */\n\n\tconst addSlashes = str => {\n\t return str.replace(/[\\\\\"']/g, '\\\\$&');\n\t};\n\t/**\n\t *\n\t */\n\n\tconst append = (parent, node) => {\n\t if (node) parent.append(node);\n\t};\n\n\tfunction getSettings(input, settings_user) {\n\t var settings = Object.assign({}, defaults, settings_user);\n\t var attr_data = settings.dataAttr;\n\t var field_label = settings.labelField;\n\t var field_value = settings.valueField;\n\t var field_disabled = settings.disabledField;\n\t var field_optgroup = settings.optgroupField;\n\t var field_optgroup_label = settings.optgroupLabelField;\n\t var field_optgroup_value = settings.optgroupValueField;\n\t var tag_name = input.tagName.toLowerCase();\n\t var placeholder = input.getAttribute('placeholder') || input.getAttribute('data-placeholder');\n\n\t if (!placeholder && !settings.allowEmptyOption) {\n\t let option = input.querySelector('option[value=\"\"]');\n\n\t if (option) {\n\t placeholder = option.textContent;\n\t }\n\t }\n\n\t var settings_element = {\n\t placeholder: placeholder,\n\t options: [],\n\t optgroups: [],\n\t items: [],\n\t maxItems: null\n\t };\n\t /**\n\t * Initialize from a <select> element.\n\t *\n\t */\n\n\t var init_select = () => {\n\t var tagName;\n\t var options = settings_element.options;\n\t var optionsMap = {};\n\t var group_count = 1;\n\n\t var readData = el => {\n\t var data = Object.assign({}, el.dataset); // get plain object from DOMStringMap\n\n\t var json = attr_data && data[attr_data];\n\n\t if (typeof json === 'string' && json.length) {\n\t data = Object.assign(data, JSON.parse(json));\n\t }\n\n\t return data;\n\t };\n\n\t var addOption = (option, group) => {\n\t var value = hash_key(option.value);\n\t if (value == null) return;\n\t if (!value && !settings.allowEmptyOption) return; // if the option already exists, it's probably been\n\t // duplicated in another optgroup. in this case, push\n\t // the current group to the \"optgroup\" property on the\n\t // existing option so that it's rendered in both places.\n\n\t if (optionsMap.hasOwnProperty(value)) {\n\t if (group) {\n\t var arr = optionsMap[value][field_optgroup];\n\n\t if (!arr) {\n\t optionsMap[value][field_optgroup] = group;\n\t } else if (!Array.isArray(arr)) {\n\t optionsMap[value][field_optgroup] = [arr, group];\n\t } else {\n\t arr.push(group);\n\t }\n\t }\n\t } else {\n\t var option_data = readData(option);\n\t option_data[field_label] = option_data[field_label] || option.textContent;\n\t option_data[field_value] = option_data[field_value] || value;\n\t option_data[field_disabled] = option_data[field_disabled] || option.disabled;\n\t option_data[field_optgroup] = option_data[field_optgroup] || group;\n\t option_data.$option = option;\n\t optionsMap[value] = option_data;\n\t options.push(option_data);\n\t }\n\n\t if (option.selected) {\n\t settings_element.items.push(value);\n\t }\n\t };\n\n\t var addGroup = optgroup => {\n\t var id, optgroup_data;\n\t optgroup_data = readData(optgroup);\n\t optgroup_data[field_optgroup_label] = optgroup_data[field_optgroup_label] || optgroup.getAttribute('label') || '';\n\t optgroup_data[field_optgroup_value] = optgroup_data[field_optgroup_value] || group_count++;\n\t optgroup_data[field_disabled] = optgroup_data[field_disabled] || optgroup.disabled;\n\t settings_element.optgroups.push(optgroup_data);\n\t id = optgroup_data[field_optgroup_value];\n\t iterate(optgroup.children, option => {\n\t addOption(option, id);\n\t });\n\t };\n\n\t settings_element.maxItems = input.hasAttribute('multiple') ? null : 1;\n\t iterate(input.children, child => {\n\t tagName = child.tagName.toLowerCase();\n\n\t if (tagName === 'optgroup') {\n\t addGroup(child);\n\t } else if (tagName === 'option') {\n\t addOption(child);\n\t }\n\t });\n\t };\n\t /**\n\t * Initialize from a <input type=\"text\"> element.\n\t *\n\t */\n\n\n\t var init_textbox = () => {\n\t const data_raw = input.getAttribute(attr_data);\n\n\t if (!data_raw) {\n\t var value = input.value.trim() || '';\n\t if (!settings.allowEmptyOption && !value.length) return;\n\t const values = value.split(settings.delimiter);\n\t iterate(values, value => {\n\t const option = {};\n\t option[field_label] = value;\n\t option[field_value] = value;\n\t settings_element.options.push(option);\n\t });\n\t settings_element.items = values;\n\t } else {\n\t settings_element.options = JSON.parse(data_raw);\n\t iterate(settings_element.options, opt => {\n\t settings_element.items.push(opt[field_value]);\n\t });\n\t }\n\t };\n\n\t if (tag_name === 'select') {\n\t init_select();\n\t } else {\n\t init_textbox();\n\t }\n\n\t return Object.assign({}, defaults, settings_element, settings_user);\n\t}\n\n\tvar instance_i = 0;\n\tclass TomSelect extends MicroPlugin(MicroEvent) {\n\t // @deprecated 1.8\n\t constructor(input_arg, user_settings) {\n\t super();\n\t this.control_input = void 0;\n\t this.wrapper = void 0;\n\t this.dropdown = void 0;\n\t this.control = void 0;\n\t this.dropdown_content = void 0;\n\t this.focus_node = void 0;\n\t this.order = 0;\n\t this.settings = void 0;\n\t this.input = void 0;\n\t this.tabIndex = void 0;\n\t this.is_select_tag = void 0;\n\t this.rtl = void 0;\n\t this.inputId = void 0;\n\t this._destroy = void 0;\n\t this.sifter = void 0;\n\t this.isOpen = false;\n\t this.isDisabled = false;\n\t this.isRequired = void 0;\n\t this.isInvalid = false;\n\t this.isValid = true;\n\t this.isLocked = false;\n\t this.isFocused = false;\n\t this.isInputHidden = false;\n\t this.isSetup = false;\n\t this.ignoreFocus = false;\n\t this.ignoreHover = false;\n\t this.hasOptions = false;\n\t this.currentResults = void 0;\n\t this.lastValue = '';\n\t this.caretPos = 0;\n\t this.loading = 0;\n\t this.loadedSearches = {};\n\t this.activeOption = null;\n\t this.activeItems = [];\n\t this.optgroups = {};\n\t this.options = {};\n\t this.userOptions = {};\n\t this.items = [];\n\t instance_i++;\n\t var dir;\n\t var input = getDom(input_arg);\n\n\t if (input.tomselect) {\n\t throw new Error('Tom Select already initialized on this element');\n\t }\n\n\t input.tomselect = this; // detect rtl environment\n\n\t var computedStyle = window.getComputedStyle && window.getComputedStyle(input, null);\n\t dir = computedStyle.getPropertyValue('direction'); // setup default state\n\n\t const settings = getSettings(input, user_settings);\n\t this.settings = settings;\n\t this.input = input;\n\t this.tabIndex = input.tabIndex || 0;\n\t this.is_select_tag = input.tagName.toLowerCase() === 'select';\n\t this.rtl = /rtl/i.test(dir);\n\t this.inputId = getId(input, 'tomselect-' + instance_i);\n\t this.isRequired = input.required; // search system\n\n\t this.sifter = new Sifter(this.options, {\n\t diacritics: settings.diacritics\n\t }); // option-dependent defaults\n\n\t settings.mode = settings.mode || (settings.maxItems === 1 ? 'single' : 'multi');\n\n\t if (typeof settings.hideSelected !== 'boolean') {\n\t settings.hideSelected = settings.mode === 'multi';\n\t }\n\n\t if (typeof settings.hidePlaceholder !== 'boolean') {\n\t settings.hidePlaceholder = settings.mode !== 'multi';\n\t } // set up createFilter callback\n\n\n\t var filter = settings.createFilter;\n\n\t if (typeof filter !== 'function') {\n\t if (typeof filter === 'string') {\n\t filter = new RegExp(filter);\n\t }\n\n\t if (filter instanceof RegExp) {\n\t settings.createFilter = input => filter.test(input);\n\t } else {\n\t settings.createFilter = value => {\n\t return this.settings.duplicates || !this.options[value];\n\t };\n\t }\n\t }\n\n\t this.initializePlugins(settings.plugins);\n\t this.setupCallbacks();\n\t this.setupTemplates(); // Create all elements\n\n\t const wrapper = getDom('<div>');\n\t const control = getDom('<div>');\n\n\t const dropdown = this._render('dropdown');\n\n\t const dropdown_content = getDom(`<div role=\"listbox\" tabindex=\"-1\">`);\n\t const classes = this.input.getAttribute('class') || '';\n\t const inputMode = settings.mode;\n\t var control_input;\n\t addClasses(wrapper, settings.wrapperClass, classes, inputMode);\n\t addClasses(control, settings.controlClass);\n\t append(wrapper, control);\n\t addClasses(dropdown, settings.dropdownClass, inputMode);\n\n\t if (settings.copyClassesToDropdown) {\n\t addClasses(dropdown, classes);\n\t }\n\n\t addClasses(dropdown_content, settings.dropdownContentClass);\n\t append(dropdown, dropdown_content);\n\t getDom(settings.dropdownParent || wrapper).appendChild(dropdown); // default controlInput\n\n\t if (isHtmlString(settings.controlInput)) {\n\t control_input = getDom(settings.controlInput); // set attributes\n\n\t var attrs = ['autocorrect', 'autocapitalize', 'autocomplete'];\n\t iterate$1(attrs, attr => {\n\t if (input.getAttribute(attr)) {\n\t setAttr(control_input, {\n\t [attr]: input.getAttribute(attr)\n\t });\n\t }\n\t });\n\t control_input.tabIndex = -1;\n\t control.appendChild(control_input);\n\t this.focus_node = control_input; // dom element\n\t } else if (settings.controlInput) {\n\t control_input = getDom(settings.controlInput);\n\t this.focus_node = control_input;\n\t } else {\n\t control_input = getDom('<input/>');\n\t this.focus_node = control;\n\t }\n\n\t this.wrapper = wrapper;\n\t this.dropdown = dropdown;\n\t this.dropdown_content = dropdown_content;\n\t this.control = control;\n\t this.control_input = control_input;\n\t this.setup();\n\t }\n\t /**\n\t * set up event bindings.\n\t *\n\t */\n\n\n\t setup() {\n\t const self = this;\n\t const settings = self.settings;\n\t const control_input = self.control_input;\n\t const dropdown = self.dropdown;\n\t const dropdown_content = self.dropdown_content;\n\t const wrapper = self.wrapper;\n\t const control = self.control;\n\t const input = self.input;\n\t const focus_node = self.focus_node;\n\t const passive_event = {\n\t passive: true\n\t };\n\t const listboxId = self.inputId + '-ts-dropdown';\n\t setAttr(dropdown_content, {\n\t id: listboxId\n\t });\n\t setAttr(focus_node, {\n\t role: 'combobox',\n\t 'aria-haspopup': 'listbox',\n\t 'aria-expanded': 'false',\n\t 'aria-controls': listboxId\n\t });\n\t const control_id = getId(focus_node, self.inputId + '-ts-control');\n\t const query = \"label[for='\" + escapeQuery(self.inputId) + \"']\";\n\t const label = document.querySelector(query);\n\t const label_click = self.focus.bind(self);\n\n\t if (label) {\n\t addEvent(label, 'click', label_click);\n\t setAttr(label, {\n\t for: control_id\n\t });\n\t const label_id = getId(label, self.inputId + '-ts-label');\n\t setAttr(focus_node, {\n\t 'aria-labelledby': label_id\n\t });\n\t setAttr(dropdown_content, {\n\t 'aria-labelledby': label_id\n\t });\n\t }\n\n\t wrapper.style.width = input.style.width;\n\n\t if (self.plugins.names.length) {\n\t const classes_plugins = 'plugin-' + self.plugins.names.join(' plugin-');\n\t addClasses([wrapper, dropdown], classes_plugins);\n\t }\n\n\t if ((settings.maxItems === null || settings.maxItems > 1) && self.is_select_tag) {\n\t setAttr(input, {\n\t multiple: 'multiple'\n\t });\n\t }\n\n\t if (settings.placeholder) {\n\t setAttr(control_input, {\n\t placeholder: settings.placeholder\n\t });\n\t } // if splitOn was not passed in, construct it from the delimiter to allow pasting universally\n\n\n\t if (!settings.splitOn && settings.delimiter) {\n\t settings.splitOn = new RegExp('\\\\s*' + escape_regex(settings.delimiter) + '+\\\\s*');\n\t } // debounce user defined load() if loadThrottle > 0\n\t // after initializePlugins() so plugins can create/modify user defined loaders\n\n\n\t if (settings.load && settings.loadThrottle) {\n\t settings.load = loadDebounce(settings.load, settings.loadThrottle);\n\t }\n\n\t self.control_input.type = input.type;\n\t addEvent(dropdown, 'mousemove', () => {\n\t self.ignoreHover = false;\n\t });\n\t addEvent(dropdown, 'mouseenter', e => {\n\t var target_match = parentMatch(e.target, '[data-selectable]', dropdown);\n\t if (target_match) self.onOptionHover(e, target_match);\n\t }, {\n\t capture: true\n\t }); // clicking on an option should select it\n\n\t addEvent(dropdown, 'click', evt => {\n\t const option = parentMatch(evt.target, '[data-selectable]');\n\n\t if (option) {\n\t self.onOptionSelect(evt, option);\n\t preventDefault(evt, true);\n\t }\n\t });\n\t addEvent(control, 'click', evt => {\n\t var target_match = parentMatch(evt.target, '[data-ts-item]', control);\n\n\t if (target_match && self.onItemSelect(evt, target_match)) {\n\t preventDefault(evt, true);\n\t return;\n\t } // retain focus (see control_input mousedown)\n\n\n\t if (control_input.value != '') {\n\t return;\n\t }\n\n\t self.onClick();\n\t preventDefault(evt, true);\n\t }); // keydown on focus_node for arrow_down/arrow_up\n\n\t addEvent(focus_node, 'keydown', e => self.onKeyDown(e)); // keypress and input/keyup\n\n\t addEvent(control_input, 'keypress', e => self.onKeyPress(e));\n\t addEvent(control_input, 'input', e => self.onInput(e));\n\t addEvent(focus_node, 'blur', e => self.onBlur(e));\n\t addEvent(focus_node, 'focus', e => self.onFocus(e));\n\t addEvent(control_input, 'paste', e => self.onPaste(e));\n\n\t const doc_mousedown = evt => {\n\t // blur if target is outside of this instance\n\t // dropdown is not always inside wrapper\n\t const target = evt.composedPath()[0];\n\n\t if (!wrapper.contains(target) && !dropdown.contains(target)) {\n\t if (self.isFocused) {\n\t self.blur();\n\t }\n\n\t self.inputState();\n\t return;\n\t } // retain focus by preventing native handling. if the\n\t // event target is the input it should not be modified.\n\t // otherwise, text selection within the input won't work.\n\t // Fixes bug #212 which is no covered by tests\n\n\n\t if (target == control_input && self.isOpen) {\n\t evt.stopPropagation(); // clicking anywhere in the control should not blur the control_input (which would close the dropdown)\n\t } else {\n\t preventDefault(evt, true);\n\t }\n\t };\n\n\t const win_scroll = () => {\n\t if (self.isOpen) {\n\t self.positionDropdown();\n\t }\n\t };\n\n\t addEvent(document, 'mousedown', doc_mousedown);\n\t addEvent(window, 'scroll', win_scroll, passive_event);\n\t addEvent(window, 'resize', win_scroll, passive_event);\n\n\t this._destroy = () => {\n\t document.removeEventListener('mousedown', doc_mousedown);\n\t window.removeEventListener('scroll', win_scroll);\n\t window.removeEventListener('resize', win_scroll);\n\t if (label) label.removeEventListener('click', label_click);\n\t }; // store original html and tab index so that they can be\n\t // restored when the destroy() method is called.\n\n\n\t this.revertSettings = {\n\t innerHTML: input.innerHTML,\n\t tabIndex: input.tabIndex\n\t };\n\t input.tabIndex = -1;\n\t input.insertAdjacentElement('afterend', self.wrapper);\n\t self.sync(false);\n\t settings.items = [];\n\t delete settings.optgroups;\n\t delete settings.options;\n\t addEvent(input, 'invalid', () => {\n\t if (self.isValid) {\n\t self.isValid = false;\n\t self.isInvalid = true;\n\t self.refreshState();\n\t }\n\t });\n\t self.updateOriginalInput();\n\t self.refreshItems();\n\t self.close(false);\n\t self.inputState();\n\t self.isSetup = true;\n\n\t if (input.disabled) {\n\t self.disable();\n\t } else {\n\t self.enable(); //sets tabIndex\n\t }\n\n\t self.on('change', this.onChange);\n\t addClasses(input, 'tomselected', 'ts-hidden-accessible');\n\t self.trigger('initialize'); // preload options\n\n\t if (settings.preload === true) {\n\t self.preload();\n\t }\n\t }\n\t /**\n\t * Register options and optgroups\n\t *\n\t */\n\n\n\t setupOptions(options = [], optgroups = []) {\n\t // build options table\n\t this.addOptions(options); // build optgroup table\n\n\t iterate$1(optgroups, optgroup => {\n\t this.registerOptionGroup(optgroup);\n\t });\n\t }\n\t /**\n\t * Sets up default rendering functions.\n\t */\n\n\n\t setupTemplates() {\n\t var self = this;\n\t var field_label = self.settings.labelField;\n\t var field_optgroup = self.settings.optgroupLabelField;\n\t var templates = {\n\t 'optgroup': data => {\n\t let optgroup = document.createElement('div');\n\t optgroup.className = 'optgroup';\n\t optgroup.appendChild(data.options);\n\t return optgroup;\n\t },\n\t 'optgroup_header': (data, escape) => {\n\t return '<div class=\"optgroup-header\">' + escape(data[field_optgroup]) + '</div>';\n\t },\n\t 'option': (data, escape) => {\n\t return '<div>' + escape(data[field_label]) + '</div>';\n\t },\n\t 'item': (data, escape) => {\n\t return '<div>' + escape(data[field_label]) + '</div>';\n\t },\n\t 'option_create': (data, escape) => {\n\t return '<div class=\"create\">Add <strong>' + escape(data.input) + '</strong>…</div>';\n\t },\n\t 'no_results': () => {\n\t return '<div class=\"no-results\">No results found</div>';\n\t },\n\t 'loading': () => {\n\t return '<div class=\"spinner\"></div>';\n\t },\n\t 'not_loading': () => {},\n\t 'dropdown': () => {\n\t return '<div></div>';\n\t }\n\t };\n\t self.settings.render = Object.assign({}, templates, self.settings.render);\n\t }\n\t /**\n\t * Maps fired events to callbacks provided\n\t * in the settings used when creating the control.\n\t */\n\n\n\t setupCallbacks() {\n\t var key, fn;\n\t var callbacks = {\n\t 'initialize': 'onInitialize',\n\t 'change': 'onChange',\n\t 'item_add': 'onItemAdd',\n\t 'item_remove': 'onItemRemove',\n\t 'item_select': 'onItemSelect',\n\t 'clear': 'onClear',\n\t 'option_add': 'onOptionAdd',\n\t 'option_remove': 'onOptionRemove',\n\t 'option_clear': 'onOptionClear',\n\t 'optgroup_add': 'onOptionGroupAdd',\n\t 'optgroup_remove': 'onOptionGroupRemove',\n\t 'optgroup_clear': 'onOptionGroupClear',\n\t 'dropdown_open': 'onDropdownOpen',\n\t 'dropdown_close': 'onDropdownClose',\n\t 'type': 'onType',\n\t 'load': 'onLoad',\n\t 'focus': 'onFocus',\n\t 'blur': 'onBlur'\n\t };\n\n\t for (key in callbacks) {\n\t fn = this.settings[callbacks[key]];\n\t if (fn) this.on(key, fn);\n\t }\n\t }\n\t /**\n\t * Sync the Tom Select instance with the original input or select\n\t *\n\t */\n\n\n\t sync(get_settings = true) {\n\t const self = this;\n\t const settings = get_settings ? getSettings(self.input, {\n\t delimiter: self.settings.delimiter\n\t }) : self.settings;\n\t self.setupOptions(settings.options, settings.optgroups);\n\t self.setValue(settings.items || [], true); // silent prevents recursion\n\n\t self.lastQuery = null; // so updated options will be displayed in dropdown\n\t }\n\t /**\n\t * Triggered when the main control element\n\t * has a click event.\n\t *\n\t */\n\n\n\t onClick() {\n\t var self = this;\n\n\t if (self.activeItems.length > 0) {\n\t self.clearActiveItems();\n\t self.focus();\n\t return;\n\t }\n\n\t if (self.isFocused && self.isOpen) {\n\t self.blur();\n\t } else {\n\t self.focus();\n\t }\n\t }\n\t /**\n\t * @deprecated v1.7\n\t *\n\t */\n\n\n\t onMouseDown() {}\n\t /**\n\t * Triggered when the value of the control has been changed.\n\t * This should propagate the event to the original DOM\n\t * input / select element.\n\t */\n\n\n\t onChange() {\n\t triggerEvent(this.input, 'input');\n\t triggerEvent(this.input, 'change');\n\t }\n\t /**\n\t * Triggered on <input> paste.\n\t *\n\t */\n\n\n\t onPaste(e) {\n\t var self = this;\n\n\t if (self.isInputHidden || self.isLocked) {\n\t preventDefault(e);\n\t return;\n\t } // If a regex or string is included, this will split the pasted\n\t // input and create Items for each separate value\n\n\n\t if (!self.settings.splitOn) {\n\t return;\n\t } // Wait for pasted text to be recognized in value\n\n\n\t setTimeout(() => {\n\t var pastedText = self.inputValue();\n\n\t if (!pastedText.match(self.settings.splitOn)) {\n\t return;\n\t }\n\n\t var splitInput = pastedText.trim().split(self.settings.splitOn);\n\t iterate$1(splitInput, piece => {\n\t const hash = hash_key(piece);\n\n\t if (hash) {\n\t if (this.options[piece]) {\n\t self.addItem(piece);\n\t } else {\n\t self.createItem(piece);\n\t }\n\t }\n\t });\n\t }, 0);\n\t }\n\t /**\n\t * Triggered on <input> keypress.\n\t *\n\t */\n\n\n\t onKeyPress(e) {\n\t var self = this;\n\n\t if (self.isLocked) {\n\t preventDefault(e);\n\t return;\n\t }\n\n\t var character = String.fromCharCode(e.keyCode || e.which);\n\n\t if (self.settings.create && self.settings.mode === 'multi' && character === self.settings.delimiter) {\n\t self.createItem();\n\t preventDefault(e);\n\t return;\n\t }\n\t }\n\t /**\n\t * Triggered on <input> keydown.\n\t *\n\t */\n\n\n\t onKeyDown(e) {\n\t var self = this;\n\t self.ignoreHover = true;\n\n\t if (self.isLocked) {\n\t if (e.keyCode !== KEY_TAB) {\n\t preventDefault(e);\n\t }\n\n\t return;\n\t }\n\n\t switch (e.keyCode) {\n\t // ctrl+A: select all\n\t case KEY_A:\n\t if (isKeyDown(KEY_SHORTCUT, e)) {\n\t if (self.control_input.value == '') {\n\t preventDefault(e);\n\t self.selectAll();\n\t return;\n\t }\n\t }\n\n\t break;\n\t // esc: close dropdown\n\n\t case KEY_ESC:\n\t if (self.isOpen) {\n\t preventDefault(e, true);\n\t self.close();\n\t }\n\n\t self.clearActiveItems();\n\t return;\n\t // down: open dropdown or move selection down\n\n\t case KEY_DOWN:\n\t if (!self.isOpen && self.hasOptions) {\n\t self.open();\n\t } else if (self.activeOption) {\n\t let next = self.getAdjacent(self.activeOption, 1);\n\t if (next) self.setActiveOption(next);\n\t }\n\n\t preventDefault(e);\n\t return;\n\t // up: move selection up\n\n\t case KEY_UP:\n\t if (self.activeOption) {\n\t let prev = self.getAdjacent(self.activeOption, -1);\n\t if (prev) self.setActiveOption(prev);\n\t }\n\n\t preventDefault(e);\n\t return;\n\t // return: select active option\n\n\t case KEY_RETURN:\n\t if (self.canSelect(self.activeOption)) {\n\t self.onOptionSelect(e, self.activeOption);\n\t preventDefault(e); // if the option_create=null, the dropdown might be closed\n\t } else if (self.settings.create && self.createItem()) {\n\t preventDefault(e); // don't submit form when searching for a value\n\t } else if (document.activeElement == self.control_input && self.isOpen) {\n\t preventDefault(e);\n\t }\n\n\t return;\n\t // left: modifiy item selection to the left\n\n\t case KEY_LEFT:\n\t self.advanceSelection(-1, e);\n\t return;\n\t // right: modifiy item selection to the right\n\n\t case KEY_RIGHT:\n\t self.advanceSelection(1, e);\n\t return;\n\t // tab: select active option and/or create item\n\n\t case KEY_TAB:\n\t if (self.settings.selectOnTab) {\n\t if (self.canSelect(self.activeOption)) {\n\t self.onOptionSelect(e, self.activeOption); // prevent default [tab] behaviour of jump to the next field\n\t // if select isFull, then the dropdown won't be open and [tab] will work normally\n\n\t preventDefault(e);\n\t }\n\n\t if (self.settings.create && self.createItem()) {\n\t preventDefault(e);\n\t }\n\t }\n\n\t return;\n\t // delete|backspace: delete items\n\n\t case KEY_BACKSPACE:\n\t case KEY_DELETE:\n\t self.deleteSelection(e);\n\t return;\n\t } // don't enter text in the control_input when active items are selected\n\n\n\t if (self.isInputHidden && !isKeyDown(KEY_SHORTCUT, e)) {\n\t preventDefault(e);\n\t }\n\t }\n\t /**\n\t * Triggered on <input> keyup.\n\t *\n\t */\n\n\n\t onInput(e) {\n\t var self = this;\n\n\t if (self.isLocked) {\n\t return;\n\t }\n\n\t var value = self.inputValue();\n\n\t if (self.lastValue !== value) {\n\t self.lastValue = value;\n\n\t if (self.settings.shouldLoad.call(self, value)) {\n\t self.load(value);\n\t }\n\n\t self.refreshOptions();\n\t self.trigger('type', value);\n\t }\n\t }\n\t /**\n\t * Triggered when the user rolls over\n\t * an option in the autocomplete dropdown menu.\n\t *\n\t */\n\n\n\t onOptionHover(evt, option) {\n\t if (this.ignoreHover) return;\n\t this.setActiveOption(option, false);\n\t }\n\t /**\n\t * Triggered on <input> focus.\n\t *\n\t */\n\n\n\t onFocus(e) {\n\t var self = this;\n\t var wasFocused = self.isFocused;\n\n\t if (self.isDisabled) {\n\t self.blur();\n\t preventDefault(e);\n\t return;\n\t }\n\n\t if (self.ignoreFocus) return;\n\t self.isFocused = true;\n\t if (self.settings.preload === 'focus') self.preload();\n\t if (!wasFocused) self.trigger('focus');\n\n\t if (!self.activeItems.length) {\n\t self.showInput();\n\t self.refreshOptions(!!self.settings.openOnFocus);\n\t }\n\n\t self.refreshState();\n\t }\n\t /**\n\t * Triggered on <input> blur.\n\t *\n\t */\n\n\n\t onBlur(e) {\n\t if (document.hasFocus() === false) return;\n\t var self = this;\n\t if (!self.isFocused) return;\n\t self.isFocused = false;\n\t self.ignoreFocus = false;\n\n\t var deactivate = () => {\n\t self.close();\n\t self.setActiveItem();\n\t self.setCaret(self.items.length);\n\t self.trigger('blur');\n\t };\n\n\t if (self.settings.create && self.settings.createOnBlur) {\n\t self.createItem(null, deactivate);\n\t } else {\n\t deactivate();\n\t }\n\t }\n\t /**\n\t * Triggered when the user clicks on an option\n\t * in the autocomplete dropdown menu.\n\t *\n\t */\n\n\n\t onOptionSelect(evt, option) {\n\t var value,\n\t self = this; // should not be possible to trigger a option under a disabled optgroup\n\n\t if (option.parentElement && option.parentElement.matches('[data-disabled]')) {\n\t return;\n\t }\n\n\t if (option.classList.contains('create')) {\n\t self.createItem(null, () => {\n\t if (self.settings.closeAfterSelect) {\n\t self.close();\n\t }\n\t });\n\t } else {\n\t value = option.dataset.value;\n\n\t if (typeof value !== 'undefined') {\n\t self.lastQuery = null;\n\t self.addItem(value);\n\n\t if (self.settings.closeAfterSelect) {\n\t self.close();\n\t }\n\n\t if (!self.settings.hideSelected && evt.type && /click/.test(evt.type)) {\n\t self.setActiveOption(option);\n\t }\n\t }\n\t }\n\t }\n\t /**\n\t * Return true if the given option can be selected\n\t *\n\t */\n\n\n\t canSelect(option) {\n\t if (this.isOpen && option && this.dropdown_content.contains(option)) {\n\t return true;\n\t }\n\n\t return false;\n\t }\n\t /**\n\t * Triggered when the user clicks on an item\n\t * that has been selected.\n\t *\n\t */\n\n\n\t onItemSelect(evt, item) {\n\t var self = this;\n\n\t if (!self.isLocked && self.settings.mode === 'multi') {\n\t preventDefault(evt);\n\t self.setActiveItem(item, evt);\n\t return true;\n\t }\n\n\t return false;\n\t }\n\t /**\n\t * Determines whether or not to invoke\n\t * the user-provided option provider / loader\n\t *\n\t * Note, there is a subtle difference between\n\t * this.canLoad() and this.settings.shouldLoad();\n\t *\n\t *\t- settings.shouldLoad() is a user-input validator.\n\t *\tWhen false is returned, the not_loading template\n\t *\twill be added to the dropdown\n\t *\n\t *\t- canLoad() is lower level validator that checks\n\t * \tthe Tom Select instance. There is no inherent user\n\t *\tfeedback when canLoad returns false\n\t *\n\t */\n\n\n\t canLoad(value) {\n\t if (!this.settings.load) return false;\n\t if (this.loadedSearches.hasOwnProperty(value)) return false;\n\t return true;\n\t }\n\t /**\n\t * Invokes the user-provided option provider / loader.\n\t *\n\t */\n\n\n\t load(value) {\n\t const self = this;\n\t if (!self.canLoad(value)) return;\n\t addClasses(self.wrapper, self.settings.loadingClass);\n\t self.loading++;\n\t const callback = self.loadCallback.bind(self);\n\t self.settings.load.call(self, value, callback);\n\t }\n\t /**\n\t * Invoked by the user-provided option provider\n\t *\n\t */\n\n\n\t loadCallback(options, optgroups) {\n\t const self = this;\n\t self.loading = Math.max(self.loading - 1, 0);\n\t self.lastQuery = null;\n\t self.clearActiveOption(); // when new results load, focus should be on first option\n\n\t self.setupOptions(options, optgroups);\n\t self.refreshOptions(self.isFocused && !self.isInputHidden);\n\n\t if (!self.loading) {\n\t removeClasses(self.wrapper, self.settings.loadingClass);\n\t }\n\n\t self.trigger('load', options, optgroups);\n\t }\n\n\t preload() {\n\t var classList = this.wrapper.classList;\n\t if (classList.contains('preloaded')) return;\n\t classList.add('preloaded');\n\t this.load('');\n\t }\n\t /**\n\t * Sets the input field of the control to the specified value.\n\t *\n\t */\n\n\n\t setTextboxValue(value = '') {\n\t var input = this.control_input;\n\t var changed = input.value !== value;\n\n\t if (changed) {\n\t input.value = value;\n\t triggerEvent(input, 'update');\n\t this.lastValue = value;\n\t }\n\t }\n\t /**\n\t * Returns the value of the control. If multiple items\n\t * can be selected (e.g. <select multiple>), this returns\n\t * an array. If only one item can be selected, this\n\t * returns a string.\n\t *\n\t */\n\n\n\t getValue() {\n\t if (this.is_select_tag && this.input.hasAttribute('multiple')) {\n\t return this.items;\n\t }\n\n\t return this.items.join(this.settings.delimiter);\n\t }\n\t /**\n\t * Resets the selected items to the given value.\n\t *\n\t */\n\n\n\t setValue(value, silent) {\n\t var events = silent ? [] : ['change'];\n\t debounce_events(this, events, () => {\n\t this.clear(silent);\n\t this.addItems(value, silent);\n\t });\n\t }\n\t /**\n\t * Resets the number of max items to the given value\n\t *\n\t */\n\n\n\t setMaxItems(value) {\n\t if (value === 0) value = null; //reset to unlimited items.\n\n\t this.settings.maxItems = value;\n\t this.refreshState();\n\t }\n\t /**\n\t * Sets the selected item.\n\t *\n\t */\n\n\n\t setActiveItem(item, e) {\n\t var self = this;\n\t var eventName;\n\t var i, begin, end, swap;\n\t var last;\n\t if (self.settings.mode === 'single') return; // clear the active selection\n\n\t if (!item) {\n\t self.clearActiveItems();\n\n\t if (self.isFocused) {\n\t self.showInput();\n\t }\n\n\t return;\n\t } // modify selection\n\n\n\t eventName = e && e.type.toLowerCase();\n\n\t if (eventName === 'click' && isKeyDown('shiftKey', e) && self.activeItems.length) {\n\t last = self.getLastActive();\n\t begin = Array.prototype.indexOf.call(self.control.children, last);\n\t end = Array.prototype.indexOf.call(self.control.children, item);\n\n\t if (begin > end) {\n\t swap = begin;\n\t begin = end;\n\t end = swap;\n\t }\n\n\t for (i = begin; i <= end; i++) {\n\t item = self.control.children[i];\n\n\t if (self.activeItems.indexOf(item) === -1) {\n\t self.setActiveItemClass(item);\n\t }\n\t }\n\n\t preventDefault(e);\n\t } else if (eventName === 'click' && isKeyDown(KEY_SHORTCUT, e) || eventName === 'keydown' && isKeyDown('shiftKey', e)) {\n\t if (item.classList.contains('active')) {\n\t self.removeActiveItem(item);\n\t } else {\n\t self.setActiveItemClass(item);\n\t }\n\t } else {\n\t self.clearActiveItems();\n\t self.setActiveItemClass(item);\n\t } // ensure control has focus\n\n\n\t self.hideInput();\n\n\t if (!self.isFocused) {\n\t self.focus();\n\t }\n\t }\n\t /**\n\t * Set the active and last-active classes\n\t *\n\t */\n\n\n\t setActiveItemClass(item) {\n\t const self = this;\n\t const last_active = self.control.querySelector('.last-active');\n\t if (last_active) removeClasses(last_active, 'last-active');\n\t addClasses(item, 'active last-active');\n\t self.trigger('item_select', item);\n\n\t if (self.activeItems.indexOf(item) == -1) {\n\t self.activeItems.push(item);\n\t }\n\t }\n\t /**\n\t * Remove active item\n\t *\n\t */\n\n\n\t removeActiveItem(item) {\n\t var idx = this.activeItems.indexOf(item);\n\t this.activeItems.splice(idx, 1);\n\t removeClasses(item, 'active');\n\t }\n\t /**\n\t * Clears all the active items\n\t *\n\t */\n\n\n\t clearActiveItems() {\n\t removeClasses(this.activeItems, 'active');\n\t this.activeItems = [];\n\t }\n\t /**\n\t * Sets the selected item in the dropdown menu\n\t * of available options.\n\t *\n\t */\n\n\n\t setActiveOption(option, scroll = true) {\n\t if (option === this.activeOption) {\n\t return;\n\t }\n\n\t this.clearActiveOption();\n\t if (!option) return;\n\t this.activeOption = option;\n\t setAttr(this.focus_node, {\n\t 'aria-activedescendant': option.getAttribute('id')\n\t });\n\t setAttr(option, {\n\t 'aria-selected': 'true'\n\t });\n\t addClasses(option, 'active');\n\t if (scroll) this.scrollToOption(option);\n\t }\n\t /**\n\t * Sets the dropdown_content scrollTop to display the option\n\t *\n\t */\n\n\n\t scrollToOption(option, behavior) {\n\t if (!option) return;\n\t const content = this.dropdown_content;\n\t const height_menu = content.clientHeight;\n\t const scrollTop = content.scrollTop || 0;\n\t const height_item = option.offsetHeight;\n\t const y = option.getBoundingClientRect().top - content.getBoundingClientRect().top + scrollTop;\n\n\t if (y + height_item > height_menu + scrollTop) {\n\t this.scroll(y - height_menu + height_item, behavior);\n\t } else if (y < scrollTop) {\n\t this.scroll(y, behavior);\n\t }\n\t }\n\t /**\n\t * Scroll the dropdown to the given position\n\t *\n\t */\n\n\n\t scroll(scrollTop, behavior) {\n\t const content = this.dropdown_content;\n\n\t if (behavior) {\n\t content.style.scrollBehavior = behavior;\n\t }\n\n\t content.scrollTop = scrollTop;\n\t content.style.scrollBehavior = '';\n\t }\n\t /**\n\t * Clears the active option\n\t *\n\t */\n\n\n\t clearActiveOption() {\n\t if (this.activeOption) {\n\t removeClasses(this.activeOption, 'active');\n\t setAttr(this.activeOption, {\n\t 'aria-selected': null\n\t });\n\t }\n\n\t this.activeOption = null;\n\t setAttr(this.focus_node, {\n\t 'aria-activedescendant': null\n\t });\n\t }\n\t /**\n\t * Selects all items (CTRL + A).\n\t */\n\n\n\t selectAll() {\n\t const self = this;\n\t if (self.settings.mode === 'single') return;\n\t const activeItems = self.controlChildren();\n\t if (!activeItems.length) return;\n\t self.hideInput();\n\t self.close();\n\t self.activeItems = activeItems;\n\t iterate$1(activeItems, item => {\n\t self.setActiveItemClass(item);\n\t });\n\t }\n\t /**\n\t * Determines if the control_input should be in a hidden or visible state\n\t *\n\t */\n\n\n\t inputState() {\n\t var self = this;\n\t if (!self.control.contains(self.control_input)) return;\n\t setAttr(self.control_input, {\n\t placeholder: self.settings.placeholder\n\t });\n\n\t if (self.activeItems.length > 0 || !self.isFocused && self.settings.hidePlaceholder && self.items.length > 0) {\n\t self.setTextboxValue();\n\t self.isInputHidden = true;\n\t } else {\n\t if (self.settings.hidePlaceholder && self.items.length > 0) {\n\t setAttr(self.control_input, {\n\t placeholder: ''\n\t });\n\t }\n\n\t self.isInputHidden = false;\n\t }\n\n\t self.wrapper.classList.toggle('input-hidden', self.isInputHidden);\n\t }\n\t /**\n\t * Hides the input element out of view, while\n\t * retaining its focus.\n\t * @deprecated 1.3\n\t */\n\n\n\t hideInput() {\n\t this.inputState();\n\t }\n\t /**\n\t * Restores input visibility.\n\t * @deprecated 1.3\n\t */\n\n\n\t showInput() {\n\t this.inputState();\n\t }\n\t /**\n\t * Get the input value\n\t */\n\n\n\t inputValue() {\n\t return this.control_input.value.trim();\n\t }\n\t /**\n\t * Gives the control focus.\n\t */\n\n\n\t focus() {\n\t var self = this;\n\t if (self.isDisabled) return;\n\t self.ignoreFocus = true;\n\n\t if (self.control_input.offsetWidth) {\n\t self.control_input.focus();\n\t } else {\n\t self.focus_node.focus();\n\t }\n\n\t setTimeout(() => {\n\t self.ignoreFocus = false;\n\t self.onFocus();\n\t }, 0);\n\t }\n\t /**\n\t * Forces the control out of focus.\n\t *\n\t */\n\n\n\t blur() {\n\t this.focus_node.blur();\n\t this.onBlur();\n\t }\n\t /**\n\t * Returns a function that scores an object\n\t * to show how good of a match it is to the\n\t * provided query.\n\t *\n\t * @return {function}\n\t */\n\n\n\t getScoreFunction(query) {\n\t return this.sifter.getScoreFunction(query, this.getSearchOptions());\n\t }\n\t /**\n\t * Returns search options for sifter (the system\n\t * for scoring and sorting results).\n\t *\n\t * @see https://github.com/orchidjs/sifter.js\n\t * @return {object}\n\t */\n\n\n\t getSearchOptions() {\n\t var settings = this.settings;\n\t var sort = settings.sortField;\n\n\t if (typeof settings.sortField === 'string') {\n\t sort = [{\n\t field: settings.sortField\n\t }];\n\t }\n\n\t return {\n\t fields: settings.searchField,\n\t conjunction: settings.searchConjunction,\n\t sort: sort,\n\t nesting: settings.nesting\n\t };\n\t }\n\t /**\n\t * Searches through available options and returns\n\t * a sorted array of matches.\n\t *\n\t */\n\n\n\t search(query) {\n\t var result, calculateScore;\n\t var self = this;\n\t var options = this.getSearchOptions(); // validate user-provided result scoring function\n\n\t if (self.settings.score) {\n\t calculateScore = self.settings.score.call(self, query);\n\n\t if (typeof calculateScore !== 'function') {\n\t throw new Error('Tom Select \"score\" setting must be a function that returns a function');\n\t }\n\t } // perform search\n\n\n\t if (query !== self.lastQuery) {\n\t self.lastQuery = query;\n\t result = self.sifter.search(query, Object.assign(options, {\n\t score: calculateScore\n\t }));\n\t self.currentResults = result;\n\t } else {\n\t result = Object.assign({}, self.currentResults);\n\t } // filter out selected items\n\n\n\t if (self.settings.hideSelected) {\n\t result.items = result.items.filter(item => {\n\t let hashed = hash_key(item.id);\n\t return !(hashed && self.items.indexOf(hashed) !== -1);\n\t });\n\t }\n\n\t return result;\n\t }\n\t /**\n\t * Refreshes the list of available options shown\n\t * in the autocomplete dropdown menu.\n\t *\n\t */\n\n\n\t refreshOptions(triggerDropdown = true) {\n\t var i, j, k, n, optgroup, optgroups, html, has_create_option, active_group;\n\t var create;\n\t const groups = {};\n\t const groups_order = [];\n\t var self = this;\n\t var query = self.inputValue();\n\t const same_query = query === self.lastQuery || query == '' && self.lastQuery == null;\n\t var results = self.search(query);\n\t var active_option = null;\n\t var show_dropdown = self.settings.shouldOpen || false;\n\t var dropdown_content = self.dropdown_content;\n\n\t if (same_query) {\n\t active_option = self.activeOption;\n\n\t if (active_option) {\n\t active_group = active_option.closest('[data-group]');\n\t }\n\t } // build markup\n\n\n\t n = results.items.length;\n\n\t if (typeof self.settings.maxOptions === 'number') {\n\t n = Math.min(n, self.settings.maxOptions);\n\t }\n\n\t if (n > 0) {\n\t show_dropdown = true;\n\t } // render and group available options individually\n\n\n\t for (i = 0; i < n; i++) {\n\t // get option dom element\n\t let item = results.items[i];\n\t if (!item) continue;\n\t let opt_value = item.id;\n\t let option = self.options[opt_value];\n\t if (option === undefined) continue;\n\t let opt_hash = get_hash(opt_value);\n\t let option_el = self.getOption(opt_hash, true); // toggle 'selected' class\n\n\t if (!self.settings.hideSelected) {\n\t option_el.classList.toggle('selected', self.items.includes(opt_hash));\n\t }\n\n\t optgroup = option[self.settings.optgroupField] || '';\n\t optgroups = Array.isArray(optgroup) ? optgroup : [optgroup];\n\n\t for (j = 0, k = optgroups && optgroups.length; j < k; j++) {\n\t optgroup = optgroups[j];\n\n\t if (!self.optgroups.hasOwnProperty(optgroup)) {\n\t optgroup = '';\n\t }\n\n\t let group_fragment = groups[optgroup];\n\n\t if (group_fragment === undefined) {\n\t group_fragment = document.createDocumentFragment();\n\t groups_order.push(optgroup);\n\t } // nodes can only have one parent, so if the option is in mutple groups, we need a clone\n\n\n\t if (j > 0) {\n\t option_el = option_el.cloneNode(true);\n\t setAttr(option_el, {\n\t id: option.$id + '-clone-' + j,\n\t 'aria-selected': null\n\t });\n\t option_el.classList.add('ts-cloned');\n\t removeClasses(option_el, 'active'); // make sure we keep the activeOption in the same group\n\n\t if (self.activeOption && self.activeOption.dataset.value == opt_value) {\n\t if (active_group && active_group.dataset.group === optgroup.toString()) {\n\t active_option = option_el;\n\t }\n\t }\n\t }\n\n\t group_fragment.appendChild(option_el);\n\t groups[optgroup] = group_fragment;\n\t }\n\t } // sort optgroups\n\n\n\t if (self.settings.lockOptgroupOrder) {\n\t groups_order.sort((a, b) => {\n\t const grp_a = self.optgroups[a];\n\t const grp_b = self.optgroups[b];\n\t const a_order = grp_a && grp_a.$order || 0;\n\t const b_order = grp_b && grp_b.$order || 0;\n\t return a_order - b_order;\n\t });\n\t } // render optgroup headers & join groups\n\n\n\t html = document.createDocumentFragment();\n\t iterate$1(groups_order, optgroup => {\n\t let group_fragment = groups[optgroup];\n\t if (!group_fragment || !group_fragment.children.length) return;\n\t let group_heading = self.optgroups[optgroup];\n\n\t if (group_heading !== undefined) {\n\t let group_options = document.createDocumentFragment();\n\t let header = self.render('optgroup_header', group_heading);\n\t append(group_options, header);\n\t append(group_options, group_fragment);\n\t let group_html = self.render('optgroup', {\n\t group: group_heading,\n\t options: group_options\n\t });\n\t append(html, group_html);\n\t } else {\n\t append(html, group_fragment);\n\t }\n\t });\n\t dropdown_content.innerHTML = '';\n\t append(dropdown_content, html); // highlight matching terms inline\n\n\t if (self.settings.highlight) {\n\t removeHighlight(dropdown_content);\n\n\t if (results.query.length && results.tokens.length) {\n\t iterate$1(results.tokens, tok => {\n\t highlight(dropdown_content, tok.regex);\n\t });\n\t }\n\t } // helper method for adding templates to dropdown\n\n\n\t var add_template = template => {\n\t let content = self.render(template, {\n\t input: query\n\t });\n\n\t if (content) {\n\t show_dropdown = true;\n\t dropdown_content.insertBefore(content, dropdown_content.firstChild);\n\t }\n\n\t return content;\n\t }; // add loading message\n\n\n\t if (self.loading) {\n\t add_template('loading'); // invalid query\n\t } else if (!self.settings.shouldLoad.call(self, query)) {\n\t add_template('not_loading'); // add no_results message\n\t } else if (results.items.length === 0) {\n\t add_template('no_results');\n\t } // add create option\n\n\n\t has_create_option = self.canCreate(query);\n\n\t if (has_create_option) {\n\t create = add_template('option_create');\n\t } // activate\n\n\n\t self.hasOptions = results.items.length > 0 || has_create_option;\n\n\t if (show_dropdown) {\n\t if (results.items.length > 0) {\n\t if (!active_option && self.settings.mode === 'single' && self.items[0] != undefined) {\n\t active_option = self.getOption(self.items[0]);\n\t }\n\n\t if (!dropdown_content.contains(active_option)) {\n\t let active_index = 0;\n\n\t if (create && !self.settings.addPrecedence) {\n\t active_index = 1;\n\t }\n\n\t active_option = self.selectable()[active_index];\n\t }\n\t } else if (create) {\n\t active_option = create;\n\t }\n\n\t if (triggerDropdown && !self.isOpen) {\n\t self.open();\n\t self.scrollToOption(active_option, 'auto');\n\t }\n\n\t self.setActiveOption(active_option);\n\t } else {\n\t self.clearActiveOption();\n\n\t if (triggerDropdown && self.isOpen) {\n\t self.close(false); // if create_option=null, we want the dropdown to close but not reset the textbox value\n\t }\n\t }\n\t }\n\t /**\n\t * Return list of selectable options\n\t *\n\t */\n\n\n\t selectable() {\n\t return this.dropdown_content.querySelectorAll('[data-selectable]');\n\t }\n\t /**\n\t * Adds an available option. If it already exists,\n\t * nothing will happen. Note: this does not refresh\n\t * the options list dropdown (use `refreshOptions`\n\t * for that).\n\t *\n\t * Usage:\n\t *\n\t * this.addOption(data)\n\t *\n\t */\n\n\n\t addOption(data, user_created = false) {\n\t const self = this; // @deprecated 1.7.7\n\t // use addOptions( array, user_created ) for adding multiple options\n\n\t if (Array.isArray(data)) {\n\t self.addOptions(data, user_created);\n\t return false;\n\t }\n\n\t const key = hash_key(data[self.settings.valueField]);\n\n\t if (key === null || self.options.hasOwnProperty(key)) {\n\t return false;\n\t }\n\n\t data.$order = data.$order || ++self.order;\n\t data.$id = self.inputId + '-opt-' + data.$order;\n\t self.options[key] = data;\n\t self.lastQuery = null;\n\n\t if (user_created) {\n\t self.userOptions[key] = user_created;\n\t self.trigger('option_add', key, data);\n\t }\n\n\t return key;\n\t }\n\t /**\n\t * Add multiple options\n\t *\n\t */\n\n\n\t addOptions(data, user_created = false) {\n\t iterate$1(data, dat => {\n\t this.addOption(dat, user_created);\n\t });\n\t }\n\t /**\n\t * @deprecated 1.7.7\n\t */\n\n\n\t registerOption(data) {\n\t return this.addOption(data);\n\t }\n\t /**\n\t * Registers an option group to the pool of option groups.\n\t *\n\t * @return {boolean|string}\n\t */\n\n\n\t registerOptionGroup(data) {\n\t var key = hash_key(data[this.settings.optgroupValueField]);\n\t if (key === null) return false;\n\t data.$order = data.$order || ++this.order;\n\t this.optgroups[key] = data;\n\t return key;\n\t }\n\t /**\n\t * Registers a new optgroup for options\n\t * to be bucketed into.\n\t *\n\t */\n\n\n\t addOptionGroup(id, data) {\n\t var hashed_id;\n\t data[this.settings.optgroupValueField] = id;\n\n\t if (hashed_id = this.registerOptionGroup(data)) {\n\t this.trigger('optgroup_add', hashed_id, data);\n\t }\n\t }\n\t /**\n\t * Removes an existing option group.\n\t *\n\t */\n\n\n\t removeOptionGroup(id) {\n\t if (this.optgroups.hasOwnProperty(id)) {\n\t delete this.optgroups[id];\n\t this.clearCache();\n\t this.trigger('optgroup_remove', id);\n\t }\n\t }\n\t /**\n\t * Clears all existing option groups.\n\t */\n\n\n\t clearOptionGroups() {\n\t this.optgroups = {};\n\t this.clearCache();\n\t this.trigger('optgroup_clear');\n\t }\n\t /**\n\t * Updates an option available for selection. If\n\t * it is visible in the selected items or options\n\t * dropdown, it will be re-rendered automatically.\n\t *\n\t */\n\n\n\t updateOption(value, data) {\n\t const self = this;\n\t var item_new;\n\t var index_item;\n\t const value_old = hash_key(value);\n\t const value_new = hash_key(data[self.settings.valueField]); // sanity checks\n\n\t if (value_old === null) return;\n\t const data_old = self.options[value_old];\n\t if (data_old == undefined) return;\n\t if (typeof value_new !== 'string') throw new Error('Value must be set in option data');\n\t const option = self.getOption(value_old);\n\t const item = self.getItem(value_old);\n\t data.$order = data.$order || data_old.$order;\n\t delete self.options[value_old]; // invalidate render cache\n\t // don't remove existing node yet, we'll remove it after replacing it\n\n\t self.uncacheValue(value_new);\n\t self.options[value_new] = data; // update the option if it's in the dropdown\n\n\t if (option) {\n\t if (self.dropdown_content.contains(option)) {\n\t const option_new = self._render('option', data);\n\n\t replaceNode(option, option_new);\n\n\t if (self.activeOption === option) {\n\t self.setActiveOption(option_new);\n\t }\n\t }\n\n\t option.remove();\n\t } // update the item if we have one\n\n\n\t if (item) {\n\t index_item = self.items.indexOf(value_old);\n\n\t if (index_item !== -1) {\n\t self.items.splice(index_item, 1, value_new);\n\t }\n\n\t item_new = self._render('item', data);\n\t if (item.classList.contains('active')) addClasses(item_new, 'active');\n\t replaceNode(item, item_new);\n\t } // invalidate last query because we might have updated the sortField\n\n\n\t self.lastQuery = null;\n\t }\n\t /**\n\t * Removes a single option.\n\t *\n\t */\n\n\n\t removeOption(value, silent) {\n\t const self = this;\n\t value = get_hash(value);\n\t self.uncacheValue(value);\n\t delete self.userOptions[value];\n\t delete self.options[value];\n\t self.lastQuery = null;\n\t self.trigger('option_remove', value);\n\t self.removeItem(value, silent);\n\t }\n\t /**\n\t * Clears all options.\n\t */\n\n\n\t clearOptions(filter) {\n\t const boundFilter = (filter || this.clearFilter).bind(this);\n\t this.loadedSearches = {};\n\t this.userOptions = {};\n\t this.clearCache();\n\t const selected = {};\n\t iterate$1(this.options, (option, key) => {\n\t if (boundFilter(option, key)) {\n\t selected[key] = option;\n\t }\n\t });\n\t this.options = this.sifter.items = selected;\n\t this.lastQuery = null;\n\t this.trigger('option_clear');\n\t }\n\t /**\n\t * Used by clearOptions() to decide whether or not an option should be removed\n\t * Return true to keep an option, false to remove\n\t *\n\t */\n\n\n\t clearFilter(option, value) {\n\t if (this.items.indexOf(value) >= 0) {\n\t return true;\n\t }\n\n\t return false;\n\t }\n\t /**\n\t * Returns the dom element of the option\n\t * matching the given value.\n\t *\n\t */\n\n\n\t getOption(value, create = false) {\n\t const hashed = hash_key(value);\n\t if (hashed === null) return null;\n\t const option = this.options[hashed];\n\n\t if (option != undefined) {\n\t if (option.$div) {\n\t return option.$div;\n\t }\n\n\t if (create) {\n\t return this._render('option', option);\n\t }\n\t }\n\n\t return null;\n\t }\n\t /**\n\t * Returns the dom element of the next or previous dom element of the same type\n\t * Note: adjacent options may not be adjacent DOM elements (optgroups)\n\t *\n\t */\n\n\n\t getAdjacent(option, direction, type = 'option') {\n\t var self = this,\n\t all;\n\n\t if (!option) {\n\t return null;\n\t }\n\n\t if (type == 'item') {\n\t all = self.controlChildren();\n\t } else {\n\t all = self.dropdown_content.querySelectorAll('[data-selectable]');\n\t }\n\n\t for (let i = 0; i < all.length; i++) {\n\t if (all[i] != option) {\n\t continue;\n\t }\n\n\t if (direction > 0) {\n\t return all[i + 1];\n\t }\n\n\t return all[i - 1];\n\t }\n\n\t return null;\n\t }\n\t /**\n\t * Returns the dom element of the item\n\t * matching the given value.\n\t *\n\t */\n\n\n\t getItem(item) {\n\t if (typeof item == 'object') {\n\t return item;\n\t }\n\n\t var value = hash_key(item);\n\t return value !== null ? this.control.querySelector(`[data-value=\"${addSlashes(value)}\"]`) : null;\n\t }\n\t /**\n\t * \"Selects\" multiple items at once. Adds them to the list\n\t * at the current caret position.\n\t *\n\t */\n\n\n\t addItems(values, silent) {\n\t var self = this;\n\t var items = Array.isArray(values) ? values : [values];\n\t items = items.filter(x => self.items.indexOf(x) === -1);\n\t const last_item = items[items.length - 1];\n\t items.forEach(item => {\n\t self.isPending = item !== last_item;\n\t self.addItem(item, silent);\n\t });\n\t }\n\t /**\n\t * \"Selects\" an item. Adds it to the list\n\t * at the current caret position.\n\t *\n\t */\n\n\n\t addItem(value, silent) {\n\t var events = silent ? [] : ['change', 'dropdown_close'];\n\t debounce_events(this, events, () => {\n\t var item, wasFull;\n\t const self = this;\n\t const inputMode = self.settings.mode;\n\t const hashed = hash_key(value);\n\n\t if (hashed && self.items.indexOf(hashed) !== -1) {\n\t if (inputMode === 'single') {\n\t self.close();\n\t }\n\n\t if (inputMode === 'single' || !self.settings.duplicates) {\n\t return;\n\t }\n\t }\n\n\t if (hashed === null || !self.options.hasOwnProperty(hashed)) return;\n\t if (inputMode === 'single') self.clear(silent);\n\t if (inputMode === 'multi' && self.isFull()) return;\n\t item = self._render('item', self.options[hashed]);\n\n\t if (self.control.contains(item)) {\n\t // duplicates\n\t item = item.cloneNode(true);\n\t }\n\n\t wasFull = self.isFull();\n\t self.items.splice(self.caretPos, 0, hashed);\n\t self.insertAtCaret(item);\n\n\t if (self.isSetup) {\n\t // update menu / remove the option (if this is not one item being added as part of series)\n\t if (!self.isPending && self.settings.hideSelected) {\n\t let option = self.getOption(hashed);\n\t let next = self.getAdjacent(option, 1);\n\n\t if (next) {\n\t self.setActiveOption(next);\n\t }\n\t } // refreshOptions after setActiveOption(),\n\t // otherwise setActiveOption() will be called by refreshOptions() with the wrong value\n\n\n\t if (!self.isPending && !self.settings.closeAfterSelect) {\n\t self.refreshOptions(self.isFocused && inputMode !== 'single');\n\t } // hide the menu if the maximum number of items have been selected or no options are left\n\n\n\t if (self.settings.closeAfterSelect != false && self.isFull()) {\n\t self.close();\n\t } else if (!self.isPending) {\n\t self.positionDropdown();\n\t }\n\n\t self.trigger('item_add', hashed, item);\n\n\t if (!self.isPending) {\n\t self.updateOriginalInput({\n\t silent: silent\n\t });\n\t }\n\t }\n\n\t if (!self.isPending || !wasFull && self.isFull()) {\n\t self.inputState();\n\t self.refreshState();\n\t }\n\t });\n\t }\n\t /**\n\t * Removes the selected item matching\n\t * the provided value.\n\t *\n\t */\n\n\n\t removeItem(item = null, silent) {\n\t const self = this;\n\t item = self.getItem(item);\n\t if (!item) return;\n\t var i, idx;\n\t const value = item.dataset.value;\n\t i = nodeIndex(item);\n\t item.remove();\n\n\t if (item.classList.contains('active')) {\n\t idx = self.activeItems.indexOf(item);\n\t self.activeItems.splice(idx, 1);\n\t removeClasses(item, 'active');\n\t }\n\n\t self.items.splice(i, 1);\n\t self.lastQuery = null;\n\n\t if (!self.settings.persist && self.userOptions.hasOwnProperty(value)) {\n\t self.removeOption(value, silent);\n\t }\n\n\t if (i < self.caretPos) {\n\t self.setCaret(self.caretPos - 1);\n\t }\n\n\t self.updateOriginalInput({\n\t silent: silent\n\t });\n\t self.refreshState();\n\t self.positionDropdown();\n\t self.trigger('item_remove', value, item);\n\t }\n\t /**\n\t * Invokes the `create` method provided in the\n\t * TomSelect options that should provide the data\n\t * for the new item, given the user input.\n\t *\n\t * Once this completes, it will be added\n\t * to the item list.\n\t *\n\t */\n\n\n\t createItem(input = null, callback = () => {}) {\n\t // triggerDropdown parameter @deprecated 2.1.1\n\t if (arguments.length === 3) {\n\t callback = arguments[2];\n\t }\n\n\t if (typeof callback != 'function') {\n\t callback = () => {};\n\t }\n\n\t var self = this;\n\t var caret = self.caretPos;\n\t var output;\n\t input = input || self.inputValue();\n\n\t if (!self.canCreate(input)) {\n\t callback();\n\t return false;\n\t }\n\n\t self.lock();\n\t var created = false;\n\n\t var create = data => {\n\t self.unlock();\n\t if (!data || typeof data !== 'object') return callback();\n\t var value = hash_key(data[self.settings.valueField]);\n\n\t if (typeof value !== 'string') {\n\t return callback();\n\t }\n\n\t self.setTextboxValue();\n\t self.addOption(data, true);\n\t self.setCaret(caret);\n\t self.addItem(value);\n\t callback(data);\n\t created = true;\n\t };\n\n\t if (typeof self.settings.create === 'function') {\n\t output = self.settings.create.call(this, input, create);\n\t } else {\n\t output = {\n\t [self.settings.labelField]: input,\n\t [self.settings.valueField]: input\n\t };\n\t }\n\n\t if (!created) {\n\t create(output);\n\t }\n\n\t return true;\n\t }\n\t /**\n\t * Re-renders the selected item lists.\n\t */\n\n\n\t refreshItems() {\n\t var self = this;\n\t self.lastQuery = null;\n\n\t if (self.isSetup) {\n\t self.addItems(self.items);\n\t }\n\n\t self.updateOriginalInput();\n\t self.refreshState();\n\t }\n\t /**\n\t * Updates all state-dependent attributes\n\t * and CSS classes.\n\t */\n\n\n\t refreshState() {\n\t const self = this;\n\t self.refreshValidityState();\n\t const isFull = self.isFull();\n\t const isLocked = self.isLocked;\n\t self.wrapper.classList.toggle('rtl', self.rtl);\n\t const wrap_classList = self.wrapper.classList;\n\t wrap_classList.toggle('focus', self.isFocused);\n\t wrap_classList.toggle('disabled', self.isDisabled);\n\t wrap_classList.toggle('required', self.isRequired);\n\t wrap_classList.toggle('invalid', !self.isValid);\n\t wrap_classList.toggle('locked', isLocked);\n\t wrap_classList.toggle('full', isFull);\n\t wrap_classList.toggle('input-active', self.isFocused && !self.isInputHidden);\n\t wrap_classList.toggle('dropdown-active', self.isOpen);\n\t wrap_classList.toggle('has-options', isEmptyObject(self.options));\n\t wrap_classList.toggle('has-items', self.items.length > 0);\n\t }\n\t /**\n\t * Update the `required` attribute of both input and control input.\n\t *\n\t * The `required` property needs to be activated on the control input\n\t * for the error to be displayed at the right place. `required` also\n\t * needs to be temporarily deactivated on the input since the input is\n\t * hidden and can't show errors.\n\t */\n\n\n\t refreshValidityState() {\n\t var self = this;\n\n\t if (!self.input.validity) {\n\t return;\n\t }\n\n\t self.isValid = self.input.validity.valid;\n\t self.isInvalid = !self.isValid;\n\t }\n\t /**\n\t * Determines whether or not more items can be added\n\t * to the control without exceeding the user-defined maximum.\n\t *\n\t * @returns {boolean}\n\t */\n\n\n\t isFull() {\n\t return this.settings.maxItems !== null && this.items.length >= this.settings.maxItems;\n\t }\n\t /**\n\t * Refreshes the original <select> or <input>\n\t * element to reflect the current state.\n\t *\n\t */\n\n\n\t updateOriginalInput(opts = {}) {\n\t const self = this;\n\t var option, label;\n\t const empty_option = self.input.querySelector('option[value=\"\"]');\n\n\t if (self.is_select_tag) {\n\t const selected = [];\n\t const has_selected = self.input.querySelectorAll('option:checked').length;\n\n\t function AddSelected(option_el, value, label) {\n\t if (!option_el) {\n\t option_el = getDom('<option value=\"' + escape_html(value) + '\">' + escape_html(label) + '</option>');\n\t } // don't move empty option from top of list\n\t // fixes bug in firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1725293\n\n\n\t if (option_el != empty_option) {\n\t self.input.append(option_el);\n\t }\n\n\t selected.push(option_el); // marking empty option as selected can break validation\n\t // fixes https://github.com/orchidjs/tom-select/issues/303\n\n\t if (option_el != empty_option || has_selected > 0) {\n\t option_el.selected = true;\n\t }\n\n\t return option_el;\n\t } // unselect all selected options\n\n\n\t self.input.querySelectorAll('option:checked').forEach(option_el => {\n\t option_el.selected = false;\n\t }); // nothing selected?\n\n\t if (self.items.length == 0 && self.settings.mode == 'single') {\n\t AddSelected(empty_option, \"\", \"\"); // order selected <option> tags for values in self.items\n\t } else {\n\t self.items.forEach(value => {\n\t option = self.options[value];\n\t label = option[self.settings.labelField] || '';\n\n\t if (selected.includes(option.$option)) {\n\t const reuse_opt = self.input.querySelector(`option[value=\"${addSlashes(value)}\"]:not(:checked)`);\n\t AddSelected(reuse_opt, value, label);\n\t } else {\n\t option.$option = AddSelected(option.$option, value, label);\n\t }\n\t });\n\t }\n\t } else {\n\t self.input.value = self.getValue();\n\t }\n\n\t if (self.isSetup) {\n\t if (!opts.silent) {\n\t self.trigger('change', self.getValue());\n\t }\n\t }\n\t }\n\t /**\n\t * Shows the autocomplete dropdown containing\n\t * the available options.\n\t */\n\n\n\t open() {\n\t var self = this;\n\t if (self.isLocked || self.isOpen || self.settings.mode === 'multi' && self.isFull()) return;\n\t self.isOpen = true;\n\t setAttr(self.focus_node, {\n\t 'aria-expanded': 'true'\n\t });\n\t self.refreshState();\n\t applyCSS(self.dropdown, {\n\t visibility: 'hidden',\n\t display: 'block'\n\t });\n\t self.positionDropdown();\n\t applyCSS(self.dropdown, {\n\t visibility: 'visible',\n\t display: 'block'\n\t });\n\t self.focus();\n\t self.trigger('dropdown_open', self.dropdown);\n\t }\n\t /**\n\t * Closes the autocomplete dropdown menu.\n\t */\n\n\n\t close(setTextboxValue = true) {\n\t var self = this;\n\t var trigger = self.isOpen;\n\n\t if (setTextboxValue) {\n\t // before blur() to prevent form onchange event\n\t self.setTextboxValue();\n\n\t if (self.settings.mode === 'single' && self.items.length) {\n\t self.hideInput();\n\t }\n\t }\n\n\t self.isOpen = false;\n\t setAttr(self.focus_node, {\n\t 'aria-expanded': 'false'\n\t });\n\t applyCSS(self.dropdown, {\n\t display: 'none'\n\t });\n\n\t if (self.settings.hideSelected) {\n\t self.clearActiveOption();\n\t }\n\n\t self.refreshState();\n\t if (trigger) self.trigger('dropdown_close', self.dropdown);\n\t }\n\t /**\n\t * Calculates and applies the appropriate\n\t * position of the dropdown if dropdownParent = 'body'.\n\t * Otherwise, position is determined by css\n\t */\n\n\n\t positionDropdown() {\n\t if (this.settings.dropdownParent !== 'body') {\n\t return;\n\t }\n\n\t var context = this.control;\n\t var rect = context.getBoundingClientRect();\n\t var top = context.offsetHeight + rect.top + window.scrollY;\n\t var left = rect.left + window.scrollX;\n\t applyCSS(this.dropdown, {\n\t width: rect.width + 'px',\n\t top: top + 'px',\n\t left: left + 'px'\n\t });\n\t }\n\t /**\n\t * Resets / clears all selected items\n\t * from the control.\n\t *\n\t */\n\n\n\t clear(silent) {\n\t var self = this;\n\t if (!self.items.length) return;\n\t var items = self.controlChildren();\n\t iterate$1(items, item => {\n\t self.removeItem(item, true);\n\t });\n\t self.showInput();\n\t if (!silent) self.updateOriginalInput();\n\t self.trigger('clear');\n\t }\n\t /**\n\t * A helper method for inserting an element\n\t * at the current caret position.\n\t *\n\t */\n\n\n\t insertAtCaret(el) {\n\t const self = this;\n\t const caret = self.caretPos;\n\t const target = self.control;\n\t target.insertBefore(el, target.children[caret] || null);\n\t self.setCaret(caret + 1);\n\t }\n\t /**\n\t * Removes the current selected item(s).\n\t *\n\t */\n\n\n\t deleteSelection(e) {\n\t var direction, selection, caret, tail;\n\t var self = this;\n\t direction = e && e.keyCode === KEY_BACKSPACE ? -1 : 1;\n\t selection = getSelection(self.control_input); // determine items that will be removed\n\n\t const rm_items = [];\n\n\t if (self.activeItems.length) {\n\t tail = getTail(self.activeItems, direction);\n\t caret = nodeIndex(tail);\n\n\t if (direction > 0) {\n\t caret++;\n\t }\n\n\t iterate$1(self.activeItems, item => rm_items.push(item));\n\t } else if ((self.isFocused || self.settings.mode === 'single') && self.items.length) {\n\t const items = self.controlChildren();\n\t let rm_item;\n\n\t if (direction < 0 && selection.start === 0 && selection.length === 0) {\n\t rm_item = items[self.caretPos - 1];\n\t } else if (direction > 0 && selection.start === self.inputValue().length) {\n\t rm_item = items[self.caretPos];\n\t }\n\n\t if (rm_item !== undefined) {\n\t rm_items.push(rm_item);\n\t }\n\t }\n\n\t if (!self.shouldDelete(rm_items, e)) {\n\t return false;\n\t }\n\n\t preventDefault(e, true); // perform removal\n\n\t if (typeof caret !== 'undefined') {\n\t self.setCaret(caret);\n\t }\n\n\t while (rm_items.length) {\n\t self.removeItem(rm_items.pop());\n\t }\n\n\t self.showInput();\n\t self.positionDropdown();\n\t self.refreshOptions(false);\n\t return true;\n\t }\n\t /**\n\t * Return true if the items should be deleted\n\t */\n\n\n\t shouldDelete(items, evt) {\n\t const values = items.map(item => item.dataset.value); // allow the callback to abort\n\n\t if (!values.length || typeof this.settings.onDelete === 'function' && this.settings.onDelete(values, evt) === false) {\n\t return false;\n\t }\n\n\t return true;\n\t }\n\t /**\n\t * Selects the previous / next item (depending on the `direction` argument).\n\t *\n\t * > 0 - right\n\t * < 0 - left\n\t *\n\t */\n\n\n\t advanceSelection(direction, e) {\n\t var last_active,\n\t adjacent,\n\t self = this;\n\t if (self.rtl) direction *= -1;\n\t if (self.inputValue().length) return; // add or remove to active items\n\n\t if (isKeyDown(KEY_SHORTCUT, e) || isKeyDown('shiftKey', e)) {\n\t last_active = self.getLastActive(direction);\n\n\t if (last_active) {\n\t if (!last_active.classList.contains('active')) {\n\t adjacent = last_active;\n\t } else {\n\t adjacent = self.getAdjacent(last_active, direction, 'item');\n\t } // if no active item, get items adjacent to the control input\n\n\t } else if (direction > 0) {\n\t adjacent = self.control_input.nextElementSibling;\n\t } else {\n\t adjacent = self.control_input.previousElementSibling;\n\t }\n\n\t if (adjacent) {\n\t if (adjacent.classList.contains('active')) {\n\t self.removeActiveItem(last_active);\n\t }\n\n\t self.setActiveItemClass(adjacent); // mark as last_active !! after removeActiveItem() on last_active\n\t } // move caret to the left or right\n\n\t } else {\n\t self.moveCaret(direction);\n\t }\n\t }\n\n\t moveCaret(direction) {}\n\t /**\n\t * Get the last active item\n\t *\n\t */\n\n\n\t getLastActive(direction) {\n\t let last_active = this.control.querySelector('.last-active');\n\n\t if (last_active) {\n\t return last_active;\n\t }\n\n\t var result = this.control.querySelectorAll('.active');\n\n\t if (result) {\n\t return getTail(result, direction);\n\t }\n\t }\n\t /**\n\t * Moves the caret to the specified index.\n\t *\n\t * The input must be moved by leaving it in place and moving the\n\t * siblings, due to the fact that focus cannot be restored once lost\n\t * on mobile webkit devices\n\t *\n\t */\n\n\n\t setCaret(new_pos) {\n\t this.caretPos = this.items.length;\n\t }\n\t /**\n\t * Return list of item dom elements\n\t *\n\t */\n\n\n\t controlChildren() {\n\t return Array.from(this.control.querySelectorAll('[data-ts-item]'));\n\t }\n\t /**\n\t * Disables user input on the control. Used while\n\t * items are being asynchronously created.\n\t */\n\n\n\t lock() {\n\t this.isLocked = true;\n\t this.refreshState();\n\t }\n\t /**\n\t * Re-enables user input on the control.\n\t */\n\n\n\t unlock() {\n\t this.isLocked = false;\n\t this.refreshState();\n\t }\n\t /**\n\t * Disables user input on the control completely.\n\t * While disabled, it cannot receive focus.\n\t */\n\n\n\t disable() {\n\t var self = this;\n\t self.input.disabled = true;\n\t self.control_input.disabled = true;\n\t self.focus_node.tabIndex = -1;\n\t self.isDisabled = true;\n\t this.close();\n\t self.lock();\n\t }\n\t /**\n\t * Enables the control so that it can respond\n\t * to focus and user input.\n\t */\n\n\n\t enable() {\n\t var self = this;\n\t self.input.disabled = false;\n\t self.control_input.disabled = false;\n\t self.focus_node.tabIndex = self.tabIndex;\n\t self.isDisabled = false;\n\t self.unlock();\n\t }\n\t /**\n\t * Completely destroys the control and\n\t * unbinds all event listeners so that it can\n\t * be garbage collected.\n\t */\n\n\n\t destroy() {\n\t var self = this;\n\t var revertSettings = self.revertSettings;\n\t self.trigger('destroy');\n\t self.off();\n\t self.wrapper.remove();\n\t self.dropdown.remove();\n\t self.input.innerHTML = revertSettings.innerHTML;\n\t self.input.tabIndex = revertSettings.tabIndex;\n\t removeClasses(self.input, 'tomselected', 'ts-hidden-accessible');\n\n\t self._destroy();\n\n\t delete self.input.tomselect;\n\t }\n\t /**\n\t * A helper method for rendering \"item\" and\n\t * \"option\" templates, given the data.\n\t *\n\t */\n\n\n\t render(templateName, data) {\n\t var id, html;\n\t const self = this;\n\n\t if (typeof this.settings.render[templateName] !== 'function') {\n\t return null;\n\t } // render markup\n\n\n\t html = self.settings.render[templateName].call(this, data, escape_html);\n\n\t if (!html) {\n\t return null;\n\t }\n\n\t html = getDom(html); // add mandatory attributes\n\n\t if (templateName === 'option' || templateName === 'option_create') {\n\t if (data[self.settings.disabledField]) {\n\t setAttr(html, {\n\t 'aria-disabled': 'true'\n\t });\n\t } else {\n\t setAttr(html, {\n\t 'data-selectable': ''\n\t });\n\t }\n\t } else if (templateName === 'optgroup') {\n\t id = data.group[self.settings.optgroupValueField];\n\t setAttr(html, {\n\t 'data-group': id\n\t });\n\n\t if (data.group[self.settings.disabledField]) {\n\t setAttr(html, {\n\t 'data-disabled': ''\n\t });\n\t }\n\t }\n\n\t if (templateName === 'option' || templateName === 'item') {\n\t const value = get_hash(data[self.settings.valueField]);\n\t setAttr(html, {\n\t 'data-value': value\n\t }); // make sure we have some classes if a template is overwritten\n\n\t if (templateName === 'item') {\n\t addClasses(html, self.settings.itemClass);\n\t setAttr(html, {\n\t 'data-ts-item': ''\n\t });\n\t } else {\n\t addClasses(html, self.settings.optionClass);\n\t setAttr(html, {\n\t role: 'option',\n\t id: data.$id\n\t }); // update cache\n\n\t data.$div = html;\n\t self.options[value] = data;\n\t }\n\t }\n\n\t return html;\n\t }\n\t /**\n\t * Type guarded rendering\n\t *\n\t */\n\n\n\t _render(templateName, data) {\n\t const html = this.render(templateName, data);\n\n\t if (html == null) {\n\t throw 'HTMLElement expected';\n\t }\n\n\t return html;\n\t }\n\t /**\n\t * Clears the render cache for a template. If\n\t * no template is given, clears all render\n\t * caches.\n\t *\n\t */\n\n\n\t clearCache() {\n\t iterate$1(this.options, option => {\n\t if (option.$div) {\n\t option.$div.remove();\n\t delete option.$div;\n\t }\n\t });\n\t }\n\t /**\n\t * Removes a value from item and option caches\n\t *\n\t */\n\n\n\t uncacheValue(value) {\n\t const option_el = this.getOption(value);\n\t if (option_el) option_el.remove();\n\t }\n\t /**\n\t * Determines whether or not to display the\n\t * create item prompt, given a user input.\n\t *\n\t */\n\n\n\t canCreate(input) {\n\t return this.settings.create && input.length > 0 && this.settings.createFilter.call(this, input);\n\t }\n\t /**\n\t * Wraps this.`method` so that `new_fn` can be invoked 'before', 'after', or 'instead' of the original method\n\t *\n\t * this.hook('instead','onKeyDown',function( arg1, arg2 ...){\n\t *\n\t * });\n\t */\n\n\n\t hook(when, method, new_fn) {\n\t var self = this;\n\t var orig_method = self[method];\n\n\t self[method] = function () {\n\t var result, result_new;\n\n\t if (when === 'after') {\n\t result = orig_method.apply(self, arguments);\n\t }\n\n\t result_new = new_fn.apply(self, arguments);\n\n\t if (when === 'instead') {\n\t return result_new;\n\t }\n\n\t if (when === 'before') {\n\t result = orig_method.apply(self, arguments);\n\t }\n\n\t return result;\n\t };\n\t }\n\n\t}\n\n\t/**\n\t * Plugin: \"change_listener\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction change_listener () {\n\t addEvent(this.input, 'change', () => {\n\t this.sync();\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"restore_on_backspace\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction checkbox_options () {\n\t var self = this;\n\t var orig_onOptionSelect = self.onOptionSelect;\n\t self.settings.hideSelected = false; // update the checkbox for an option\n\n\t var UpdateCheckbox = function UpdateCheckbox(option) {\n\t setTimeout(() => {\n\t var checkbox = option.querySelector('input');\n\n\t if (checkbox instanceof HTMLInputElement) {\n\t if (option.classList.contains('selected')) {\n\t checkbox.checked = true;\n\t } else {\n\t checkbox.checked = false;\n\t }\n\t }\n\t }, 1);\n\t }; // add checkbox to option template\n\n\n\t self.hook('after', 'setupTemplates', () => {\n\t var orig_render_option = self.settings.render.option;\n\n\t self.settings.render.option = (data, escape_html) => {\n\t var rendered = getDom(orig_render_option.call(self, data, escape_html));\n\t var checkbox = document.createElement('input');\n\t checkbox.addEventListener('click', function (evt) {\n\t preventDefault(evt);\n\t });\n\t checkbox.type = 'checkbox';\n\t const hashed = hash_key(data[self.settings.valueField]);\n\n\t if (hashed && self.items.indexOf(hashed) > -1) {\n\t checkbox.checked = true;\n\t }\n\n\t rendered.prepend(checkbox);\n\t return rendered;\n\t };\n\t }); // uncheck when item removed\n\n\t self.on('item_remove', value => {\n\t var option = self.getOption(value);\n\n\t if (option) {\n\t // if dropdown hasn't been opened yet, the option won't exist\n\t option.classList.remove('selected'); // selected class won't be removed yet\n\n\t UpdateCheckbox(option);\n\t }\n\t }); // check when item added\n\n\t self.on('item_add', value => {\n\t var option = self.getOption(value);\n\n\t if (option) {\n\t // if dropdown hasn't been opened yet, the option won't exist\n\t UpdateCheckbox(option);\n\t }\n\t }); // remove items when selected option is clicked\n\n\t self.hook('instead', 'onOptionSelect', (evt, option) => {\n\t if (option.classList.contains('selected')) {\n\t option.classList.remove('selected');\n\t self.removeItem(option.dataset.value);\n\t self.refreshOptions();\n\t preventDefault(evt, true);\n\t return;\n\t }\n\n\t orig_onOptionSelect.call(self, evt, option);\n\t UpdateCheckbox(option);\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"dropdown_header\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction clear_button (userOptions) {\n\t const self = this;\n\t const options = Object.assign({\n\t className: 'clear-button',\n\t title: 'Clear All',\n\t html: data => {\n\t return `<div class=\"${data.className}\" title=\"${data.title}\">⨯</div>`;\n\t }\n\t }, userOptions);\n\t self.on('initialize', () => {\n\t var button = getDom(options.html(options));\n\t button.addEventListener('click', evt => {\n\t if (self.isDisabled) {\n\t return;\n\t }\n\n\t self.clear();\n\n\t if (self.settings.mode === 'single' && self.settings.allowEmptyOption) {\n\t self.addItem('');\n\t }\n\n\t evt.preventDefault();\n\t evt.stopPropagation();\n\t });\n\t self.control.appendChild(button);\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"drag_drop\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction drag_drop () {\n\t var self = this;\n\t if (!$.fn.sortable) throw new Error('The \"drag_drop\" plugin requires jQuery UI \"sortable\".');\n\t if (self.settings.mode !== 'multi') return;\n\t var orig_lock = self.lock;\n\t var orig_unlock = self.unlock;\n\t self.hook('instead', 'lock', () => {\n\t var sortable = $(self.control).data('sortable');\n\t if (sortable) sortable.disable();\n\t return orig_lock.call(self);\n\t });\n\t self.hook('instead', 'unlock', () => {\n\t var sortable = $(self.control).data('sortable');\n\t if (sortable) sortable.enable();\n\t return orig_unlock.call(self);\n\t });\n\t self.on('initialize', () => {\n\t var $control = $(self.control).sortable({\n\t items: '[data-value]',\n\t forcePlaceholderSize: true,\n\t disabled: self.isLocked,\n\t start: (e, ui) => {\n\t ui.placeholder.css('width', ui.helper.css('width'));\n\t $control.css({\n\t overflow: 'visible'\n\t });\n\t },\n\t stop: () => {\n\t $control.css({\n\t overflow: 'hidden'\n\t });\n\t var values = [];\n\t $control.children('[data-value]').each(function () {\n\t if (this.dataset.value) values.push(this.dataset.value);\n\t });\n\t self.setValue(values);\n\t }\n\t });\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"dropdown_header\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction dropdown_header (userOptions) {\n\t const self = this;\n\t const options = Object.assign({\n\t title: 'Untitled',\n\t headerClass: 'dropdown-header',\n\t titleRowClass: 'dropdown-header-title',\n\t labelClass: 'dropdown-header-label',\n\t closeClass: 'dropdown-header-close',\n\t html: data => {\n\t return '<div class=\"' + data.headerClass + '\">' + '<div class=\"' + data.titleRowClass + '\">' + '<span class=\"' + data.labelClass + '\">' + data.title + '</span>' + '<a class=\"' + data.closeClass + '\">×</a>' + '</div>' + '</div>';\n\t }\n\t }, userOptions);\n\t self.on('initialize', () => {\n\t var header = getDom(options.html(options));\n\t var close_link = header.querySelector('.' + options.closeClass);\n\n\t if (close_link) {\n\t close_link.addEventListener('click', evt => {\n\t preventDefault(evt, true);\n\t self.close();\n\t });\n\t }\n\n\t self.dropdown.insertBefore(header, self.dropdown.firstChild);\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"dropdown_input\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction caret_position () {\n\t var self = this;\n\t /**\n\t * Moves the caret to the specified index.\n\t *\n\t * The input must be moved by leaving it in place and moving the\n\t * siblings, due to the fact that focus cannot be restored once lost\n\t * on mobile webkit devices\n\t *\n\t */\n\n\t self.hook('instead', 'setCaret', new_pos => {\n\t if (self.settings.mode === 'single' || !self.control.contains(self.control_input)) {\n\t new_pos = self.items.length;\n\t } else {\n\t new_pos = Math.max(0, Math.min(self.items.length, new_pos));\n\n\t if (new_pos != self.caretPos && !self.isPending) {\n\t self.controlChildren().forEach((child, j) => {\n\t if (j < new_pos) {\n\t self.control_input.insertAdjacentElement('beforebegin', child);\n\t } else {\n\t self.control.appendChild(child);\n\t }\n\t });\n\t }\n\t }\n\n\t self.caretPos = new_pos;\n\t });\n\t self.hook('instead', 'moveCaret', direction => {\n\t if (!self.isFocused) return; // move caret before or after selected items\n\n\t const last_active = self.getLastActive(direction);\n\n\t if (last_active) {\n\t const idx = nodeIndex(last_active);\n\t self.setCaret(direction > 0 ? idx + 1 : idx);\n\t self.setActiveItem();\n\t removeClasses(last_active, 'last-active'); // move caret left or right of current position\n\t } else {\n\t self.setCaret(self.caretPos + direction);\n\t }\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"dropdown_input\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction dropdown_input () {\n\t const self = this;\n\t self.settings.shouldOpen = true; // make sure the input is shown even if there are no options to display in the dropdown\n\n\t self.hook('before', 'setup', () => {\n\t self.focus_node = self.control;\n\t addClasses(self.control_input, 'dropdown-input');\n\t const div = getDom('<div class=\"dropdown-input-wrap\">');\n\t div.append(self.control_input);\n\t self.dropdown.insertBefore(div, self.dropdown.firstChild); // set a placeholder in the select control\n\n\t const placeholder = getDom('<input class=\"items-placeholder\" tabindex=\"-1\" />');\n\t placeholder.placeholder = self.settings.placeholder || '';\n\t self.control.append(placeholder);\n\t });\n\t self.on('initialize', () => {\n\t // set tabIndex on control to -1, otherwise [shift+tab] will put focus right back on control_input\n\t self.control_input.addEventListener('keydown', evt => {\n\t //addEvent(self.control_input,'keydown' as const,(evt:KeyboardEvent) =>{\n\t switch (evt.keyCode) {\n\t case KEY_ESC:\n\t if (self.isOpen) {\n\t preventDefault(evt, true);\n\t self.close();\n\t }\n\n\t self.clearActiveItems();\n\t return;\n\n\t case KEY_TAB:\n\t self.focus_node.tabIndex = -1;\n\t break;\n\t }\n\n\t return self.onKeyDown.call(self, evt);\n\t });\n\t self.on('blur', () => {\n\t self.focus_node.tabIndex = self.isDisabled ? -1 : self.tabIndex;\n\t }); // give the control_input focus when the dropdown is open\n\n\t self.on('dropdown_open', () => {\n\t self.control_input.focus();\n\t }); // prevent onBlur from closing when focus is on the control_input\n\n\t const orig_onBlur = self.onBlur;\n\t self.hook('instead', 'onBlur', evt => {\n\t if (evt && evt.relatedTarget == self.control_input) return;\n\t return orig_onBlur.call(self);\n\t });\n\t addEvent(self.control_input, 'blur', () => self.onBlur()); // return focus to control to allow further keyboard input\n\n\t self.hook('before', 'close', () => {\n\t if (!self.isOpen) return;\n\t self.focus_node.focus({\n\t preventScroll: true\n\t });\n\t });\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"input_autogrow\" (Tom Select)\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction input_autogrow () {\n\t var self = this;\n\t self.on('initialize', () => {\n\t var test_input = document.createElement('span');\n\t var control = self.control_input;\n\t test_input.style.cssText = 'position:absolute; top:-99999px; left:-99999px; width:auto; padding:0; white-space:pre; ';\n\t self.wrapper.appendChild(test_input);\n\t var transfer_styles = ['letterSpacing', 'fontSize', 'fontFamily', 'fontWeight', 'textTransform'];\n\n\t for (const style_name of transfer_styles) {\n\t // @ts-ignore TS7015 https://stackoverflow.com/a/50506154/697576\n\t test_input.style[style_name] = control.style[style_name];\n\t }\n\t /**\n\t * Set the control width\n\t *\n\t */\n\n\n\t var resize = () => {\n\t test_input.textContent = control.value;\n\t control.style.width = test_input.clientWidth + 'px';\n\t };\n\n\t resize();\n\t self.on('update item_add item_remove', resize);\n\t addEvent(control, 'input', resize);\n\t addEvent(control, 'keyup', resize);\n\t addEvent(control, 'blur', resize);\n\t addEvent(control, 'update', resize);\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"input_autogrow\" (Tom Select)\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction no_backspace_delete () {\n\t var self = this;\n\t var orig_deleteSelection = self.deleteSelection;\n\t this.hook('instead', 'deleteSelection', evt => {\n\t if (self.activeItems.length) {\n\t return orig_deleteSelection.call(self, evt);\n\t }\n\n\t return false;\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"no_active_items\" (Tom Select)\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction no_active_items () {\n\t this.hook('instead', 'setActiveItem', () => {});\n\t this.hook('instead', 'selectAll', () => {});\n\t}\n\n\t/**\n\t * Plugin: \"optgroup_columns\" (Tom Select.js)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction optgroup_columns () {\n\t var self = this;\n\t var orig_keydown = self.onKeyDown;\n\t self.hook('instead', 'onKeyDown', evt => {\n\t var index, option, options, optgroup;\n\n\t if (!self.isOpen || !(evt.keyCode === KEY_LEFT || evt.keyCode === KEY_RIGHT)) {\n\t return orig_keydown.call(self, evt);\n\t }\n\n\t self.ignoreHover = true;\n\t optgroup = parentMatch(self.activeOption, '[data-group]');\n\t index = nodeIndex(self.activeOption, '[data-selectable]');\n\n\t if (!optgroup) {\n\t return;\n\t }\n\n\t if (evt.keyCode === KEY_LEFT) {\n\t optgroup = optgroup.previousSibling;\n\t } else {\n\t optgroup = optgroup.nextSibling;\n\t }\n\n\t if (!optgroup) {\n\t return;\n\t }\n\n\t options = optgroup.querySelectorAll('[data-selectable]');\n\t option = options[Math.min(options.length - 1, index)];\n\n\t if (option) {\n\t self.setActiveOption(option);\n\t }\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"remove_button\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction remove_button (userOptions) {\n\t const options = Object.assign({\n\t label: '×',\n\t title: 'Remove',\n\t className: 'remove',\n\t append: true\n\t }, userOptions); //options.className = 'remove-single';\n\n\t var self = this; // override the render method to add remove button to each item\n\n\t if (!options.append) {\n\t return;\n\t }\n\n\t var html = '<a href=\"javascript:void(0)\" class=\"' + options.className + '\" tabindex=\"-1\" title=\"' + escape_html(options.title) + '\">' + options.label + '</a>';\n\t self.hook('after', 'setupTemplates', () => {\n\t var orig_render_item = self.settings.render.item;\n\n\t self.settings.render.item = (data, escape) => {\n\t var item = getDom(orig_render_item.call(self, data, escape));\n\t var close_button = getDom(html);\n\t item.appendChild(close_button);\n\t addEvent(close_button, 'mousedown', evt => {\n\t preventDefault(evt, true);\n\t });\n\t addEvent(close_button, 'click', evt => {\n\t // propagating will trigger the dropdown to show for single mode\n\t preventDefault(evt, true);\n\t if (self.isLocked) return;\n\t if (!self.shouldDelete([item], evt)) return;\n\t self.removeItem(item);\n\t self.refreshOptions(false);\n\t self.inputState();\n\t });\n\t return item;\n\t };\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"restore_on_backspace\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction restore_on_backspace (userOptions) {\n\t const self = this;\n\t const options = Object.assign({\n\t text: option => {\n\t return option[self.settings.labelField];\n\t }\n\t }, userOptions);\n\t self.on('item_remove', function (value) {\n\t if (!self.isFocused) {\n\t return;\n\t }\n\n\t if (self.control_input.value.trim() === '') {\n\t var option = self.options[value];\n\n\t if (option) {\n\t self.setTextboxValue(options.text.call(self, option));\n\t }\n\t }\n\t });\n\t}\n\n\t/**\n\t * Plugin: \"restore_on_backspace\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction virtual_scroll () {\n\t const self = this;\n\t const orig_canLoad = self.canLoad;\n\t const orig_clearActiveOption = self.clearActiveOption;\n\t const orig_loadCallback = self.loadCallback;\n\t var pagination = {};\n\t var dropdown_content;\n\t var loading_more = false;\n\t var load_more_opt;\n\t var default_values = [];\n\n\t if (!self.settings.shouldLoadMore) {\n\t // return true if additional results should be loaded\n\t self.settings.shouldLoadMore = () => {\n\t const scroll_percent = dropdown_content.clientHeight / (dropdown_content.scrollHeight - dropdown_content.scrollTop);\n\n\t if (scroll_percent > 0.9) {\n\t return true;\n\t }\n\n\t if (self.activeOption) {\n\t var selectable = self.selectable();\n\t var index = Array.from(selectable).indexOf(self.activeOption);\n\n\t if (index >= selectable.length - 2) {\n\t return true;\n\t }\n\t }\n\n\t return false;\n\t };\n\t }\n\n\t if (!self.settings.firstUrl) {\n\t throw 'virtual_scroll plugin requires a firstUrl() method';\n\t } // in order for virtual scrolling to work,\n\t // options need to be ordered the same way they're returned from the remote data source\n\n\n\t self.settings.sortField = [{\n\t field: '$order'\n\t }, {\n\t field: '$score'\n\t }]; // can we load more results for given query?\n\n\t const canLoadMore = query => {\n\t if (typeof self.settings.maxOptions === 'number' && dropdown_content.children.length >= self.settings.maxOptions) {\n\t return false;\n\t }\n\n\t if (query in pagination && pagination[query]) {\n\t return true;\n\t }\n\n\t return false;\n\t };\n\n\t const clearFilter = (option, value) => {\n\t if (self.items.indexOf(value) >= 0 || default_values.indexOf(value) >= 0) {\n\t return true;\n\t }\n\n\t return false;\n\t }; // set the next url that will be\n\n\n\t self.setNextUrl = (value, next_url) => {\n\t pagination[value] = next_url;\n\t }; // getUrl() to be used in settings.load()\n\n\n\t self.getUrl = query => {\n\t if (query in pagination) {\n\t const next_url = pagination[query];\n\t pagination[query] = false;\n\t return next_url;\n\t } // if the user goes back to a previous query\n\t // we need to load the first page again\n\n\n\t pagination = {};\n\t return self.settings.firstUrl.call(self, query);\n\t }; // don't clear the active option (and cause unwanted dropdown scroll)\n\t // while loading more results\n\n\n\t self.hook('instead', 'clearActiveOption', () => {\n\t if (loading_more) {\n\t return;\n\t }\n\n\t return orig_clearActiveOption.call(self);\n\t }); // override the canLoad method\n\n\t self.hook('instead', 'canLoad', query => {\n\t // first time the query has been seen\n\t if (!(query in pagination)) {\n\t return orig_canLoad.call(self, query);\n\t }\n\n\t return canLoadMore(query);\n\t }); // wrap the load\n\n\t self.hook('instead', 'loadCallback', (options, optgroups) => {\n\t if (!loading_more) {\n\t self.clearOptions(clearFilter);\n\t } else if (load_more_opt) {\n\t const first_option = options[0];\n\n\t if (first_option !== undefined) {\n\t load_more_opt.dataset.value = first_option[self.settings.valueField];\n\t }\n\t }\n\n\t orig_loadCallback.call(self, options, optgroups);\n\t loading_more = false;\n\t }); // add templates to dropdown\n\t //\tloading_more if we have another url in the queue\n\t //\tno_more_results if we don't have another url in the queue\n\n\t self.hook('after', 'refreshOptions', () => {\n\t const query = self.lastValue;\n\t var option;\n\n\t if (canLoadMore(query)) {\n\t option = self.render('loading_more', {\n\t query: query\n\t });\n\n\t if (option) {\n\t option.setAttribute('data-selectable', ''); // so that navigating dropdown with [down] keypresses can navigate to this node\n\n\t load_more_opt = option;\n\t }\n\t } else if (query in pagination && !dropdown_content.querySelector('.no-results')) {\n\t option = self.render('no_more_results', {\n\t query: query\n\t });\n\t }\n\n\t if (option) {\n\t addClasses(option, self.settings.optionClass);\n\t dropdown_content.append(option);\n\t }\n\t }); // add scroll listener and default templates\n\n\t self.on('initialize', () => {\n\t default_values = Object.keys(self.options);\n\t dropdown_content = self.dropdown_content; // default templates\n\n\t self.settings.render = Object.assign({}, {\n\t loading_more: () => {\n\t return `<div class=\"loading-more-results\">Loading more results ... </div>`;\n\t },\n\t no_more_results: () => {\n\t return `<div class=\"no-more-results\">No more results</div>`;\n\t }\n\t }, self.settings.render); // watch dropdown content scroll position\n\n\t dropdown_content.addEventListener('scroll', () => {\n\t if (!self.settings.shouldLoadMore.call(self)) {\n\t return;\n\t } // !important: this will get checked again in load() but we still need to check here otherwise loading_more will be set to true\n\n\n\t if (!canLoadMore(self.lastValue)) {\n\t return;\n\t } // don't call load() too much\n\n\n\t if (loading_more) return;\n\t loading_more = true;\n\t self.load.call(self, self.lastValue);\n\t });\n\t });\n\t}\n\n\tTomSelect.define('change_listener', change_listener);\n\tTomSelect.define('checkbox_options', checkbox_options);\n\tTomSelect.define('clear_button', clear_button);\n\tTomSelect.define('drag_drop', drag_drop);\n\tTomSelect.define('dropdown_header', dropdown_header);\n\tTomSelect.define('caret_position', caret_position);\n\tTomSelect.define('dropdown_input', dropdown_input);\n\tTomSelect.define('input_autogrow', input_autogrow);\n\tTomSelect.define('no_backspace_delete', no_backspace_delete);\n\tTomSelect.define('no_active_items', no_active_items);\n\tTomSelect.define('optgroup_columns', optgroup_columns);\n\tTomSelect.define('remove_button', remove_button);\n\tTomSelect.define('restore_on_backspace', restore_on_backspace);\n\tTomSelect.define('virtual_scroll', virtual_scroll);\n\n\treturn TomSelect;\n\n}));\nvar tomSelect=function(el,opts){return new TomSelect(el,opts);} \n//# sourceMappingURL=tom-select.complete.js.map\n\n\n//# sourceURL=webpack:///./node_modules/tom-select/dist/js/tom-select.complete.js?")}
53,0: 54/*!**************************************************************************************************!*\ 55 !*** multi ./JavaScript/Frontend/main.js ./Sass/backend.scss ./Sass/demo.scss ./Sass/style.scss ***! 56 \**************************************************************************************************/ 57/*! no static exports found */function(module,exports,__webpack_require__){eval('__webpack_require__(/*! ./JavaScript/Frontend/main.js */"./JavaScript/Frontend/main.js");\n__webpack_require__(/*! ./Sass/backend.scss */"./Sass/backend.scss");\n__webpack_require__(/*! ./Sass/demo.scss */"./Sass/demo.scss");\nmodule.exports = __webpack_require__(/*! ./Sass/style.scss */"./Sass/style.scss");\n\n\n//# sourceURL=webpack:///multi_./JavaScript/Frontend/main.js_./Sass/backend.scss_./Sass/demo.scss_./Sass/style.scss?')}});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.