diff --git a/src/OrchardCore.Modules/OrchardCore.Resources/ResourceManagementOptionsConfiguration.cs b/src/OrchardCore.Modules/OrchardCore.Resources/ResourceManagementOptionsConfiguration.cs index 7dd85255e3b..6f811a44798 100644 --- a/src/OrchardCore.Modules/OrchardCore.Resources/ResourceManagementOptionsConfiguration.cs +++ b/src/OrchardCore.Modules/OrchardCore.Resources/ResourceManagementOptionsConfiguration.cs @@ -201,16 +201,16 @@ ResourceManifest BuildManifest() manifest .DefineStyle("bootstrap-select") .SetUrl("~/OrchardCore.Resources/Styles/bootstrap-select.min.css", "~/OrchardCore.Resources/Styles/bootstrap-select.css") - .SetCdn("https://cdn.jsdelivr.net/npm/bootstrap-select@1.14.0-beta2/dist/css/bootstrap-select.min.css", "https://cdn.jsdelivr.net/npm/bootstrap-select@1.14.0-beta2/dist/css/bootstrap-select.css") - .SetCdnIntegrity("sha256-UqiEyrW1sB5d6ZDzcWXKfYCR4MKVYMEdXNjJde84cjc=", "sha256-bmB8s0iyqUelK/WUqWRUG6y8K6RZYD2D/GJU2iIpF8s=") + .SetCdn("https://cdn.jsdelivr.net/npm/bootstrap-select@1.14.0-beta3/dist/css/bootstrap-select.min.css", "https://cdn.jsdelivr.net/npm/bootstrap-select@1.14.0-beta3/dist/css/bootstrap-select.css") + .SetCdnIntegrity("sha384-xF1Y2i6HgC34+4EWddbDhlQuru7cLSKRcPT3hoL3mPoKoV+624vVSZJmegPX77vS", "sha384-DtuOZ7LbR+xAYzDGD4YLpe9eiAayUBwZRqAcoy+RepIoV53tAoJbXnr4AX1xTJ43") .SetVersion("1.14.0"); manifest .DefineScript("bootstrap-select") .SetDependencies("jQuery") .SetUrl("~/OrchardCore.Resources/Scripts/bootstrap-select.min.js", "~/OrchardCore.Resources/Scripts/bootstrap-select.js") - .SetCdn("https://cdn.jsdelivr.net/npm/bootstrap-select@1.14.0-beta2/dist/js/bootstrap-select.min.js", "https://cdn.jsdelivr.net/npm/bootstrap-select@1.14.0-beta2/dist/js/bootstrap-select.js") - .SetCdnIntegrity("sha256-KK/CsQKh6Rb0LsRn4Z8Jcs4h7rRquelIb4EjQm6ige4=", "sha256-igJSxRuCIkTAOsoD48Fqd3mYbVGWL17ajzNLe+Ke2Hk=") + .SetCdn("https://cdn.jsdelivr.net/npm/bootstrap-select@1.14.0-beta3/dist/js/bootstrap-select.min.js", "https://cdn.jsdelivr.net/npm/bootstrap-select@1.14.0-beta3/dist/js/bootstrap-select.js") + .SetCdnIntegrity("sha384-0O3sg2SQIGn4393xwamQISjphC8DIXjCzlhj1gPAMC5xGg+2perF5Mehr5njv0fZ", "sha384-2b0aLFg/Ejp4OF57nW0BUqNzm259RHYYMf/mpKClBijsEH2P+4ea2oWAq0twd8L0") .SetVersion("1.14.0"); manifest diff --git a/src/OrchardCore.Modules/OrchardCore.Resources/package-lock.json b/src/OrchardCore.Modules/OrchardCore.Resources/package-lock.json index 62778bdd4e0..4d30fc1a4ad 100644 --- a/src/OrchardCore.Modules/OrchardCore.Resources/package-lock.json +++ b/src/OrchardCore.Modules/OrchardCore.Resources/package-lock.json @@ -12,7 +12,7 @@ "@popperjs/core": "2.10.2", "bootstrap": "5.1.3", "bootstrap-scss": "5.1.3", - "bootstrap-select": "1.14.0-beta2", + "bootstrap-select": "1.14.0-beta3", "codemirror": "5.65.7", "jquery": "3.7.1", "jquery-resizable-dom": "0.35.0", @@ -180,9 +180,9 @@ "integrity": "sha512-vgj+bNDlS6Lzu7u+TGgN+P7YI45pS/ujKGznA8WIm74XnPK6LehhV8ueXjvjQxJ1MiYChLyDSb03b+ZCu59Evg==" }, "node_modules/bootstrap-select": { - "version": "1.14.0-beta2", - "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.14.0-beta2.tgz", - "integrity": "sha512-Q63QUbConUwA+/Te7tCJcv0nE3SI/J+rNI5A1mdX1KxP6lW0pFQy+4KVP6VwgZEcwkoPfrwjvAo6WT7fdl+Sdg==", + "version": "1.14.0-beta3", + "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.14.0-beta3.tgz", + "integrity": "sha512-wYUDY4NAYBcNydXybE7wh3+ucyf+AcUOhZ+e0TFIoZ38A+k/3BVT1RPl5f0CiPxAexP1IQuqALKMqI8wtZS71A==", "peerDependencies": { "bootstrap": ">=3.0.0", "jquery": "1.9.1 - 3" @@ -755,9 +755,9 @@ "integrity": "sha512-vgj+bNDlS6Lzu7u+TGgN+P7YI45pS/ujKGznA8WIm74XnPK6LehhV8ueXjvjQxJ1MiYChLyDSb03b+ZCu59Evg==" }, "bootstrap-select": { - "version": "1.14.0-beta2", - "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.14.0-beta2.tgz", - "integrity": "sha512-Q63QUbConUwA+/Te7tCJcv0nE3SI/J+rNI5A1mdX1KxP6lW0pFQy+4KVP6VwgZEcwkoPfrwjvAo6WT7fdl+Sdg==", + "version": "1.14.0-beta3", + "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.14.0-beta3.tgz", + "integrity": "sha512-wYUDY4NAYBcNydXybE7wh3+ucyf+AcUOhZ+e0TFIoZ38A+k/3BVT1RPl5f0CiPxAexP1IQuqALKMqI8wtZS71A==", "requires": {} }, "brace-expansion": { diff --git a/src/OrchardCore.Modules/OrchardCore.Resources/package.json b/src/OrchardCore.Modules/OrchardCore.Resources/package.json index 3d3adf19025..b955a54b7ec 100644 --- a/src/OrchardCore.Modules/OrchardCore.Resources/package.json +++ b/src/OrchardCore.Modules/OrchardCore.Resources/package.json @@ -6,7 +6,7 @@ "@popperjs/core": "2.10.2", "bootstrap": "5.1.3", "bootstrap-scss": "5.1.3", - "bootstrap-select": "1.14.0-beta2", + "bootstrap-select": "1.14.0-beta3", "nouislider": "15.7.0", "codemirror": "5.65.7", "jquery": "3.7.1", diff --git a/src/OrchardCore.Modules/OrchardCore.Resources/wwwroot/Scripts/bootstrap-select.js b/src/OrchardCore.Modules/OrchardCore.Resources/wwwroot/Scripts/bootstrap-select.js index c3ade449e24..bbc86afdc3f 100644 --- a/src/OrchardCore.Modules/OrchardCore.Resources/wwwroot/Scripts/bootstrap-select.js +++ b/src/OrchardCore.Modules/OrchardCore.Resources/wwwroot/Scripts/bootstrap-select.js @@ -5,9 +5,9 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } /*! - * Bootstrap-select v1.14.0-beta2 (https://developer.snapappointments.com/bootstrap-select) + * Bootstrap-select v1.14.0-beta3 (https://developer.snapappointments.com/bootstrap-select) * - * Copyright 2012-2021 SnapAppointments, LLC + * Copyright 2012-2022 SnapAppointments, LLC * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE) */ @@ -221,6 +221,13 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == } testElement = null; + // Polyfill for IE (remove in v2) + Object.values = typeof Object.values === 'function' ? Object.values : function (obj) { + return Object.keys(obj).map(function (key) { + return obj[key]; + }); + }; + // shallow array comparison function isEqual(array1, array2) { return array1.length === array2.length && array1.every(function (element, index) { @@ -278,8 +285,17 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == } })(); } + function toKebabCase(str) { + return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, function ($, ofs) { + return (ofs ? '-' : '') + $.toLowerCase(); + }); + } function getSelectedOptions() { - var selectedOptions = this.selectpicker.main.data.filter(function (item) { + var options = this.selectpicker.main.data; + if (this.options.source.data || this.options.source.search) { + options = Object.values(this.selectpicker.optionValuesDataMap); + } + var selectedOptions = options.filter(function (item) { if (item.selected) { if (this.options.hideDisabled && item.disabled) return false; return true; @@ -868,11 +884,11 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == case 'style': value = option.style.cssText; break; - case 'content': - case 'tokens': - case 'subtext': - case 'icon': - value = option.getAttribute('data-' + type); + case 'title': + value = option.title; + break; + default: + value = option.getAttribute('data-' + toKebabCase(type)); break; } return value; @@ -884,12 +900,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == case 'label': value = option.text || option.value || ''; break; - case 'divider': - case 'style': - case 'content': - case 'tokens': - case 'subtext': - case 'icon': + default: value = option[type]; break; } @@ -920,12 +931,19 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == this.options = options; this.selectpicker = { main: { - optionQueue: elementTemplates.fragment.cloneNode(false) + data: [], + optionQueue: elementTemplates.fragment.cloneNode(false), + hasMore: false + }, + search: { + data: [], + hasMore: false }, - search: {}, current: {}, - // current changes if a search is in progress + // current is either equal to main or search depending on if a search is in progress view: {}, + // map of option values and their respective data (only used in conjunction with options.source) + optionValuesDataMap: {}, isSearching: false, keydown: { keyHistory: '', @@ -959,7 +977,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == this.hide = Selectpicker.prototype.hide; this.init(); }; - Selectpicker.VERSION = '1.14.0-beta2'; + Selectpicker.VERSION = '1.14.0-beta3'; // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both. Selectpicker.DEFAULTS = { @@ -973,7 +991,9 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == }, selectAllText: 'Select All', deselectAllText: 'Deselect All', - source: {}, + source: { + pageSize: 40 + }, chunkSize: 40, doneButton: false, doneButtonText: 'Close', @@ -1006,7 +1026,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == }, maxOptions: false, mobile: false, - selectOnTab: false, + selectOnTab: true, dropdownAlignRight: false, windowPadding: 0, virtualScroll: 600, @@ -1051,13 +1071,6 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == that.$element.trigger('loaded' + EVENT_KEY); }); }); - this.fetchData(function () { - that.render(true); - that.buildList(); - requestAnimationFrame(function () { - that.$element.trigger('loaded' + EVENT_KEY); - }); - }); if (this.options.dropdownAlignRight === true) this.$menu[0].classList.add(classNames.MENURIGHT); if (typeof id !== 'undefined') { this.$button.attr('data-id', id); @@ -1197,10 +1210,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == }, createView: function createView(isSearching, setSize, refresh) { var that = this, - scrollTop = 0, - active = [], - selected, - prevActive; + scrollTop = 0; this.selectpicker.isSearching = isSearching; this.selectpicker.current = isSearching ? this.selectpicker.search : this.selectpicker.main; this.setPositionData(); @@ -1261,24 +1271,21 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == that.selectpicker.view.position0 = isVirtual === false ? 0 : Math.max(0, chunks[firstChunk][0]) || 0; that.selectpicker.view.position1 = isVirtual === false ? size : Math.min(size, chunks[lastChunk][1]) || 0; positionIsDifferent = prevPositions[0] !== that.selectpicker.view.position0 || prevPositions[1] !== that.selectpicker.view.position1; - if (that.activeIndex !== undefined) { - prevActive = (that.selectpicker.main.data[that.prevActiveIndex] || {}).element; - active = (that.selectpicker.main.data[that.activeIndex] || {}).element; - selected = (that.selectpicker.main.data[that.selectedIndex] || {}).element; + if (that.activeElement !== undefined) { if (init) { - if (that.activeIndex !== that.selectedIndex) { - that.defocusItem(active); + if (that.activeElement !== that.selectedElement) { + that.defocusItem(that.activeElement); } - that.activeIndex = undefined; + that.activeElement = undefined; } - if (that.activeIndex && that.activeIndex !== that.selectedIndex) { - that.defocusItem(selected); + if (that.activeElement !== that.selectedElement) { + that.defocusItem(that.selectedElement); } } - if (that.prevActiveIndex !== undefined && that.prevActiveIndex !== that.activeIndex && that.prevActiveIndex !== that.selectedIndex) { - that.defocusItem(prevActive); + if (that.prevActiveElement !== undefined && that.prevActiveElement !== that.activeElement && that.prevActiveElement !== that.selectedElement) { + that.defocusItem(that.prevActiveElement); } - if (init || positionIsDifferent) { + if (init || positionIsDifferent || that.selectpicker.current.hasMore) { previousElements = that.selectpicker.view.visibleElements ? that.selectpicker.view.visibleElements.slice() : []; if (isVirtual === false) { that.selectpicker.view.visibleElements = that.selectpicker.current.elements; @@ -1354,16 +1361,22 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == } } } - if ((!isSearching && that.options.source.load || isSearching && that.options.source.search) && currentChunk === chunkCount - 1) { - that.fetchData(function () { - that.render(); - that.buildList(size, isSearching); - that.setPositionData(); - scroll(scrollTop); - }, isSearching ? 'search' : 'load', currentChunk + 1, isSearching ? that.selectpicker.search.previousValue : undefined); + if ((!isSearching && that.options.source.data || isSearching && that.options.source.search) && that.selectpicker.current.hasMore && currentChunk === chunkCount - 1) { + // Don't load the next chunk until scrolling has started + // This prevents unnecessary requests while the user is typing if pageSize is <= chunkSize + if (scrollTop > 0) { + // Chunks use 0-based indexing, but pages use 1-based. Add 1 to convert and add 1 again to get next page + var page = Math.floor(currentChunk * that.options.chunkSize / that.options.source.pageSize) + 2; + that.fetchData(function () { + that.render(); + that.buildList(size, isSearching); + that.setPositionData(); + scroll(scrollTop); + }, isSearching ? 'search' : 'data', page, isSearching ? that.selectpicker.search.previousValue : undefined); + } } } - that.prevActiveIndex = that.activeIndex; + that.prevActiveElement = that.activeElement; if (!that.options.liveSearch) { that.$menuInner.trigger('focus'); } else if (isSearching && init) { @@ -1374,7 +1387,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == } newActive = that.selectpicker.view.visibleElements[index]; that.defocusItem(that.selectpicker.view.currentActive); - that.activeIndex = (that.selectpicker.current.data[index] || {}).index; + that.activeElement = (that.selectpicker.current.data[index] || {}).element; that.focusItem(newActive); } } @@ -1385,7 +1398,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == }, focusItem: function focusItem(li, liData, noStyle) { if (li) { - liData = liData || this.selectpicker.main.data[this.activeIndex]; + liData = liData || this.selectpicker.current.data[this.selectpicker.current.elements.indexOf(this.activeElement)]; var a = li.firstChild; if (a) { a.setAttribute('aria-setsize', this.selectpicker.view.size); @@ -1453,6 +1466,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == return updateIndex; }, fetchData: function fetchData(callback, type, page, searchValue) { + page = page || 1; type = type || 'data'; var that = this, data = this.options.source[type], @@ -1460,9 +1474,13 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == if (data) { this.options.virtualScroll = true; if (typeof data === 'function') { - data.call(this, function (data) { + data.call(this, function (data, more, totalItems) { + var current = that.selectpicker[type === 'search' ? 'search' : 'main']; + current.hasMore = more; + current.totalItems = totalItems; builtData = that.buildData(data, type); callback.call(that, builtData); + that.$element.trigger('fetched' + EVENT_KEY); }, page, searchValue); } else if (Array.isArray(data)) { builtData = that.buildData(data, type); @@ -1474,16 +1492,15 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == } }, buildData: function buildData(data, type) { + var that = this; var dataGetter = data === false ? getOptionData.fromOption : getOptionData.fromDataSource; - var optionSelector = ':not([hidden]):not([data-hidden="true"])', + var optionSelector = ':not([hidden]):not([data-hidden="true"]):not([style*="display: none"])', mainData = [], - startLen = 0, + startLen = this.selectpicker.main.data ? this.selectpicker.main.data.length : 0, optID = 0, startIndex = this.setPlaceholder() && !data ? 1 : 0; // append the titleOption if necessary and skip the first option in the loop - if (type === 'load') { - startLen = this.selectpicker.main.data.length; - } else if (type === 'search') { + if (type === 'search') { startLen = this.selectpicker.search.data.length; } if (this.options.hideDisabled) optionSelector += ':not(:disabled)'; @@ -1515,6 +1532,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == config.optionClass = optionClass.trim(); config.inlineStyle = inlineStyle; config.text = dataGetter(item, 'text'); + config.title = dataGetter(item, 'title'); config.content = dataGetter(item, 'content'); config.tokens = dataGetter(item, 'tokens'); config.subtext = dataGetter(item, 'subtext'); @@ -1527,6 +1545,13 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == config.option.liIndex = liIndex; config.selected = !!item.selected; config.disabled = config.disabled || !!item.disabled; + if (data !== false) { + if (that.selectpicker.optionValuesDataMap[config.value]) { + config = $.extend(that.selectpicker.optionValuesDataMap[config.value], config); + } else { + that.selectpicker.optionValuesDataMap[config.value] = config; + } + } mainData.push(config); } } @@ -1542,7 +1567,8 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == subtext: dataGetter(optgroup, 'subtext'), icon: dataGetter(optgroup, 'icon'), type: 'optgroup-label', - optgroupClass: ' ' + (optgroup.className || '') + optgroupClass: ' ' + (optgroup.className || ''), + optgroup: optgroup }, headerIndex, lastIndex; @@ -1578,7 +1604,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == var item = selectOptions[i], children = item.children; if (children && children.length) { - addOptgroup.call(this, startIndex, selectOptions); + addOptgroup.call(this, i, selectOptions); } else { addOption.call(this, item, {}); } @@ -1586,11 +1612,9 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == switch (type) { case 'data': { - this.selectpicker.main.data = this.selectpicker.current.data = mainData; - break; - } - case 'load': - { + if (!this.selectpicker.main.data) { + this.selectpicker.main.data = []; + } Array.prototype.push.apply(this.selectpicker.main.data, mainData); this.selectpicker.current.data = this.selectpicker.main.data; break; @@ -1629,8 +1653,12 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == liElement = generateOption.li(generateOption.label.call(that, item), 'dropdown-header' + item.optgroupClass, item.optID); break; } - item.element = liElement; - mainElements.push(liElement); + if (!item.element) { + item.element = liElement; + } else { + item.element.innerHTML = liElement.innerHTML; + } + mainElements.push(item.element); // count the number of characters in the option - not perfect, but should work in most cases if (item.display) combinedLength += item.display.length; @@ -1707,7 +1735,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == text: this.options.placeholder }, true); } else { - showCount = this.multiple && this.options.selectedTextFormat.indexOf('count') !== -1 && selectedCount > 1; + showCount = this.multiple && this.options.selectedTextFormat.indexOf('count') !== -1 && selectedCount > 0; // determine if the number of selected options will be shown (showCount === true) if (showCount) { @@ -1751,7 +1779,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == } } } else { - var optionSelector = ':not([hidden]):not([data-hidden="true"]):not([data-divider="true"])'; + var optionSelector = ':not([hidden]):not([data-hidden="true"]):not([data-divider="true"]):not([style*="display: none"])'; if (this.options.hideDisabled) optionSelector += ':not(:disabled)'; // If this is a multiselect, and selectedTextFormat is count, then show 1 of 2 selected, etc. @@ -1853,7 +1881,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == if (this.selectpicker.current.data.length) { for (var i = 0; i < this.selectpicker.current.data.length; i++) { var data = this.selectpicker.current.data[i]; - if (data.type === 'option') { + if (data.type === 'option' && $(data.element.firstChild).css('display') !== 'none') { li = data.element; break; } @@ -2005,7 +2033,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == }); this.$menuInner.css({ 'max-height': menuInnerHeight + 'px', - 'overflow-y': 'auto', + 'overflow': 'hidden auto', 'min-height': menuInnerMinHeight + 'px' }); @@ -2166,25 +2194,24 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == } }, /** - * @param {number} index - the index of the option that is being changed + * @param {Object} liData - the option object that is being changed * @param {boolean} selected - true if the option is being selected, false if being deselected */ setSelected: function setSelected(liData, selected) { selected = selected === undefined ? liData.selected : selected; - var index = liData.index, - li = liData.element, - activeIndexIsSet = this.activeIndex !== undefined, - thisIsActive = this.activeIndex === index, + var li = liData.element, + activeElementIsSet = this.activeElement !== undefined, + thisIsActive = this.activeElement === li, prevActive, a, // if current option is already active // OR // if the current option is being selected, it's NOT multiple, and - // activeIndex is undefined: + // activeElement is undefined: // - when the menu is first being opened, OR // - after a search has been performed, OR - // - when retainActive is false when selecting a new option (i.e. index of the newly selected option is not the same as the current activeIndex) - keepActive = thisIsActive || selected && !this.multiple && !activeIndexIsSet; + // - when retainActive is false when selecting a new option (i.e. index of the newly selected option is not the same as the current activeElement) + keepActive = thisIsActive || selected && !this.multiple && !activeElementIsSet; if (!li) return; if (selected !== undefined) { liData.selected = selected; @@ -2195,13 +2222,13 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == } a = li.firstChild; if (selected) { - this.selectedIndex = index; + this.selectedElement = li; } li.classList.toggle('selected', selected); if (keepActive) { this.focusItem(li, liData); this.selectpicker.view.currentActive = li; - this.activeIndex = index; + this.activeElement = li; } else { this.defocusItem(li); } @@ -2217,8 +2244,8 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == } } } - if (!keepActive && !activeIndexIsSet && selected && this.prevActiveIndex !== undefined) { - prevActive = this.selectpicker.main.elements[this.prevActiveIndex]; + if (!keepActive && !activeElementIsSet && selected && this.prevActiveElement !== undefined) { + prevActive = this.prevActiveElement; this.defocusItem(prevActive); } }, @@ -2355,7 +2382,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == element = that.$element[0], position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0, clickedData = that.selectpicker.current.data[$this.parent().index() + position0], - clickedIndex = clickedData.index, + clickedElement = clickedData.element, prevValue = getSelectValues.call(that), prevIndex = element.selectedIndex, prevOption = element.options[prevIndex], @@ -2373,16 +2400,20 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == var option = clickedData.option, $option = $(option), state = option.selected, - $optgroup = $option.parent('optgroup'), - $optgroupOptions = $optgroup.find('option'), - maxOptions = that.options.maxOptions, - maxOptionsGrp = $optgroup.data('maxOptions') || false; - if (clickedIndex === that.activeIndex) retainActive = true; + optgroupData = that.selectpicker.current.data.find(function (datum) { + return datum.optID === clickedData.optID && datum.type === 'optgroup-label'; + }), + optgroup = optgroupData ? optgroupData.optgroup : undefined, + dataGetter = optgroup instanceof Element ? getOptionData.fromOption : getOptionData.fromDataSource, + optgroupOptions = optgroup && optgroup.children, + maxOptions = parseInt(that.options.maxOptions), + maxOptionsGrp = optgroup && parseInt(dataGetter(optgroup, 'maxOptions')) || false; + if (clickedElement === that.activeElement) retainActive = true; if (!retainActive) { - that.prevActiveIndex = that.activeIndex; - that.activeIndex = undefined; + that.prevActiveElement = that.activeElement; + that.activeElement = undefined; } - if (!that.multiple) { + if (!that.multiple || maxOptions === 1) { // Deselect previous option if not multi select if (prevData) that.setSelected(prevData, false); that.setSelected(clickedData, true); @@ -2392,20 +2423,23 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == that.focusedParent.focus(); if (maxOptions !== false || maxOptionsGrp !== false) { var maxReached = maxOptions < getSelectedOptions.call(that).length, - maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length; + selectedGroupOptions = 0; + if (optgroup && optgroup.children) { + for (var i = 0; i < optgroup.children.length; i++) { + if (optgroup.children[i].selected) selectedGroupOptions++; + } + } + var maxReachedGrp = maxOptionsGrp < selectedGroupOptions; if (maxOptions && maxReached || maxOptionsGrp && maxReachedGrp) { - if (maxOptions && maxOptions == 1) { + if (maxOptions && maxOptions === 1) { element.selectedIndex = -1; - option.selected = true; that.setOptionStatus(true); - } else if (maxOptionsGrp && maxOptionsGrp == 1) { - for (var i = 0; i < $optgroupOptions.length; i++) { - var _option = $optgroupOptions[i]; - _option.selected = false; - that.setSelected(_option.liIndex, false); + } else if (maxOptionsGrp && maxOptionsGrp === 1) { + for (var i = 0; i < optgroupOptions.length; i++) { + var _option = optgroupOptions[i]; + that.setSelected(that.selectpicker.current.data[_option.liIndex], false); } - option.selected = true; - that.setSelected(clickedIndex, true); + that.setSelected(clickedData, true); } else { var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText, maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText, @@ -2418,7 +2452,6 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]); maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]); } - option.selected = false; that.$menu.append($notify); if (maxOptions && maxReached) { $notify.append($('