';\r\n\r\n return $(drop);\r\n },\r\n\r\n setPositionData: function () {\r\n this.selectpicker.view.canHighlight = [];\r\n\r\n for (var i = 0; i < this.selectpicker.current.data.length; i++) {\r\n var li = this.selectpicker.current.data[i],\r\n canHighlight = true;\r\n\r\n if (li.type === 'divider') {\r\n canHighlight = false;\r\n li.height = this.sizeInfo.dividerHeight;\r\n } else if (li.type === 'optgroup-label') {\r\n canHighlight = false;\r\n li.height = this.sizeInfo.dropdownHeaderHeight;\r\n } else {\r\n li.height = this.sizeInfo.liHeight;\r\n }\r\n\r\n if (li.disabled) canHighlight = false;\r\n\r\n this.selectpicker.view.canHighlight.push(canHighlight);\r\n\r\n li.position = (i === 0 ? 0 : this.selectpicker.current.data[i - 1].position) + li.height;\r\n }\r\n },\r\n\r\n isVirtual: function () {\r\n return (this.options.virtualScroll !== false) && (this.selectpicker.main.elements.length >= this.options.virtualScroll) || this.options.virtualScroll === true;\r\n },\r\n\r\n createView: function (isSearching, scrollTop) {\r\n scrollTop = scrollTop || 0;\r\n\r\n var that = this;\r\n\r\n this.selectpicker.current = isSearching ? this.selectpicker.search : this.selectpicker.main;\r\n\r\n var active = [];\r\n var selected;\r\n var prevActive;\r\n\r\n this.setPositionData();\r\n\r\n scroll(scrollTop, true);\r\n\r\n this.$menuInner.off('scroll.createView').on('scroll.createView', function (e, updateValue) {\r\n if (!that.noScroll) scroll(this.scrollTop, updateValue);\r\n that.noScroll = false;\r\n });\r\n\r\n function scroll (scrollTop, init) {\r\n var size = that.selectpicker.current.elements.length,\r\n chunks = [],\r\n chunkSize,\r\n chunkCount,\r\n firstChunk,\r\n lastChunk,\r\n currentChunk,\r\n prevPositions,\r\n positionIsDifferent,\r\n previousElements,\r\n menuIsDifferent = true,\r\n isVirtual = that.isVirtual();\r\n\r\n that.selectpicker.view.scrollTop = scrollTop;\r\n\r\n if (isVirtual === true) {\r\n // if an option that is encountered that is wider than the current menu width, update the menu width accordingly\r\n if (that.sizeInfo.hasScrollBar && that.$menu[0].offsetWidth > that.sizeInfo.totalMenuWidth) {\r\n that.sizeInfo.menuWidth = that.$menu[0].offsetWidth;\r\n that.sizeInfo.totalMenuWidth = that.sizeInfo.menuWidth + that.sizeInfo.scrollBarWidth;\r\n that.$menu.css('min-width', that.sizeInfo.menuWidth);\r\n }\r\n }\r\n\r\n chunkSize = Math.ceil(that.sizeInfo.menuInnerHeight / that.sizeInfo.liHeight * 1.5); // number of options in a chunk\r\n chunkCount = Math.round(size / chunkSize) || 1; // number of chunks\r\n\r\n for (var i = 0; i < chunkCount; i++) {\r\n var endOfChunk = (i + 1) * chunkSize;\r\n\r\n if (i === chunkCount - 1) {\r\n endOfChunk = size;\r\n }\r\n\r\n chunks[i] = [\r\n (i) * chunkSize + (!i ? 0 : 1),\r\n endOfChunk\r\n ];\r\n\r\n if (!size) break;\r\n\r\n if (currentChunk === undefined && scrollTop <= that.selectpicker.current.data[endOfChunk - 1].position - that.sizeInfo.menuInnerHeight) {\r\n currentChunk = i;\r\n }\r\n }\r\n\r\n if (currentChunk === undefined) currentChunk = 0;\r\n\r\n prevPositions = [that.selectpicker.view.position0, that.selectpicker.view.position1];\r\n\r\n // always display previous, current, and next chunks\r\n firstChunk = Math.max(0, currentChunk - 1);\r\n lastChunk = Math.min(chunkCount - 1, currentChunk + 1);\r\n\r\n that.selectpicker.view.position0 = Math.max(0, chunks[firstChunk][0]) || 0;\r\n that.selectpicker.view.position1 = Math.min(size, chunks[lastChunk][1]) || 0;\r\n\r\n positionIsDifferent = prevPositions[0] !== that.selectpicker.view.position0 || prevPositions[1] !== that.selectpicker.view.position1;\r\n\r\n if (that.activeIndex !== undefined) {\r\n prevActive = that.selectpicker.current.elements[that.selectpicker.current.map.newIndex[that.prevActiveIndex]];\r\n active = that.selectpicker.current.elements[that.selectpicker.current.map.newIndex[that.activeIndex]];\r\n selected = that.selectpicker.current.elements[that.selectpicker.current.map.newIndex[that.selectedIndex]];\r\n\r\n if (init) {\r\n if (that.activeIndex !== that.selectedIndex && active && active.length) {\r\n active.classList.remove('active');\r\n if (active.firstChild) active.firstChild.classList.remove('active');\r\n }\r\n that.activeIndex = undefined;\r\n }\r\n\r\n if (that.activeIndex && that.activeIndex !== that.selectedIndex && selected && selected.length) {\r\n selected.classList.remove('active');\r\n if (selected.firstChild) selected.firstChild.classList.remove('active');\r\n }\r\n }\r\n\r\n if (that.prevActiveIndex !== undefined && that.prevActiveIndex !== that.activeIndex && that.prevActiveIndex !== that.selectedIndex && prevActive && prevActive.length) {\r\n prevActive.classList.remove('active');\r\n if (prevActive.firstChild) prevActive.firstChild.classList.remove('active');\r\n }\r\n\r\n if (init || positionIsDifferent) {\r\n previousElements = that.selectpicker.view.visibleElements ? that.selectpicker.view.visibleElements.slice() : [];\r\n\r\n that.selectpicker.view.visibleElements = that.selectpicker.current.elements.slice(that.selectpicker.view.position0, that.selectpicker.view.position1);\r\n\r\n that.setOptionStatus();\r\n\r\n // if searching, check to make sure the list has actually been updated before updating DOM\r\n // this prevents unnecessary repaints\r\n if (isSearching || (isVirtual === false && init)) menuIsDifferent = !isEqual(previousElements, that.selectpicker.view.visibleElements);\r\n\r\n // if virtual scroll is disabled and not searching,\r\n // menu should never need to be updated more than once\r\n if ((init || isVirtual === true) && menuIsDifferent) {\r\n var menuInner = that.$menuInner[0],\r\n menuFragment = document.createDocumentFragment(),\r\n emptyMenu = menuInner.firstChild.cloneNode(false),\r\n marginTop,\r\n marginBottom,\r\n elements = isVirtual === true ? that.selectpicker.view.visibleElements : that.selectpicker.current.elements,\r\n toSanitize = [];\r\n\r\n // replace the existing UL with an empty one - this is faster than $.empty()\r\n menuInner.replaceChild(emptyMenu, menuInner.firstChild);\r\n\r\n for (var i = 0, visibleElementsLen = elements.length; i < visibleElementsLen; i++) {\r\n var element = elements[i],\r\n elText,\r\n elementData;\r\n\r\n if (that.options.sanitize) {\r\n elText = element.lastChild;\r\n\r\n if (elText) {\r\n elementData = that.selectpicker.current.data[i + that.selectpicker.view.position0].data;\r\n\r\n if (elementData && elementData.content && !elementData.sanitized) {\r\n toSanitize.push(elText);\r\n elementData.sanitized = true;\r\n }\r\n }\r\n }\r\n\r\n menuFragment.appendChild(element);\r\n }\r\n\r\n if (that.options.sanitize && toSanitize.length) {\r\n sanitizeHtml(toSanitize, that.options.whiteList, that.options.sanitizeFn);\r\n }\r\n\r\n if (isVirtual === true) {\r\n marginTop = (that.selectpicker.view.position0 === 0 ? 0 : that.selectpicker.current.data[that.selectpicker.view.position0 - 1].position);\r\n marginBottom = (that.selectpicker.view.position1 > size - 1 ? 0 : that.selectpicker.current.data[size - 1].position - that.selectpicker.current.data[that.selectpicker.view.position1 - 1].position);\r\n\r\n menuInner.firstChild.style.marginTop = marginTop + 'px';\r\n menuInner.firstChild.style.marginBottom = marginBottom + 'px';\r\n }\r\n\r\n menuInner.firstChild.appendChild(menuFragment);\r\n }\r\n }\r\n\r\n that.prevActiveIndex = that.activeIndex;\r\n\r\n if (!that.options.liveSearch) {\r\n that.$menuInner.trigger('focus');\r\n } else if (isSearching && init) {\r\n var index = 0,\r\n newActive;\r\n\r\n if (!that.selectpicker.view.canHighlight[index]) {\r\n index = 1 + that.selectpicker.view.canHighlight.slice(1).indexOf(true);\r\n }\r\n\r\n newActive = that.selectpicker.view.visibleElements[index];\r\n\r\n if (that.selectpicker.view.currentActive) {\r\n that.selectpicker.view.currentActive.classList.remove('active');\r\n if (that.selectpicker.view.currentActive.firstChild) that.selectpicker.view.currentActive.firstChild.classList.remove('active');\r\n }\r\n\r\n if (newActive) {\r\n newActive.classList.add('active');\r\n if (newActive.firstChild) newActive.firstChild.classList.add('active');\r\n }\r\n\r\n that.activeIndex = that.selectpicker.current.map.originalIndex[index];\r\n }\r\n }\r\n\r\n $(window)\r\n .off('resize' + EVENT_KEY + '.' + this.selectId + '.createView')\r\n .on('resize' + EVENT_KEY + '.' + this.selectId + '.createView', function () {\r\n var isActive = that.$newElement.hasClass(classNames.SHOW);\r\n\r\n if (isActive) scroll(that.$menuInner[0].scrollTop);\r\n });\r\n },\r\n\r\n setPlaceholder: function () {\r\n var updateIndex = false;\r\n\r\n if (this.options.title && !this.multiple) {\r\n if (!this.selectpicker.view.titleOption) this.selectpicker.view.titleOption = document.createElement('option');\r\n\r\n // this option doesn't create a new
element, but does add a new option, so liIndex is decreased\r\n // since newIndex is recalculated on every refresh, liIndex needs to be decreased even if the titleOption is already appended\r\n updateIndex = true;\r\n\r\n var element = this.$element[0],\r\n isSelected = false,\r\n titleNotAppended = !this.selectpicker.view.titleOption.parentNode;\r\n\r\n if (titleNotAppended) {\r\n // Use native JS to prepend option (faster)\r\n this.selectpicker.view.titleOption.className = 'bs-title-option';\r\n this.selectpicker.view.titleOption.value = '';\r\n\r\n // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.\r\n // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,\r\n // if so, the select will have the data-selected attribute\r\n var $opt = $(element.options[element.selectedIndex]);\r\n isSelected = $opt.attr('selected') === undefined && this.$element.data('selected') === undefined;\r\n }\r\n\r\n if (titleNotAppended || this.selectpicker.view.titleOption.index !== 0) {\r\n element.insertBefore(this.selectpicker.view.titleOption, element.firstChild);\r\n }\r\n\r\n // Set selected *after* appending to select,\r\n // otherwise the option doesn't get selected in IE\r\n // set using selectedIndex, as setting the selected attr to true here doesn't work in IE11\r\n if (isSelected) element.selectedIndex = 0;\r\n }\r\n\r\n return updateIndex;\r\n },\r\n\r\n createLi: function () {\r\n var that = this,\r\n iconBase = that.options.iconBase,\r\n optionSelector = ':not([hidden]):not([data-hidden=\"true\"])',\r\n checkMark,\r\n mainElements = [],\r\n widestOption,\r\n widestOptionLength = 0,\r\n mainData = [],\r\n optID = 0,\r\n headerIndex = 0,\r\n liIndex = -1; // increment liIndex whenever a new
element is created to ensure newIndex is correct\r\n\r\n if (this.options.hideDisabled) optionSelector += ':not(:disabled)';\r\n\r\n if (that.options.showTick || that.multiple) {\r\n checkMark = elementTemplates.span.cloneNode(false);\r\n checkMark.className = iconBase + ' ' + that.options.tickIcon + ' check-mark';\r\n elementTemplates.a.appendChild(checkMark);\r\n }\r\n\r\n if (this.setPlaceholder()) liIndex--;\r\n\r\n var selectOptions = this.$element[0].options;\r\n\r\n for (var index = 0, len = selectOptions.length; index < len; index++) {\r\n var option = selectOptions[index];\r\n\r\n liIndex++;\r\n\r\n if (option.classList.contains('bs-title-option')) continue;\r\n\r\n var thisData = {\r\n content: option.getAttribute('data-content'),\r\n tokens: option.getAttribute('data-tokens'),\r\n subtext: option.getAttribute('data-subtext'),\r\n icon: option.getAttribute('data-icon'),\r\n hidden: option.getAttribute('data-hidden') === 'true',\r\n divider: option.getAttribute('data-divider') === 'true'\r\n };\r\n\r\n // Get the class and text for the option\r\n var optionClass = option.className || '',\r\n cssText = option.style.cssText,\r\n inline = cssText ? htmlEscape(cssText) : '',\r\n optionContent = thisData.content,\r\n text = option.textContent,\r\n parent = option.parentNode,\r\n next = option.nextElementSibling,\r\n previous = option.previousElementSibling,\r\n isOptgroup = parent.tagName === 'OPTGROUP',\r\n isOptgroupDisabled = isOptgroup && parent.disabled,\r\n isDisabled = option.disabled || isOptgroupDisabled,\r\n prevHiddenIndex,\r\n showDivider = previous && previous.tagName === 'OPTGROUP',\r\n textElement,\r\n labelElement,\r\n prevHidden;\r\n\r\n var parentData = {\r\n hidden: parent.getAttribute('data-hidden') === 'true'\r\n };\r\n\r\n if (\r\n (\r\n (thisData.hidden === true || option.hidden) ||\r\n (isOptgroup && (parentData.hidden === true || parent.hidden))\r\n ) ||\r\n (that.options.hideDisabled && (isDisabled || isOptgroupDisabled))\r\n ) {\r\n // set prevHiddenIndex - the index of the first hidden option in a group of hidden options\r\n // used to determine whether or not a divider should be placed after an optgroup if there are\r\n // hidden options between the optgroup and the first visible option\r\n prevHiddenIndex = option.prevHiddenIndex;\r\n if (next) next.prevHiddenIndex = (prevHiddenIndex !== undefined ? prevHiddenIndex : index);\r\n\r\n liIndex--;\r\n\r\n continue;\r\n } else {\r\n if (next && next.prevHiddenIndex !== undefined) next.prevHiddenIndex = undefined;\r\n }\r\n\r\n if (isOptgroup && thisData.divider !== true) {\r\n var optGroupClass = ' ' + parent.className || '',\r\n previousOption = option.previousElementSibling;\r\n\r\n prevHiddenIndex = option.prevHiddenIndex;\r\n\r\n // Get the first visible option before the first hidden option in the group.\r\n // Ensures a divider is shown if, for example, the first option in the optgroup is hidden.\r\n if (prevHiddenIndex !== undefined) {\r\n previousOption = selectOptions[prevHiddenIndex].previousElementSibling;\r\n }\r\n\r\n // if there is no previous option, this option is the first visible option in the optgroup\r\n if (!previousOption) {\r\n optID += 1;\r\n\r\n parentData.subtext = parent.getAttribute('data-subtext');\r\n parentData.icon = parent.getAttribute('data-icon');\r\n\r\n // Get the opt group label\r\n var label = parent.label,\r\n labelEscaped = htmlEscape(label),\r\n labelSubtext = parentData.subtext,\r\n labelIcon = parentData.icon;\r\n\r\n if (index !== 0 && mainElements.length > 0) { // Is it NOT the first option of the select && are there elements in the dropdown?\r\n liIndex++;\r\n mainElements.push(\r\n generateOption.li(\r\n false,\r\n classNames.DIVIDER,\r\n optID + 'div'\r\n )\r\n );\r\n mainData.push({\r\n type: 'divider',\r\n optID: optID\r\n });\r\n }\r\n liIndex++;\r\n\r\n labelElement = generateOption.label({\r\n labelEscaped: labelEscaped,\r\n labelSubtext: labelSubtext,\r\n labelIcon: labelIcon,\r\n iconBase: iconBase\r\n });\r\n\r\n mainElements.push(generateOption.li(labelElement, 'dropdown-header' + optGroupClass, optID));\r\n mainData.push({\r\n content: labelEscaped,\r\n subtext: labelSubtext,\r\n type: 'optgroup-label',\r\n optID: optID\r\n });\r\n\r\n headerIndex = liIndex - 1;\r\n }\r\n\r\n textElement = generateOption.text({\r\n text: text,\r\n optionContent: optionContent,\r\n optionSubtext: thisData.subtext,\r\n optionIcon: thisData.icon,\r\n iconBase: iconBase\r\n });\r\n\r\n mainElements.push(generateOption.li(generateOption.a(textElement, 'opt ' + optionClass + optGroupClass, inline), '', optID));\r\n mainData.push({\r\n content: optionContent || text,\r\n subtext: thisData.subtext,\r\n tokens: thisData.tokens,\r\n type: 'option',\r\n optID: optID,\r\n headerIndex: headerIndex,\r\n lastIndex: headerIndex + parent.querySelectorAll('option' + optionSelector).length,\r\n originalIndex: index,\r\n data: thisData\r\n });\r\n } else if (thisData.divider === true) {\r\n mainElements.push(generateOption.li(false, classNames.DIVIDER));\r\n mainData.push({\r\n type: 'divider',\r\n originalIndex: index,\r\n data: thisData\r\n });\r\n } else {\r\n if (that.options.hideDisabled) {\r\n if (showDivider) {\r\n var disabledOptions = previous.querySelectorAll('option:disabled');\r\n\r\n if (disabledOptions.length === previous.children.length) showDivider = false;\r\n } else {\r\n prevHiddenIndex = option.prevHiddenIndex;\r\n\r\n if (prevHiddenIndex !== undefined) {\r\n // select the element **before** the first hidden element in the group\r\n prevHidden = selectOptions[prevHiddenIndex].previousElementSibling;\r\n\r\n if (prevHidden && prevHidden.tagName === 'OPTGROUP' && !prevHidden.disabled) {\r\n var disabledOptions = prevHidden.querySelectorAll('option:disabled');\r\n\r\n if (disabledOptions.length < prevHidden.children.length) showDivider = true;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (showDivider && mainData.length && mainData[mainData.length - 1].type !== 'divider') {\r\n liIndex++;\r\n mainElements.push(\r\n generateOption.li(\r\n false,\r\n classNames.DIVIDER,\r\n optID + 'div'\r\n )\r\n );\r\n mainData.push({\r\n type: 'divider',\r\n optID: optID\r\n });\r\n }\r\n\r\n textElement = generateOption.text({\r\n text: text,\r\n optionContent: optionContent,\r\n optionSubtext: thisData.subtext,\r\n optionIcon: thisData.icon,\r\n iconBase: iconBase\r\n });\r\n\r\n mainElements.push(generateOption.li(generateOption.a(textElement, optionClass, inline)));\r\n mainData.push({\r\n content: optionContent || text,\r\n subtext: thisData.subtext,\r\n tokens: thisData.tokens,\r\n type: 'option',\r\n originalIndex: index,\r\n data: thisData\r\n });\r\n }\r\n\r\n that.selectpicker.main.map.newIndex[index] = liIndex;\r\n that.selectpicker.main.map.originalIndex[liIndex] = index;\r\n\r\n // get the most recent option info added to mainData\r\n var _mainDataLast = mainData[mainData.length - 1];\r\n\r\n _mainDataLast.disabled = isDisabled;\r\n\r\n var combinedLength = 0;\r\n\r\n // count the number of characters in the option - not perfect, but should work in most cases\r\n if (_mainDataLast.content) combinedLength += _mainDataLast.content.length;\r\n if (_mainDataLast.subtext) combinedLength += _mainDataLast.subtext.length;\r\n // if there is an icon, ensure this option's width is checked\r\n if (thisData.icon) combinedLength += 1;\r\n\r\n if (combinedLength > widestOptionLength) {\r\n widestOptionLength = combinedLength;\r\n\r\n // guess which option is the widest\r\n // use this when calculating menu width\r\n // not perfect, but it's fast, and the width will be updating accordingly when scrolling\r\n widestOption = mainElements[mainElements.length - 1];\r\n }\r\n }\r\n\r\n this.selectpicker.main.elements = mainElements;\r\n this.selectpicker.main.data = mainData;\r\n\r\n this.selectpicker.current = this.selectpicker.main;\r\n\r\n this.selectpicker.view.widestOption = widestOption;\r\n },\r\n\r\n findLis: function () {\r\n return this.$menuInner.find('.inner > li');\r\n },\r\n\r\n render: function () {\r\n // ensure titleOption is appended and selected (if necessary) before getting selectedOptions\r\n this.setPlaceholder();\r\n\r\n var that = this,\r\n selectedOptions = this.$element[0].selectedOptions,\r\n selectedCount = selectedOptions.length,\r\n button = this.$button[0],\r\n buttonInner = button.querySelector('.filter-option-inner-inner'),\r\n multipleSeparator = document.createTextNode(this.options.multipleSeparator),\r\n titleFragment = elementTemplates.fragment.cloneNode(false),\r\n showCount,\r\n countMax,\r\n hasContent = false;\r\n\r\n this.togglePlaceholder();\r\n\r\n this.tabIndex();\r\n\r\n if (this.options.selectedTextFormat === 'static') {\r\n titleFragment = generateOption.text({ text: this.options.title }, true);\r\n } else {\r\n showCount = this.multiple && this.options.selectedTextFormat.indexOf('count') !== -1 && selectedCount > 1;\r\n\r\n // determine if the number of selected options will be shown (showCount === true)\r\n if (showCount) {\r\n countMax = this.options.selectedTextFormat.split('>');\r\n showCount = (countMax.length > 1 && selectedCount > countMax[1]) || (countMax.length === 1 && selectedCount >= 2);\r\n }\r\n\r\n // only loop through all selected options if the count won't be shown\r\n if (showCount === false) {\r\n for (var selectedIndex = 0; selectedIndex < selectedCount; selectedIndex++) {\r\n if (selectedIndex < 50) {\r\n var option = selectedOptions[selectedIndex],\r\n titleOptions = {},\r\n thisData = {\r\n content: option.getAttribute('data-content'),\r\n subtext: option.getAttribute('data-subtext'),\r\n icon: option.getAttribute('data-icon')\r\n };\r\n\r\n if (this.multiple && selectedIndex > 0) {\r\n titleFragment.appendChild(multipleSeparator.cloneNode(false));\r\n }\r\n\r\n if (option.title) {\r\n titleOptions.text = option.title;\r\n } else if (thisData.content && that.options.showContent) {\r\n titleOptions.optionContent = thisData.content.toString();\r\n hasContent = true;\r\n } else {\r\n if (that.options.showIcon) {\r\n titleOptions.optionIcon = thisData.icon;\r\n titleOptions.iconBase = this.options.iconBase;\r\n }\r\n if (that.options.showSubtext && !that.multiple && thisData.subtext) titleOptions.optionSubtext = ' ' + thisData.subtext;\r\n titleOptions.text = option.textContent.trim();\r\n }\r\n\r\n titleFragment.appendChild(generateOption.text(titleOptions, true));\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n // add ellipsis\r\n if (selectedCount > 49) {\r\n titleFragment.appendChild(document.createTextNode('...'));\r\n }\r\n } else {\r\n var optionSelector = ':not([hidden]):not([data-hidden=\"true\"]):not([data-divider=\"true\"])';\r\n if (this.options.hideDisabled) optionSelector += ':not(:disabled)';\r\n\r\n // If this is a multiselect, and selectedTextFormat is count, then show 1 of 2 selected, etc.\r\n var totalCount = this.$element[0].querySelectorAll('select > option' + optionSelector + ', optgroup' + optionSelector + ' option' + optionSelector).length,\r\n tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedCount, totalCount) : this.options.countSelectedText;\r\n\r\n titleFragment = generateOption.text({\r\n text: tr8nText.replace('{0}', selectedCount.toString()).replace('{1}', totalCount.toString())\r\n }, true);\r\n }\r\n }\r\n\r\n if (this.options.title == undefined) {\r\n // use .attr to ensure undefined is returned if title attribute is not set\r\n this.options.title = this.$element.attr('title');\r\n }\r\n\r\n // If the select doesn't have a title, then use the default, or if nothing is set at all, use noneSelectedText\r\n if (!titleFragment.childNodes.length) {\r\n titleFragment = generateOption.text({\r\n text: typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText\r\n }, true);\r\n }\r\n\r\n // strip all HTML tags and trim the result, then unescape any escaped tags\r\n button.title = titleFragment.textContent.replace(/<[^>]*>?/g, '').trim();\r\n\r\n if (this.options.sanitize && hasContent) {\r\n sanitizeHtml([titleFragment], that.options.whiteList, that.options.sanitizeFn);\r\n }\r\n\r\n buttonInner.innerHTML = '';\r\n buttonInner.appendChild(titleFragment);\r\n\r\n if (version.major < 4 && this.$newElement[0].parentNode.classList.contains('input-group')) {\r\n var filterExpand = button.querySelector('.filter-expand'),\r\n clone = buttonInner.cloneNode(true);\r\n\r\n clone.className = 'filter-expand';\r\n\r\n if (filterExpand) {\r\n button.replaceChild(clone, filterExpand);\r\n } else {\r\n button.appendChild(clone);\r\n }\r\n }\r\n\r\n this.$element.trigger('rendered' + EVENT_KEY);\r\n },\r\n\r\n /**\r\n * @param [style]\r\n * @param [status]\r\n */\r\n setStyle: function (newStyle, status) {\r\n var button = this.$button[0],\r\n style = this.options.style.split(' '),\r\n buttonClass;\r\n\r\n if (this.$element.attr('class')) {\r\n this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\\[.*\\]/gi, ''));\r\n }\r\n\r\n if (version.major < 4) {\r\n this.$newElement[0].classList.add('bs3');\r\n }\r\n\r\n if (newStyle) {\r\n buttonClass = newStyle.split(' ');\r\n } else {\r\n buttonClass = style;\r\n }\r\n\r\n if (status == 'add') {\r\n button.classList.add.apply(button.classList, buttonClass);\r\n } else if (status == 'remove') {\r\n button.classList.remove.apply(button.classList, buttonClass);\r\n } else {\r\n button.classList.remove.apply(button.classList, style);\r\n button.classList.add.apply(button.classList, buttonClass);\r\n }\r\n },\r\n\r\n liHeight: function (refresh) {\r\n if (!refresh && (this.options.size === false || this.sizeInfo)) return;\r\n\r\n if (!this.sizeInfo) this.sizeInfo = {};\r\n\r\n var newElement = document.createElement('div'),\r\n menu = document.createElement('div'),\r\n menuInner = document.createElement('div'),\r\n menuInnerInner = document.createElement('ul'),\r\n divider = document.createElement('li'),\r\n dropdownHeader = document.createElement('li'),\r\n li = document.createElement('li'),\r\n a = document.createElement('a'),\r\n text = document.createElement('span'),\r\n header = this.options.header && this.$menu.find('.' + classNames.POPOVERHEADER).length > 0 ? this.$menu.find('.' + classNames.POPOVERHEADER)[0].cloneNode(true) : null,\r\n search = this.options.liveSearch ? document.createElement('div') : null,\r\n actions = this.options.actionsBox && this.multiple && this.$menu.find('.bs-actionsbox').length > 0 ? this.$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,\r\n doneButton = this.options.doneButton && this.multiple && this.$menu.find('.bs-donebutton').length > 0 ? this.$menu.find('.bs-donebutton')[0].cloneNode(true) : null,\r\n firstOption = this.$element.find('option')[0];\r\n\r\n this.sizeInfo.selectWidth = this.$newElement[0].offsetWidth;\r\n\r\n text.className = 'text';\r\n a.className = 'dropdown-item ' + (firstOption ? firstOption.className : '');\r\n newElement.className = this.$menu[0].parentNode.className + ' ' + classNames.SHOW;\r\n newElement.style.width = this.sizeInfo.selectWidth + 'px';\r\n if (this.options.width === 'auto') menu.style.minWidth = 0;\r\n menu.className = classNames.MENU + ' ' + classNames.SHOW;\r\n menuInner.className = 'inner ' + classNames.SHOW;\r\n menuInnerInner.className = classNames.MENU + ' inner ' + (version.major === '4' ? classNames.SHOW : '');\r\n divider.className = classNames.DIVIDER;\r\n dropdownHeader.className = 'dropdown-header';\r\n\r\n text.appendChild(document.createTextNode('\\u200b'));\r\n a.appendChild(text);\r\n li.appendChild(a);\r\n dropdownHeader.appendChild(text.cloneNode(true));\r\n\r\n if (this.selectpicker.view.widestOption) {\r\n menuInnerInner.appendChild(this.selectpicker.view.widestOption.cloneNode(true));\r\n }\r\n\r\n menuInnerInner.appendChild(li);\r\n menuInnerInner.appendChild(divider);\r\n menuInnerInner.appendChild(dropdownHeader);\r\n if (header) menu.appendChild(header);\r\n if (search) {\r\n var input = document.createElement('input');\r\n search.className = 'bs-searchbox';\r\n input.className = 'form-control';\r\n search.appendChild(input);\r\n menu.appendChild(search);\r\n }\r\n if (actions) menu.appendChild(actions);\r\n menuInner.appendChild(menuInnerInner);\r\n menu.appendChild(menuInner);\r\n if (doneButton) menu.appendChild(doneButton);\r\n newElement.appendChild(menu);\r\n\r\n document.body.appendChild(newElement);\r\n\r\n var liHeight = a.offsetHeight,\r\n dropdownHeaderHeight = dropdownHeader ? dropdownHeader.offsetHeight : 0,\r\n headerHeight = header ? header.offsetHeight : 0,\r\n searchHeight = search ? search.offsetHeight : 0,\r\n actionsHeight = actions ? actions.offsetHeight : 0,\r\n doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,\r\n dividerHeight = $(divider).outerHeight(true),\r\n // fall back to jQuery if getComputedStyle is not supported\r\n menuStyle = window.getComputedStyle ? window.getComputedStyle(menu) : false,\r\n menuWidth = menu.offsetWidth,\r\n $menu = menuStyle ? null : $(menu),\r\n menuPadding = {\r\n vert: toInteger(menuStyle ? menuStyle.paddingTop : $menu.css('paddingTop')) +\r\n toInteger(menuStyle ? menuStyle.paddingBottom : $menu.css('paddingBottom')) +\r\n toInteger(menuStyle ? menuStyle.borderTopWidth : $menu.css('borderTopWidth')) +\r\n toInteger(menuStyle ? menuStyle.borderBottomWidth : $menu.css('borderBottomWidth')),\r\n horiz: toInteger(menuStyle ? menuStyle.paddingLeft : $menu.css('paddingLeft')) +\r\n toInteger(menuStyle ? menuStyle.paddingRight : $menu.css('paddingRight')) +\r\n toInteger(menuStyle ? menuStyle.borderLeftWidth : $menu.css('borderLeftWidth')) +\r\n toInteger(menuStyle ? menuStyle.borderRightWidth : $menu.css('borderRightWidth'))\r\n },\r\n menuExtras = {\r\n vert: menuPadding.vert +\r\n toInteger(menuStyle ? menuStyle.marginTop : $menu.css('marginTop')) +\r\n toInteger(menuStyle ? menuStyle.marginBottom : $menu.css('marginBottom')) + 2,\r\n horiz: menuPadding.horiz +\r\n toInteger(menuStyle ? menuStyle.marginLeft : $menu.css('marginLeft')) +\r\n toInteger(menuStyle ? menuStyle.marginRight : $menu.css('marginRight')) + 2\r\n },\r\n scrollBarWidth;\r\n\r\n menuInner.style.overflowY = 'scroll';\r\n\r\n scrollBarWidth = menu.offsetWidth - menuWidth;\r\n\r\n document.body.removeChild(newElement);\r\n\r\n this.sizeInfo.liHeight = liHeight;\r\n this.sizeInfo.dropdownHeaderHeight = dropdownHeaderHeight;\r\n this.sizeInfo.headerHeight = headerHeight;\r\n this.sizeInfo.searchHeight = searchHeight;\r\n this.sizeInfo.actionsHeight = actionsHeight;\r\n this.sizeInfo.doneButtonHeight = doneButtonHeight;\r\n this.sizeInfo.dividerHeight = dividerHeight;\r\n this.sizeInfo.menuPadding = menuPadding;\r\n this.sizeInfo.menuExtras = menuExtras;\r\n this.sizeInfo.menuWidth = menuWidth;\r\n this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth;\r\n this.sizeInfo.scrollBarWidth = scrollBarWidth;\r\n this.sizeInfo.selectHeight = this.$newElement[0].offsetHeight;\r\n\r\n this.setPositionData();\r\n },\r\n\r\n getSelectPosition: function () {\r\n var that = this,\r\n $window = $(window),\r\n pos = that.$newElement.offset(),\r\n $container = $(that.options.container),\r\n containerPos;\r\n\r\n if (that.options.container && $container.length && !$container.is('body')) {\r\n containerPos = $container.offset();\r\n containerPos.top += parseInt($container.css('borderTopWidth'));\r\n containerPos.left += parseInt($container.css('borderLeftWidth'));\r\n } else {\r\n containerPos = { top: 0, left: 0 };\r\n }\r\n\r\n var winPad = that.options.windowPadding;\r\n\r\n this.sizeInfo.selectOffsetTop = pos.top - containerPos.top - $window.scrollTop();\r\n this.sizeInfo.selectOffsetBot = $window.height() - this.sizeInfo.selectOffsetTop - this.sizeInfo.selectHeight - containerPos.top - winPad[2];\r\n this.sizeInfo.selectOffsetLeft = pos.left - containerPos.left - $window.scrollLeft();\r\n this.sizeInfo.selectOffsetRight = $window.width() - this.sizeInfo.selectOffsetLeft - this.sizeInfo.selectWidth - containerPos.left - winPad[1];\r\n this.sizeInfo.selectOffsetTop -= winPad[0];\r\n this.sizeInfo.selectOffsetLeft -= winPad[3];\r\n },\r\n\r\n setMenuSize: function (isAuto) {\r\n this.getSelectPosition();\r\n\r\n var selectWidth = this.sizeInfo.selectWidth,\r\n liHeight = this.sizeInfo.liHeight,\r\n headerHeight = this.sizeInfo.headerHeight,\r\n searchHeight = this.sizeInfo.searchHeight,\r\n actionsHeight = this.sizeInfo.actionsHeight,\r\n doneButtonHeight = this.sizeInfo.doneButtonHeight,\r\n divHeight = this.sizeInfo.dividerHeight,\r\n menuPadding = this.sizeInfo.menuPadding,\r\n menuInnerHeight,\r\n menuHeight,\r\n divLength = 0,\r\n minHeight,\r\n _minHeight,\r\n maxHeight,\r\n menuInnerMinHeight,\r\n estimate;\r\n\r\n if (this.options.dropupAuto) {\r\n // Get the estimated height of the menu without scrollbars.\r\n // This is useful for smaller menus, where there might be plenty of room\r\n // below the button without setting dropup, but we can't know\r\n // the exact height of the menu until createView is called later\r\n estimate = liHeight * this.selectpicker.current.elements.length + menuPadding.vert;\r\n this.$newElement.toggleClass(classNames.DROPUP, this.sizeInfo.selectOffsetTop - this.sizeInfo.selectOffsetBot > this.sizeInfo.menuExtras.vert && estimate + this.sizeInfo.menuExtras.vert + 50 > this.sizeInfo.selectOffsetBot);\r\n }\r\n\r\n if (this.options.size === 'auto') {\r\n _minHeight = this.selectpicker.current.elements.length > 3 ? this.sizeInfo.liHeight * 3 + this.sizeInfo.menuExtras.vert - 2 : 0;\r\n menuHeight = this.sizeInfo.selectOffsetBot - this.sizeInfo.menuExtras.vert;\r\n minHeight = _minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;\r\n menuInnerMinHeight = Math.max(_minHeight - menuPadding.vert, 0);\r\n\r\n if (this.$newElement.hasClass(classNames.DROPUP)) {\r\n menuHeight = this.sizeInfo.selectOffsetTop - this.sizeInfo.menuExtras.vert;\r\n }\r\n\r\n maxHeight = menuHeight;\r\n menuInnerHeight = menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert;\r\n } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {\r\n for (var i = 0; i < this.options.size; i++) {\r\n if (this.selectpicker.current.data[i].type === 'divider') divLength++;\r\n }\r\n\r\n menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert;\r\n menuInnerHeight = menuHeight - menuPadding.vert;\r\n maxHeight = menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;\r\n minHeight = menuInnerMinHeight = '';\r\n }\r\n\r\n if (this.options.dropdownAlignRight === 'auto') {\r\n this.$menu.toggleClass(classNames.MENURIGHT, this.sizeInfo.selectOffsetLeft > this.sizeInfo.selectOffsetRight && this.sizeInfo.selectOffsetRight < (this.sizeInfo.totalMenuWidth - selectWidth));\r\n }\r\n\r\n this.$menu.css({\r\n 'max-height': maxHeight + 'px',\r\n 'overflow': 'hidden',\r\n 'min-height': minHeight + 'px'\r\n });\r\n\r\n this.$menuInner.css({\r\n 'max-height': menuInnerHeight + 'px',\r\n 'overflow-y': 'auto',\r\n 'min-height': menuInnerMinHeight + 'px'\r\n });\r\n\r\n // ensure menuInnerHeight is always a positive number to prevent issues calculating chunkSize in createView\r\n this.sizeInfo.menuInnerHeight = Math.max(menuInnerHeight, 1);\r\n\r\n if (this.selectpicker.current.data.length && this.selectpicker.current.data[this.selectpicker.current.data.length - 1].position > this.sizeInfo.menuInnerHeight) {\r\n this.sizeInfo.hasScrollBar = true;\r\n this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth + this.sizeInfo.scrollBarWidth;\r\n\r\n this.$menu.css('min-width', this.sizeInfo.totalMenuWidth);\r\n }\r\n\r\n if (this.dropdown && this.dropdown._popper) this.dropdown._popper.update();\r\n },\r\n\r\n setSize: function (refresh) {\r\n this.liHeight(refresh);\r\n\r\n if (this.options.header) this.$menu.css('padding-top', 0);\r\n if (this.options.size === false) return;\r\n\r\n var that = this,\r\n $window = $(window),\r\n selectedIndex,\r\n offset = 0;\r\n\r\n this.setMenuSize();\r\n\r\n if (this.options.liveSearch) {\r\n this.$searchbox\r\n .off('input.setMenuSize propertychange.setMenuSize')\r\n .on('input.setMenuSize propertychange.setMenuSize', function () {\r\n return that.setMenuSize();\r\n });\r\n }\r\n\r\n if (this.options.size === 'auto') {\r\n $window\r\n .off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize')\r\n .on('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize', function () {\r\n return that.setMenuSize();\r\n });\r\n } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {\r\n $window.off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize');\r\n }\r\n\r\n if (refresh) {\r\n offset = this.$menuInner[0].scrollTop;\r\n } else if (!that.multiple) {\r\n selectedIndex = that.selectpicker.main.map.newIndex[that.$element[0].selectedIndex];\r\n\r\n if (typeof selectedIndex === 'number' && that.options.size !== false) {\r\n offset = that.sizeInfo.liHeight * selectedIndex;\r\n offset = offset - (that.sizeInfo.menuInnerHeight / 2) + (that.sizeInfo.liHeight / 2);\r\n }\r\n }\r\n\r\n that.createView(false, offset);\r\n },\r\n\r\n setWidth: function () {\r\n var that = this;\r\n\r\n if (this.options.width === 'auto') {\r\n requestAnimationFrame(function () {\r\n that.$menu.css('min-width', '0');\r\n\r\n that.$element.on('loaded' + EVENT_KEY, function () {\r\n that.liHeight();\r\n that.setMenuSize();\r\n\r\n // Get correct width if element is hidden\r\n var $selectClone = that.$newElement.clone().appendTo('body'),\r\n btnWidth = $selectClone.css('width', 'auto').children('button').outerWidth();\r\n\r\n $selectClone.remove();\r\n\r\n // Set width to whatever's larger, button title or longest option\r\n that.sizeInfo.selectWidth = Math.max(that.sizeInfo.totalMenuWidth, btnWidth);\r\n that.$newElement.css('width', that.sizeInfo.selectWidth + 'px');\r\n });\r\n });\r\n } else if (this.options.width === 'fit') {\r\n // Remove inline min-width so width can be changed from 'auto'\r\n this.$menu.css('min-width', '');\r\n this.$newElement.css('width', '').addClass('fit-width');\r\n } else if (this.options.width) {\r\n // Remove inline min-width so width can be changed from 'auto'\r\n this.$menu.css('min-width', '');\r\n this.$newElement.css('width', this.options.width);\r\n } else {\r\n // Remove inline min-width/width so width can be changed\r\n this.$menu.css('min-width', '');\r\n this.$newElement.css('width', '');\r\n }\r\n // Remove fit-width class if width is changed programmatically\r\n if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {\r\n this.$newElement[0].classList.remove('fit-width');\r\n }\r\n },\r\n\r\n selectPosition: function () {\r\n this.$bsContainer = $('');\r\n\r\n var that = this,\r\n $container = $(this.options.container),\r\n pos,\r\n containerPos,\r\n actualHeight,\r\n getPlacement = function ($element) {\r\n var containerPosition = {},\r\n // fall back to dropdown's default display setting if display is not manually set\r\n display = that.options.display || (\r\n // Bootstrap 3 doesn't have $.fn.dropdown.Constructor.Default\r\n $.fn.dropdown.Constructor.Default ? $.fn.dropdown.Constructor.Default.display\r\n : false\r\n );\r\n\r\n that.$bsContainer.addClass($element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass(classNames.DROPUP, $element.hasClass(classNames.DROPUP));\r\n pos = $element.offset();\r\n\r\n if (!$container.is('body')) {\r\n containerPos = $container.offset();\r\n containerPos.top += parseInt($container.css('borderTopWidth')) - $container.scrollTop();\r\n containerPos.left += parseInt($container.css('borderLeftWidth')) - $container.scrollLeft();\r\n } else {\r\n containerPos = { top: 0, left: 0 };\r\n }\r\n\r\n actualHeight = $element.hasClass(classNames.DROPUP) ? 0 : $element[0].offsetHeight;\r\n\r\n // Bootstrap 4+ uses Popper for menu positioning\r\n if (version.major < 4 || display === 'static') {\r\n containerPosition.top = pos.top - containerPos.top + actualHeight;\r\n containerPosition.left = pos.left - containerPos.left;\r\n }\r\n\r\n containerPosition.width = $element[0].offsetWidth;\r\n\r\n that.$bsContainer.css(containerPosition);\r\n };\r\n\r\n this.$button.on('click.bs.dropdown.data-api', function () {\r\n if (that.isDisabled()) {\r\n return;\r\n }\r\n\r\n getPlacement(that.$newElement);\r\n\r\n that.$bsContainer\r\n .appendTo(that.options.container)\r\n .toggleClass(classNames.SHOW, !that.$button.hasClass(classNames.SHOW))\r\n .append(that.$menu);\r\n });\r\n\r\n $(window)\r\n .off('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId)\r\n .on('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId, function () {\r\n var isActive = that.$newElement.hasClass(classNames.SHOW);\r\n\r\n if (isActive) getPlacement(that.$newElement);\r\n });\r\n\r\n this.$element.on('hide' + EVENT_KEY, function () {\r\n that.$menu.data('height', that.$menu.height());\r\n that.$bsContainer.detach();\r\n });\r\n },\r\n\r\n setOptionStatus: function () {\r\n var that = this,\r\n selectOptions = this.$element[0].options;\r\n\r\n that.noScroll = false;\r\n\r\n if (that.selectpicker.view.visibleElements && that.selectpicker.view.visibleElements.length) {\r\n for (var i = 0; i < that.selectpicker.view.visibleElements.length; i++) {\r\n var index = that.selectpicker.current.map.originalIndex[i + that.selectpicker.view.position0], // faster than $(li).data('originalIndex')\r\n option = selectOptions[index];\r\n\r\n if (option) {\r\n var liIndex = this.selectpicker.main.map.newIndex[index],\r\n li = this.selectpicker.main.elements[liIndex];\r\n\r\n that.setDisabled(\r\n index,\r\n option.disabled || (option.parentNode.tagName === 'OPTGROUP' && option.parentNode.disabled),\r\n liIndex,\r\n li\r\n );\r\n\r\n that.setSelected(\r\n index,\r\n option.selected,\r\n liIndex,\r\n li\r\n );\r\n }\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * @param {number} index - the index of the option that is being changed\r\n * @param {boolean} selected - true if the option is being selected, false if being deselected\r\n */\r\n setSelected: function (index, selected, liIndex, li) {\r\n var activeIndexIsSet = this.activeIndex !== undefined,\r\n thisIsActive = this.activeIndex === index,\r\n prevActiveIndex,\r\n prevActive,\r\n a,\r\n // if current option is already active\r\n // OR\r\n // if the current option is being selected, it's NOT multiple, and\r\n // activeIndex is undefined:\r\n // - when the menu is first being opened, OR\r\n // - after a search has been performed, OR\r\n // - 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)\r\n keepActive = thisIsActive || (selected && !this.multiple && !activeIndexIsSet);\r\n\r\n if (!liIndex) liIndex = this.selectpicker.main.map.newIndex[index];\r\n if (!li) li = this.selectpicker.main.elements[liIndex];\r\n\r\n a = li.firstChild;\r\n\r\n if (selected) {\r\n this.selectedIndex = index;\r\n }\r\n\r\n li.classList.toggle('selected', selected);\r\n li.classList.toggle('active', keepActive);\r\n\r\n if (keepActive) {\r\n this.selectpicker.view.currentActive = li;\r\n this.activeIndex = index;\r\n }\r\n\r\n if (a) {\r\n a.classList.toggle('selected', selected);\r\n a.classList.toggle('active', keepActive);\r\n a.setAttribute('aria-selected', selected);\r\n }\r\n\r\n if (!keepActive) {\r\n if (!activeIndexIsSet && selected && this.prevActiveIndex !== undefined) {\r\n prevActiveIndex = this.selectpicker.main.map.newIndex[this.prevActiveIndex];\r\n prevActive = this.selectpicker.main.elements[prevActiveIndex];\r\n\r\n prevActive.classList.remove('active');\r\n if (prevActive.firstChild) {\r\n prevActive.firstChild.classList.remove('active');\r\n }\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * @param {number} index - the index of the option that is being disabled\r\n * @param {boolean} disabled - true if the option is being disabled, false if being enabled\r\n */\r\n setDisabled: function (index, disabled, liIndex, li) {\r\n var a;\r\n\r\n if (!liIndex) liIndex = this.selectpicker.main.map.newIndex[index];\r\n if (!li) li = this.selectpicker.main.elements[liIndex];\r\n\r\n a = li.firstChild;\r\n\r\n li.classList.toggle(classNames.DISABLED, disabled);\r\n\r\n if (a) {\r\n if (version.major === '4') a.classList.toggle(classNames.DISABLED, disabled);\r\n\r\n a.setAttribute('aria-disabled', disabled);\r\n\r\n if (disabled) {\r\n a.setAttribute('tabindex', -1);\r\n } else {\r\n a.setAttribute('tabindex', 0);\r\n }\r\n }\r\n },\r\n\r\n isDisabled: function () {\r\n return this.$element[0].disabled;\r\n },\r\n\r\n checkDisabled: function () {\r\n var that = this;\r\n\r\n if (this.isDisabled()) {\r\n this.$newElement[0].classList.add(classNames.DISABLED);\r\n this.$button.addClass(classNames.DISABLED).attr('tabindex', -1).attr('aria-disabled', true);\r\n } else {\r\n if (this.$button[0].classList.contains(classNames.DISABLED)) {\r\n this.$newElement[0].classList.remove(classNames.DISABLED);\r\n this.$button.removeClass(classNames.DISABLED).attr('aria-disabled', false);\r\n }\r\n\r\n if (this.$button.attr('tabindex') == -1 && !this.$element.data('tabindex')) {\r\n this.$button.removeAttr('tabindex');\r\n }\r\n }\r\n\r\n this.$button.on('click', function () {\r\n return !that.isDisabled();\r\n });\r\n },\r\n\r\n togglePlaceholder: function () {\r\n // much faster than calling $.val()\r\n var element = this.$element[0],\r\n selectedIndex = element.selectedIndex,\r\n nothingSelected = selectedIndex === -1;\r\n\r\n if (!nothingSelected && !element.options[selectedIndex].value) nothingSelected = true;\r\n\r\n this.$button.toggleClass('bs-placeholder', nothingSelected);\r\n },\r\n\r\n tabIndex: function () {\r\n if (this.$element.data('tabindex') !== this.$element.attr('tabindex') &&\r\n (this.$element.attr('tabindex') !== -98 && this.$element.attr('tabindex') !== '-98')) {\r\n this.$element.data('tabindex', this.$element.attr('tabindex'));\r\n this.$button.attr('tabindex', this.$element.data('tabindex'));\r\n }\r\n\r\n this.$element.attr('tabindex', -98);\r\n },\r\n\r\n clickListener: function () {\r\n var that = this,\r\n $document = $(document);\r\n\r\n $document.data('spaceSelect', false);\r\n\r\n this.$button.on('keyup', function (e) {\r\n if (/(32)/.test(e.keyCode.toString(10)) && $document.data('spaceSelect')) {\r\n e.preventDefault();\r\n $document.data('spaceSelect', false);\r\n }\r\n });\r\n\r\n this.$newElement.on('show.bs.dropdown', function () {\r\n if (version.major > 3 && !that.dropdown) {\r\n that.dropdown = that.$button.data('bs.dropdown');\r\n that.dropdown._menu = that.$menu[0];\r\n }\r\n });\r\n\r\n this.$button.on('click.bs.dropdown.data-api', function () {\r\n if (!that.$newElement.hasClass(classNames.SHOW)) {\r\n that.setSize();\r\n }\r\n });\r\n\r\n function setFocus () {\r\n if (that.options.liveSearch) {\r\n that.$searchbox.trigger('focus');\r\n } else {\r\n that.$menuInner.trigger('focus');\r\n }\r\n }\r\n\r\n function checkPopperExists () {\r\n if (that.dropdown && that.dropdown._popper && that.dropdown._popper.state.isCreated) {\r\n setFocus();\r\n } else {\r\n requestAnimationFrame(checkPopperExists);\r\n }\r\n }\r\n\r\n this.$element.on('shown' + EVENT_KEY, function () {\r\n if (that.$menuInner[0].scrollTop !== that.selectpicker.view.scrollTop) {\r\n that.$menuInner[0].scrollTop = that.selectpicker.view.scrollTop;\r\n }\r\n\r\n if (version.major > 3) {\r\n requestAnimationFrame(checkPopperExists);\r\n } else {\r\n setFocus();\r\n }\r\n });\r\n\r\n this.$menuInner.on('click', 'li a', function (e, retainActive) {\r\n var $this = $(this),\r\n position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,\r\n clickedIndex = that.selectpicker.current.map.originalIndex[$this.parent().index() + position0],\r\n prevValue = getSelectValues(that.$element[0]),\r\n prevIndex = that.$element.prop('selectedIndex'),\r\n triggerChange = true;\r\n\r\n // Don't close on multi choice menu\r\n if (that.multiple && that.options.maxOptions !== 1) {\r\n e.stopPropagation();\r\n }\r\n\r\n e.preventDefault();\r\n\r\n // Don't run if the select is disabled\r\n if (!that.isDisabled() && !$this.parent().hasClass(classNames.DISABLED)) {\r\n var $options = that.$element.find('option'),\r\n $option = $options.eq(clickedIndex),\r\n state = $option.prop('selected'),\r\n $optgroup = $option.parent('optgroup'),\r\n $optgroupOptions = $optgroup.find('option'),\r\n maxOptions = that.options.maxOptions,\r\n maxOptionsGrp = $optgroup.data('maxOptions') || false;\r\n\r\n if (clickedIndex === that.activeIndex) retainActive = true;\r\n\r\n if (!retainActive) {\r\n that.prevActiveIndex = that.activeIndex;\r\n that.activeIndex = undefined;\r\n }\r\n\r\n if (!that.multiple) { // Deselect all others if not multi select box\r\n $options.prop('selected', false);\r\n $option.prop('selected', true);\r\n that.setSelected(clickedIndex, true);\r\n } else { // Toggle the one we have chosen if we are multi select.\r\n $option.prop('selected', !state);\r\n\r\n that.setSelected(clickedIndex, !state);\r\n $this.trigger('blur');\r\n\r\n if (maxOptions !== false || maxOptionsGrp !== false) {\r\n var maxReached = maxOptions < $options.filter(':selected').length,\r\n maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length;\r\n\r\n if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {\r\n if (maxOptions && maxOptions == 1) {\r\n $options.prop('selected', false);\r\n $option.prop('selected', true);\r\n\r\n for (var i = 0; i < $options.length; i++) {\r\n that.setSelected(i, false);\r\n }\r\n\r\n that.setSelected(clickedIndex, true);\r\n } else if (maxOptionsGrp && maxOptionsGrp == 1) {\r\n $optgroup.find('option:selected').prop('selected', false);\r\n $option.prop('selected', true);\r\n\r\n for (var i = 0; i < $optgroupOptions.length; i++) {\r\n var option = $optgroupOptions[i];\r\n that.setSelected($options.index(option), false);\r\n }\r\n\r\n that.setSelected(clickedIndex, true);\r\n } else {\r\n var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText,\r\n maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText,\r\n maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),\r\n maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),\r\n $notify = $('');\r\n // If {var} is set in array, replace it\r\n /** @deprecated */\r\n if (maxOptionsArr[2]) {\r\n maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);\r\n maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);\r\n }\r\n\r\n $option.prop('selected', false);\r\n\r\n that.$menu.append($notify);\r\n\r\n if (maxOptions && maxReached) {\r\n $notify.append($('