/*! * JavaScript Custom Forms : Select Module * * Copyright 2014-2015 PSD2HTML - http://psd2html.com/jcf * Released under the MIT license (LICENSE.txt) * * Version: 1.2.0 */ jcf.addModule(function($, window) { 'use strict'; var module = { name: 'Select', selector: 'select', options: { element: null, multipleCompactStyle: false }, plugins: { ListBox: ListBox, ComboBox: ComboBox, SelectList: SelectList }, matchElement: function(element) { return element.is('select'); }, init: function() { this.element = $(this.options.element); this.createInstance(); }, isListBox: function() { return this.element.is('[size]:not([jcf-size]), [multiple]'); }, createInstance: function() { if (this.instance) { this.instance.destroy(); } if (this.isListBox() && !this.options.multipleCompactStyle) { this.instance = new ListBox(this.options); } else { this.instance = new ComboBox(this.options); } }, refresh: function() { var typeMismatch = (this.isListBox() && this.instance instanceof ComboBox) || (!this.isListBox() && this.instance instanceof ListBox); if (typeMismatch) { this.createInstance(); } else { this.instance.refresh(); } }, destroy: function() { this.instance.destroy(); } }; // combobox module function ComboBox(options) { this.options = $.extend({ wrapNative: true, wrapNativeOnMobile: true, fakeDropInBody: true, useCustomScroll: true, flipDropToFit: true, maxVisibleItems: 10, fakeAreaStructure: '', fakeDropStructure: '
', optionClassPrefix: 'jcf-option-', selectClassPrefix: 'jcf-select-', dropContentSelector: '.jcf-select-drop-content', selectTextSelector: '.jcf-select-text', dropActiveClass: 'jcf-drop-active', flipDropClass: 'jcf-drop-flipped' }, options); this.init(); } $.extend(ComboBox.prototype, { init: function() { this.initStructure(); this.bindHandlers(); this.attachEvents(); this.refresh(); }, initStructure: function() { // prepare structure this.win = $(window); this.doc = $(document); this.realElement = $(this.options.element); this.fakeElement = $(this.options.fakeAreaStructure).insertAfter(this.realElement); this.selectTextContainer = this.fakeElement.find(this.options.selectTextSelector); this.selectText = $('').appendTo(this.selectTextContainer); makeUnselectable(this.fakeElement); // copy classes from original select this.fakeElement.addClass(getPrefixedClasses(this.realElement.prop('className'), this.options.selectClassPrefix)); // handle compact multiple style if (this.realElement.prop('multiple')) { this.fakeElement.addClass('jcf-compact-multiple'); } // detect device type and dropdown behavior if (this.options.isMobileDevice && this.options.wrapNativeOnMobile && !this.options.wrapNative) { this.options.wrapNative = true; } if (this.options.wrapNative) { // wrap native select inside fake block this.realElement.prependTo(this.fakeElement).css({ position: 'absolute', height: '100%', width: '100%' }).addClass(this.options.resetAppearanceClass); } else { // just hide native select this.realElement.addClass(this.options.hiddenClass); this.fakeElement.attr('title', this.realElement.attr('title')); this.fakeDropTarget = this.options.fakeDropInBody ? $('body') : this.fakeElement; } }, attachEvents: function() { // delayed refresh handler var self = this; this.delayedRefresh = function() { setTimeout(function() { self.refresh(); if (self.list) { self.list.refresh(); self.list.scrollToActiveOption(); } }, 1); }; // native dropdown event handlers if (this.options.wrapNative) { this.realElement.on({ focus: this.onFocus, change: this.onChange, click: this.onChange, keydown: this.onChange }); } else { // custom dropdown event handlers this.realElement.on({ focus: this.onFocus, change: this.onChange, keydown: this.onKeyDown }); this.fakeElement.on({ 'jcf-pointerdown': this.onSelectAreaPress }); } }, onKeyDown: function(e) { if (e.which === 13) { this.toggleDropdown(); } else if (this.dropActive) { this.delayedRefresh(); } }, onChange: function() { this.refresh(); }, onFocus: function() { if (!this.pressedFlag || !this.focusedFlag) { this.fakeElement.addClass(this.options.focusClass); this.realElement.on('blur', this.onBlur); this.toggleListMode(true); this.focusedFlag = true; } }, onBlur: function() { if (!this.pressedFlag) { this.fakeElement.removeClass(this.options.focusClass); this.realElement.off('blur', this.onBlur); this.toggleListMode(false); this.focusedFlag = false; } }, onResize: function() { if (this.dropActive) { this.hideDropdown(); } }, onSelectDropPress: function() { this.pressedFlag = true; }, onSelectDropRelease: function(e, pointerEvent) { this.pressedFlag = false; if (pointerEvent.pointerType === 'mouse') { this.realElement.focus(); } }, onSelectAreaPress: function(e) { // skip click if drop inside fake element or real select is disabled var dropClickedInsideFakeElement = !this.options.fakeDropInBody && $(e.target).closest(this.dropdown).length; if (dropClickedInsideFakeElement || e.button > 1 || this.realElement.is(':disabled')) { return; } // toggle dropdown visibility this.selectOpenedByEvent = e.pointerType; this.toggleDropdown(); // misc handlers if (!this.focusedFlag) { if (e.pointerType === 'mouse') { this.realElement.focus(); } else { this.onFocus(e); } } this.pressedFlag = true; this.fakeElement.addClass(this.options.pressedClass); this.doc.on('jcf-pointerup', this.onSelectAreaRelease); }, onSelectAreaRelease: function(e) { if (this.focusedFlag && e.pointerType === 'mouse') { this.realElement.focus(); } this.pressedFlag = false; this.fakeElement.removeClass(this.options.pressedClass); this.doc.off('jcf-pointerup', this.onSelectAreaRelease); }, onOutsideClick: function(e) { var target = $(e.target), clickedInsideSelect = target.closest(this.fakeElement).length || target.closest(this.dropdown).length; if (!clickedInsideSelect) { this.hideDropdown(); } }, onSelect: function() { this.refresh(); if (this.realElement.prop('multiple')) { this.repositionDropdown(); } else { this.hideDropdown(); } this.fireNativeEvent(this.realElement, 'change'); }, toggleListMode: function(state) { if (!this.options.wrapNative) { if (state) { // temporary change select to list to avoid appearing of native dropdown this.realElement.attr({ size: 4, 'jcf-size': '' }); } else { // restore select from list mode to dropdown select if (!this.options.wrapNative) { this.realElement.removeAttr('size jcf-size'); } } } }, createDropdown: function() { // destroy previous dropdown if needed if (this.dropdown) { this.list.destroy(); this.dropdown.remove(); } // create new drop container this.dropdown = $(this.options.fakeDropStructure).appendTo(this.fakeDropTarget); this.dropdown.addClass(getPrefixedClasses(this.realElement.prop('className'), this.options.selectClassPrefix)); makeUnselectable(this.dropdown); // handle compact multiple style if (this.realElement.prop('multiple')) { this.dropdown.addClass('jcf-compact-multiple'); } // set initial styles for dropdown in body if (this.options.fakeDropInBody) { this.dropdown.css({ position: 'absolute', top: -9999 }); } // create new select list instance this.list = new SelectList({ useHoverClass: true, handleResize: false, alwaysPreventMouseWheel: true, maxVisibleItems: this.options.maxVisibleItems, useCustomScroll: this.options.useCustomScroll, holder: this.dropdown.find(this.options.dropContentSelector), multipleSelectWithoutKey: this.realElement.prop('multiple'), element: this.realElement }); $(this.list).on({ select: this.onSelect, press: this.onSelectDropPress, release: this.onSelectDropRelease }); }, repositionDropdown: function() { var selectOffset = this.fakeElement.offset(), selectWidth = this.fakeElement.outerWidth(), selectHeight = this.fakeElement.outerHeight(), dropHeight = this.dropdown.css('width', selectWidth).outerHeight(), winScrollTop = this.win.scrollTop(), winHeight = this.win.height(), calcTop, calcLeft, bodyOffset, needFlipDrop = false; // check flip drop position if (selectOffset.top + selectHeight + dropHeight > winScrollTop + winHeight && selectOffset.top - dropHeight > winScrollTop) { needFlipDrop = true; } if (this.options.fakeDropInBody) { bodyOffset = this.fakeDropTarget.css('position') !== 'static' ? this.fakeDropTarget.offset().top : 0; if (this.options.flipDropToFit && needFlipDrop) { // calculate flipped dropdown position calcLeft = selectOffset.left; calcTop = selectOffset.top - dropHeight - bodyOffset; } else { // calculate default drop position calcLeft = selectOffset.left; calcTop = selectOffset.top + selectHeight - bodyOffset; } // update drop styles this.dropdown.css({ width: selectWidth, left: calcLeft, top: calcTop }); } // refresh flipped class this.dropdown.add(this.fakeElement).toggleClass(this.options.flipDropClass, this.options.flipDropToFit && needFlipDrop); }, showDropdown: function() { // do not show empty custom dropdown if (!this.realElement.prop('options').length) { return; } // create options list if not created if (!this.dropdown) { this.createDropdown(); } // show dropdown this.dropActive = true; this.dropdown.appendTo(this.fakeDropTarget); this.fakeElement.addClass(this.options.dropActiveClass); this.refreshSelectedText(); this.repositionDropdown(); this.list.setScrollTop(this.savedScrollTop); this.list.refresh(); // add temporary event handlers this.win.on('resize', this.onResize); this.doc.on('jcf-pointerdown', this.onOutsideClick); }, hideDropdown: function() { if (this.dropdown) { this.savedScrollTop = this.list.getScrollTop(); this.fakeElement.removeClass(this.options.dropActiveClass + ' ' + this.options.flipDropClass); this.dropdown.removeClass(this.options.flipDropClass).detach(); this.doc.off('jcf-pointerdown', this.onOutsideClick); this.win.off('resize', this.onResize); this.dropActive = false; if (this.selectOpenedByEvent === 'touch') { this.onBlur(); } } }, toggleDropdown: function() { if (this.dropActive) { this.hideDropdown(); } else { this.showDropdown(); } }, refreshSelectedText: function() { // redraw selected area var selectedIndex = this.realElement.prop('selectedIndex'), selectedOption = this.realElement.prop('options')[selectedIndex], selectedOptionImage = selectedOption ? selectedOption.getAttribute('data-image') : null, selectedOptionText = '', selectedOptionClasses, self = this; if (this.realElement.prop('multiple')) { $.each(this.realElement.prop('options'), function(index, option) { if (option.selected) { selectedOptionText += (selectedOptionText ? ', ' : '') + option.innerHTML; } }); if (!selectedOptionText) { selectedOptionText = self.realElement.attr('placeholder') || ''; } this.selectText.removeAttr('class').html(selectedOptionText); } else if (!selectedOption) { if (this.selectImage) { this.selectImage.hide(); } this.selectText.removeAttr('class').empty(); } else if (this.currentSelectedText !== selectedOption.innerHTML || this.currentSelectedImage !== selectedOptionImage) { selectedOptionClasses = getPrefixedClasses(selectedOption.className, this.options.optionClassPrefix); this.selectText.attr('class', selectedOptionClasses).html(selectedOption.innerHTML); if (selectedOptionImage) { if (!this.selectImage) { this.selectImage = $('').prependTo(this.selectTextContainer).hide(); } this.selectImage.attr('src', selectedOptionImage).show(); } else if (this.selectImage) { this.selectImage.hide(); } this.currentSelectedText = selectedOption.innerHTML; this.currentSelectedImage = selectedOptionImage; } }, refresh: function() { // refresh fake select visibility if (this.realElement.prop('style').display === 'none') { this.fakeElement.hide(); } else { this.fakeElement.show(); } // refresh selected text this.refreshSelectedText(); // handle disabled state this.fakeElement.toggleClass(this.options.disabledClass, this.realElement.is(':disabled')); }, destroy: function() { // restore structure if (this.options.wrapNative) { this.realElement.insertBefore(this.fakeElement).css({ position: '', height: '', width: '' }).removeClass(this.options.resetAppearanceClass); } else { this.realElement.removeClass(this.options.hiddenClass); if (this.realElement.is('[jcf-size]')) { this.realElement.removeAttr('size jcf-size'); } } // removing element will also remove its event handlers this.fakeElement.remove(); // remove other event handlers this.doc.off('jcf-pointerup', this.onSelectAreaRelease); this.realElement.off({ focus: this.onFocus }); } }); // listbox module function ListBox(options) { this.options = $.extend({ wrapNative: true, useCustomScroll: true, fakeStructure: '', selectClassPrefix: 'jcf-select-', listHolder: '.jcf-list-wrapper' }, options); this.init(); } $.extend(ListBox.prototype, { init: function() { this.bindHandlers(); this.initStructure(); this.attachEvents(); }, initStructure: function() { this.realElement = $(this.options.element); this.fakeElement = $(this.options.fakeStructure).insertAfter(this.realElement); this.listHolder = this.fakeElement.find(this.options.listHolder); makeUnselectable(this.fakeElement); // copy classes from original select this.fakeElement.addClass(getPrefixedClasses(this.realElement.prop('className'), this.options.selectClassPrefix)); this.realElement.addClass(this.options.hiddenClass); this.list = new SelectList({ useCustomScroll: this.options.useCustomScroll, holder: this.listHolder, selectOnClick: false, element: this.realElement }); }, attachEvents: function() { // delayed refresh handler var self = this; this.delayedRefresh = function(e) { if (e && e.which === 16) { // ignore SHIFT key return; } else { clearTimeout(self.refreshTimer); self.refreshTimer = setTimeout(function() { self.refresh(); self.list.scrollToActiveOption(); }, 1); } }; // other event handlers this.realElement.on({ focus: this.onFocus, click: this.delayedRefresh, keydown: this.delayedRefresh }); // select list event handlers $(this.list).on({ select: this.onSelect, press: this.onFakeOptionsPress, release: this.onFakeOptionsRelease }); }, onFakeOptionsPress: function(e, pointerEvent) { this.pressedFlag = true; if (pointerEvent.pointerType === 'mouse') { this.realElement.focus(); } }, onFakeOptionsRelease: function(e, pointerEvent) { this.pressedFlag = false; if (pointerEvent.pointerType === 'mouse') { this.realElement.focus(); } }, onSelect: function() { this.fireNativeEvent(this.realElement, 'change'); this.fireNativeEvent(this.realElement, 'click'); }, onFocus: function() { if (!this.pressedFlag || !this.focusedFlag) { this.fakeElement.addClass(this.options.focusClass); this.realElement.on('blur', this.onBlur); this.focusedFlag = true; } }, onBlur: function() { if (!this.pressedFlag) { this.fakeElement.removeClass(this.options.focusClass); this.realElement.off('blur', this.onBlur); this.focusedFlag = false; } }, refresh: function() { this.fakeElement.toggleClass(this.options.disabledClass, this.realElement.is(':disabled')); this.list.refresh(); }, destroy: function() { this.list.destroy(); this.realElement.insertBefore(this.fakeElement).removeClass(this.options.hiddenClass); this.fakeElement.remove(); } }); // options list module function SelectList(options) { this.options = $.extend({ holder: null, maxVisibleItems: 10, selectOnClick: true, useHoverClass: false, useCustomScroll: false, handleResize: true, multipleSelectWithoutKey: false, alwaysPreventMouseWheel: false, indexAttribute: 'data-index', cloneClassPrefix: 'jcf-option-', containerStructure: '', containerSelector: '.jcf-list-content', captionClass: 'jcf-optgroup-caption', disabledClass: 'jcf-disabled', optionClass: 'jcf-option', groupClass: 'jcf-optgroup', hoverClass: 'jcf-hover', selectedClass: 'jcf-selected', scrollClass: 'jcf-scroll-active' }, options); this.init(); } $.extend(SelectList.prototype, { init: function() { this.initStructure(); this.refreshSelectedClass(); this.attachEvents(); }, initStructure: function() { this.element = $(this.options.element); this.indexSelector = '[' + this.options.indexAttribute + ']'; this.container = $(this.options.containerStructure).appendTo(this.options.holder); this.listHolder = this.container.find(this.options.containerSelector); this.lastClickedIndex = this.element.prop('selectedIndex'); this.rebuildList(); }, attachEvents: function() { this.bindHandlers(); this.listHolder.on('jcf-pointerdown', this.indexSelector, this.onItemPress); this.listHolder.on('jcf-pointerdown', this.onPress); if (this.options.useHoverClass) { this.listHolder.on('jcf-pointerover', this.indexSelector, this.onHoverItem); } }, onPress: function(e) { $(this).trigger('press', e); this.listHolder.on('jcf-pointerup', this.onRelease); }, onRelease: function(e) { $(this).trigger('release', e); this.listHolder.off('jcf-pointerup', this.onRelease); }, onHoverItem: function(e) { var hoverIndex = parseFloat(e.currentTarget.getAttribute(this.options.indexAttribute)); this.fakeOptions.removeClass(this.options.hoverClass).eq(hoverIndex).addClass(this.options.hoverClass); }, onItemPress: function(e) { if (e.pointerType === 'touch' || this.options.selectOnClick) { // select option after "click" this.tmpListOffsetTop = this.list.offset().top; this.listHolder.on('jcf-pointerup', this.indexSelector, this.onItemRelease); } else { // select option immediately this.onSelectItem(e); } }, onItemRelease: function(e) { // remove event handlers and temporary data this.listHolder.off('jcf-pointerup', this.indexSelector, this.onItemRelease); // simulate item selection if (this.tmpListOffsetTop === this.list.offset().top) { this.listHolder.on('click', this.indexSelector, { savedPointerType: e.pointerType }, this.onSelectItem); } delete this.tmpListOffsetTop; }, onSelectItem: function(e) { var clickedIndex = parseFloat(e.currentTarget.getAttribute(this.options.indexAttribute)), pointerType = e.data && e.data.savedPointerType || e.pointerType || 'mouse', range; // remove click event handler this.listHolder.off('click', this.indexSelector, this.onSelectItem); // ignore clicks on disabled options if (e.button > 1 || this.realOptions[clickedIndex].disabled) { return; } if (this.element.prop('multiple')) { if (e.metaKey || e.ctrlKey || pointerType === 'touch' || this.options.multipleSelectWithoutKey) { // if CTRL/CMD pressed or touch devices - toggle selected option this.realOptions[clickedIndex].selected = !this.realOptions[clickedIndex].selected; } else if (e.shiftKey) { // if SHIFT pressed - update selection range = [this.lastClickedIndex, clickedIndex].sort(function(a, b) { return a - b; }); this.realOptions.each(function(index, option) { option.selected = (index >= range[0] && index <= range[1]); }); } else { // set single selected index this.element.prop('selectedIndex', clickedIndex); } } else { this.element.prop('selectedIndex', clickedIndex); } // save last clicked option if (!e.shiftKey) { this.lastClickedIndex = clickedIndex; } // refresh classes this.refreshSelectedClass(); // scroll to active item in desktop browsers if (pointerType === 'mouse') { this.scrollToActiveOption(); } // make callback when item selected $(this).trigger('select'); }, rebuildList: function() { // rebuild options var self = this, rootElement = this.element[0]; // recursively create fake options this.storedSelectHTML = rootElement.innerHTML; this.optionIndex = 0; this.list = $(this.createOptionsList(rootElement)); this.listHolder.empty().append(this.list); this.realOptions = this.element.find('option'); this.fakeOptions = this.list.find(this.indexSelector); this.fakeListItems = this.list.find('.' + this.options.captionClass + ',' + this.indexSelector); delete this.optionIndex; // detect max visible items var maxCount = this.options.maxVisibleItems, sizeValue = this.element.prop('size'); if (sizeValue > 1 && !this.element.is('[jcf-size]')) { maxCount = sizeValue; } // handle scrollbar var needScrollBar = this.fakeOptions.length > maxCount; this.container.toggleClass(this.options.scrollClass, needScrollBar); if (needScrollBar) { // change max-height this.listHolder.css({ maxHeight: this.getOverflowHeight(maxCount), overflow: 'auto' }); if (this.options.useCustomScroll && jcf.modules.Scrollable) { // add custom scrollbar if specified in options jcf.replace(this.listHolder, 'Scrollable', { handleResize: this.options.handleResize, alwaysPreventMouseWheel: this.options.alwaysPreventMouseWheel }); return; } } // disable edge wheel scrolling if (this.options.alwaysPreventMouseWheel) { this.preventWheelHandler = function(e) { var currentScrollTop = self.listHolder.scrollTop(), maxScrollTop = self.listHolder.prop('scrollHeight') - self.listHolder.innerHeight(); // check edge cases if ((currentScrollTop <= 0 && e.deltaY < 0) || (currentScrollTop >= maxScrollTop && e.deltaY > 0)) { e.preventDefault(); } }; this.listHolder.on('jcf-mousewheel', this.preventWheelHandler); } }, refreshSelectedClass: function() { var self = this, selectedItem, isMultiple = this.element.prop('multiple'), selectedIndex = this.element.prop('selectedIndex'); if (isMultiple) { this.realOptions.each(function(index, option) { self.fakeOptions.eq(index).toggleClass(self.options.selectedClass, !!option.selected); }); } else { this.fakeOptions.removeClass(this.options.selectedClass + ' ' + this.options.hoverClass); selectedItem = this.fakeOptions.eq(selectedIndex).addClass(this.options.selectedClass); if (this.options.useHoverClass) { selectedItem.addClass(this.options.hoverClass); } } }, scrollToActiveOption: function() { // scroll to target option var targetOffset = this.getActiveOptionOffset(); if (typeof targetOffset === 'number') { this.listHolder.prop('scrollTop', targetOffset); } }, getSelectedIndexRange: function() { var firstSelected = -1, lastSelected = -1; this.realOptions.each(function(index, option) { if (option.selected) { if (firstSelected < 0) { firstSelected = index; } lastSelected = index; } }); return [firstSelected, lastSelected]; }, getChangedSelectedIndex: function() { var selectedIndex = this.element.prop('selectedIndex'), targetIndex; if (this.element.prop('multiple')) { // multiple selects handling if (!this.previousRange) { this.previousRange = [selectedIndex, selectedIndex]; } this.currentRange = this.getSelectedIndexRange(); targetIndex = this.currentRange[this.currentRange[0] !== this.previousRange[0] ? 0 : 1]; this.previousRange = this.currentRange; return targetIndex; } else { // single choice selects handling return selectedIndex; } }, getActiveOptionOffset: function() { // calc values var dropHeight = this.listHolder.height(), dropScrollTop = this.listHolder.prop('scrollTop'), currentIndex = this.getChangedSelectedIndex(), fakeOption = this.fakeOptions.eq(currentIndex), fakeOptionOffset = fakeOption.offset().top - this.list.offset().top, fakeOptionHeight = fakeOption.innerHeight(); // scroll list if (fakeOptionOffset + fakeOptionHeight >= dropScrollTop + dropHeight) { // scroll down (always scroll to option) return fakeOptionOffset - dropHeight + fakeOptionHeight; } else if (fakeOptionOffset < dropScrollTop) { // scroll up to option return fakeOptionOffset; } }, getOverflowHeight: function(sizeValue) { var item = this.fakeListItems.eq(sizeValue - 1), listOffset = this.list.offset().top, itemOffset = item.offset().top, itemHeight = item.innerHeight(); return itemOffset + itemHeight - listOffset; }, getScrollTop: function() { return this.listHolder.scrollTop(); }, setScrollTop: function(value) { this.listHolder.scrollTop(value); }, createOption: function(option) { var newOption = document.createElement('span'); newOption.className = this.options.optionClass; newOption.innerHTML = option.innerHTML; newOption.setAttribute(this.options.indexAttribute, this.optionIndex++); var optionImage, optionImageSrc = option.getAttribute('data-image'); if (optionImageSrc) { optionImage = document.createElement('img'); optionImage.src = optionImageSrc; newOption.insertBefore(optionImage, newOption.childNodes[0]); } if (option.disabled) { newOption.className += ' ' + this.options.disabledClass; } if (option.className) { newOption.className += ' ' + getPrefixedClasses(option.className, this.options.cloneClassPrefix); } return newOption; }, createOptGroup: function(optgroup) { var optGroupContainer = document.createElement('span'), optGroupName = optgroup.getAttribute('label'), optGroupCaption, optGroupList; // create caption optGroupCaption = document.createElement('span'); optGroupCaption.className = this.options.captionClass; optGroupCaption.innerHTML = optGroupName; optGroupContainer.appendChild(optGroupCaption); // create list of options if (optgroup.children.length) { optGroupList = this.createOptionsList(optgroup); optGroupContainer.appendChild(optGroupList); } optGroupContainer.className = this.options.groupClass; return optGroupContainer; }, createOptionContainer: function() { var optionContainer = document.createElement('li'); return optionContainer; }, createOptionsList: function(container) { var self = this, list = document.createElement('ul'); $.each(container.children, function(index, currentNode) { var item = self.createOptionContainer(currentNode), newNode; switch (currentNode.tagName.toLowerCase()) { case 'option': newNode = self.createOption(currentNode); break; case 'optgroup': newNode = self.createOptGroup(currentNode); break; } list.appendChild(item).appendChild(newNode); }); return list; }, refresh: function() { // check for select innerHTML changes if (this.storedSelectHTML !== this.element.prop('innerHTML')) { this.rebuildList(); } // refresh custom scrollbar var scrollInstance = jcf.getInstance(this.listHolder); if (scrollInstance) { scrollInstance.refresh(); } // refresh selectes classes this.refreshSelectedClass(); }, destroy: function() { this.listHolder.off('jcf-mousewheel', this.preventWheelHandler); this.listHolder.off('jcf-pointerdown', this.indexSelector, this.onSelectItem); this.listHolder.off('jcf-pointerover', this.indexSelector, this.onHoverItem); this.listHolder.off('jcf-pointerdown', this.onPress); } }); // helper functions var getPrefixedClasses = function(className, prefixToAdd) { return className ? className.replace(/[\s]*([\S]+)+[\s]*/gi, prefixToAdd + '$1 ') : ''; }; var makeUnselectable = (function() { var unselectableClass = jcf.getOptions().unselectableClass; function preventHandler(e) { e.preventDefault(); } return function(node) { node.addClass(unselectableClass).on('selectstart', preventHandler); }; }()); return module; });