').parent().append($wrapper.prepend($label), $items, $input);\r\n\r\n eventTriggers = {\r\n open : _open,\r\n close : _close,\r\n destroy : _destroy,\r\n refresh : _refresh,\r\n init : _init\r\n };\r\n\r\n $original.on(eventTriggers).wrap('
');\r\n $.extend(_this, eventTriggers);\r\n\r\n labelBuilder = _this.options.labelBuilder;\r\n\r\n if ( _this.options.inheritOriginalWidth && originalWidth > 0 )\r\n $outerWrapper.width(originalWidth);\r\n\r\n _populate();\r\n }\r\n\r\n // Generate options markup and event binds\r\n function _populate() {\r\n _this.items = [];\r\n\r\n var $options = $original.children(),\r\n _$li = '
',\r\n $justOptions = $original.find('option'),\r\n selectedIndex = $justOptions.index($justOptions.filter(':selected')),\r\n currIndex = 0;\r\n\r\n currValue = (selected = ~selectedIndex ? selectedIndex : 0);\r\n\r\n if ( optionsLength = $options.length ) {\r\n // Build options markup\r\n $options.each(function() {\r\n var $elm = $(this);\r\n\r\n if ( $elm.is('optgroup') ) {\r\n var groupDisabled = $elm.prop('disabled'),\r\n $children = $elm.children();\r\n\r\n _$li += _utils.format('- {3}
',\r\n $.trim([_this.classes.group, groupDisabled ? 'disabled' : '', $elm.prop('class')].join(' ')),\r\n _this.classes.grouplabel,\r\n $elm.prop('label')\r\n );\r\n\r\n if ( groupDisabled ) {\r\n $children.prop('disabled', true);\r\n }\r\n\r\n $children.each(buildOption);\r\n\r\n _$li += '
';\r\n } else {\r\n buildOption.call($elm);\r\n }\r\n\r\n function buildOption() {\r\n var $elm = $(this),\r\n optionText = $elm.html(),\r\n selectDisabled = $elm.prop('disabled'),\r\n itemBuilder = _this.options.optionsItemBuilder;\r\n\r\n _this.items[currIndex] = {\r\n element : $elm,\r\n value : $elm.val(),\r\n text : optionText,\r\n slug : _utils.replaceDiacritics(optionText),\r\n disabled : selectDisabled\r\n };\r\n\r\n _$li += _utils.format('- {3}
',\r\n currIndex,\r\n $.trim([currIndex == currValue ? 'selected' : '', currIndex == optionsLength - 1 ? 'last' : '', selectDisabled ? 'disabled' : ''].join(' ')),\r\n $.isFunction(itemBuilder) ? itemBuilder(_this.items[currIndex], $elm, currIndex) : _utils.format(itemBuilder, _this.items[currIndex])\r\n );\r\n\r\n currIndex++;\r\n }\r\n });\r\n\r\n $items.append( $itemsScroll.html(_$li + '
') );\r\n\r\n $label.html(\r\n $.isFunction(labelBuilder) ? labelBuilder(_this.items[currValue]) : _utils.format(labelBuilder, _this.items[currValue])\r\n )\r\n }\r\n\r\n $wrapper.add($original).add($outerWrapper).add($input).off(bindSufix);\r\n\r\n $outerWrapper.prop('class', [\r\n _this.classes.wrapper,\r\n _this.options.customClass.overwrite ?\r\n $original.prop('class').replace(/\\S+/g, _this.options.customClass.prefix + '-$&') :\r\n $original.prop('class'),\r\n _this.options.responsive ? _this.classes.responsive : ''\r\n ].join(' '));\r\n\r\n if ( !$original.prop('disabled') ) {\r\n isEnabled = true;\r\n\r\n // Not disabled, so... Removing disabled class and bind hover\r\n $outerWrapper.removeClass(_this.classes.disabled).on('mouseenter' + bindSufix + ' mouseleave' + bindSufix, function(e) {\r\n $(this).toggleClass(_this.classes.hover);\r\n\r\n // Delay close effect when openOnHover is true\r\n if ( _this.options.openOnHover ) {\r\n clearTimeout(_this.closeTimer);\r\n e.type == 'mouseleave' ? _this.closeTimer = setTimeout(_close, _this.options.hoverIntentTimeout) : _open();\r\n }\r\n });\r\n\r\n // Toggle open/close\r\n $wrapper.on('click' + bindSufix, function(e) {\r\n isOpen ? _close() : _open(e);\r\n });\r\n\r\n $input\r\n .prop({\r\n tabindex: tabindex,\r\n disabled: false\r\n })\r\n .on('keypress' + bindSufix, _handleSystemKeys)\r\n .on('keydown' + bindSufix, function(e) {\r\n _handleSystemKeys(e);\r\n\r\n // Clear search\r\n clearTimeout(_this.resetStr);\r\n _this.resetStr = setTimeout(function() {\r\n $input.val('');\r\n }, _this.options.keySearchTimeout);\r\n\r\n var key = e.keyCode || e.which;\r\n\r\n // If it's a directional key\r\n // 37 => Left\r\n // 38 => Up\r\n // 39 => Right\r\n // 40 => Down\r\n if ( key > 36 && key < 41 ) {\r\n if ( !_this.options.allowWrap ) {\r\n if ( (key < 39 && selected == 0) || (key > 38 && (selected + 1) == _this.items.length) ) {\r\n return;\r\n }\r\n }\r\n\r\n _select(_utils[(key < 39 ? 'previous' : 'next') + 'EnabledItem'](_this.items, selected));\r\n }\r\n })\r\n .on('focusin' + bindSufix, function(e) {\r\n // Stupid, but necessary... Prevent the flicker when\r\n // focusing out and back again in the browser window\r\n $input.one('blur', function() {\r\n $input.blur();\r\n });\r\n\r\n isOpen || _open(e);\r\n })\r\n .on('oninput' in $input[0] ? 'input' : 'keyup', function() {\r\n if ( $input.val().length ) {\r\n // Search in select options\r\n $.each(_this.items, function(i, elm) {\r\n if ( RegExp('^' + $input.val(), 'i').test(elm.slug) && !elm.disabled ) {\r\n _select(i);\r\n return false;\r\n }\r\n });\r\n }\r\n });\r\n\r\n $original.prop('tabindex', false);\r\n\r\n // Remove styles from items box\r\n // Fix incorrect height when refreshed is triggered with fewer options\r\n $li = $('li', $items.removeAttr('style')).on({\r\n // Prevent
blur on Chrome\r\n mousedown: function(e) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n },\r\n click: function() {\r\n // The second parameter is to close the box after click\r\n _select($(this).data('index'), true);\r\n\r\n // Chrome doesn't close options box if select is wrapped with a label\r\n // We need to 'return false' to avoid that\r\n return false;\r\n }\r\n }).filter('[data-index]');\r\n } else {\r\n $outerWrapper.addClass(_this.classes.disabled);\r\n $input.prop('disabled', true);\r\n }\r\n\r\n _utils.triggerCallback('Init', _this);\r\n }\r\n\r\n function _refresh() {\r\n _utils.triggerCallback('Refresh', _this);\r\n _populate();\r\n }\r\n\r\n // Behavior when system keys is pressed\r\n function _handleSystemKeys(e) {\r\n var key = e.keyCode || e.which;\r\n\r\n if ( key == 13 ) {\r\n e.preventDefault();\r\n }\r\n\r\n // Tab / Enter / ESC\r\n if ( /^(9|13|27)$/.test(key) ) {\r\n e.stopPropagation();\r\n _select(selected, true);\r\n }\r\n }\r\n\r\n // Set options box width/height\r\n function _calculateOptionsDimensions() {\r\n // Calculate options box height\r\n // Set a temporary class on the hidden parent of the element\r\n var hiddenChildren = $items.closest(':visible').children(':hidden').addClass(_this.classes.tempshow),\r\n maxHeight = _this.options.maxHeight,\r\n itemsWidth = $items.outerWidth(),\r\n wrapperWidth = $wrapper.outerWidth() - (itemsWidth - $items.width());\r\n\r\n // Set the dimensions, minimum is wrapper width, expand for long items if option is true\r\n if ( !_this.options.expandToItemText || wrapperWidth > itemsWidth )\r\n finalWidth = wrapperWidth;\r\n else {\r\n // Make sure the scrollbar width is included\r\n $items.css('overflow', 'scroll');\r\n\r\n // Set a really long width for $outerWrapper\r\n $outerWrapper.width(9e4);\r\n finalWidth = $items.width();\r\n // Set scroll bar to auto\r\n $items.css('overflow', '');\r\n $outerWrapper.width('');\r\n }\r\n\r\n $items.width(finalWidth).height() > maxHeight && $items.height(maxHeight);\r\n\r\n // Remove the temporary class\r\n hiddenChildren.removeClass(_this.classes.tempshow);\r\n }\r\n\r\n // Open the select options box\r\n function _open(e) {\r\n _utils.triggerCallback('BeforeOpen', _this);\r\n\r\n if ( e ) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n }\r\n\r\n if ( isEnabled ) {\r\n _calculateOptionsDimensions();\r\n\r\n // Find any other opened instances of select and close it\r\n $('.' + _this.classes.hideselect, '.' + _this.classes.open).children()[pluginName]('close');\r\n\r\n isOpen = true;\r\n itemsHeight = $items.outerHeight();\r\n itemsInnerHeight = $items.height();\r\n\r\n // Toggle options box visibility\r\n $outerWrapper.addClass(_this.classes.open);\r\n\r\n // Give dummy input focus\r\n $input.val('').is(':focus') || $input.focus();\r\n\r\n $doc.on('click' + bindSufix, _close).on('scroll' + bindSufix, _isInViewport);\r\n _isInViewport();\r\n\r\n // Prevent window scroll when using mouse wheel inside items box\r\n if ( _this.options.preventWindowScroll ) {\r\n $doc.on('mousewheel' + bindSufix + ' DOMMouseScroll' + bindSufix, '.' + _this.classes.scroll, function(e) {\r\n var orgEvent = e.originalEvent,\r\n scrollTop = $(this).scrollTop(),\r\n deltaY = 0;\r\n\r\n if ( 'detail' in orgEvent ) { deltaY = orgEvent.detail * -1; }\r\n if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent.wheelDelta; }\r\n if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY; }\r\n if ( 'deltaY' in orgEvent ) { deltaY = orgEvent.deltaY * -1; }\r\n\r\n if ( scrollTop == (this.scrollHeight - itemsInnerHeight) && deltaY < 0 || scrollTop == 0 && deltaY > 0 ) {\r\n e.preventDefault();\r\n }\r\n });\r\n }\r\n\r\n _detectItemVisibility(selected);\r\n\r\n _utils.triggerCallback('Open', _this);\r\n }\r\n }\r\n\r\n // Detect is the options box is inside the window\r\n function _isInViewport() {\r\n $outerWrapper.toggleClass(_this.classes.above, $outerWrapper.offset().top + $outerWrapper.outerHeight() + itemsHeight > $win.scrollTop() + $win.height());\r\n }\r\n\r\n // Close the select options box\r\n function _close() {\r\n _utils.triggerCallback('BeforeClose', _this);\r\n\r\n if ( currValue != selected ) {\r\n _utils.triggerCallback('BeforeChange', _this);\r\n\r\n var text = _this.items[selected].text;\r\n\r\n // Apply changed value to original select\r\n $original\r\n .prop('selectedIndex', currValue = selected)\r\n .data('value', text);\r\n\r\n // Change label text\r\n $label.html(\r\n $.isFunction(labelBuilder) ? labelBuilder(_this.items[selected]) : _utils.format(labelBuilder, _this.items[selected])\r\n )\r\n\r\n _utils.triggerCallback('Change', _this);\r\n }\r\n\r\n // Remove custom events on document\r\n $doc.off(bindSufix);\r\n\r\n // Remove visible class to hide options box\r\n $outerWrapper.removeClass(_this.classes.open);\r\n\r\n isOpen = false;\r\n\r\n _utils.triggerCallback('Close', _this);\r\n }\r\n\r\n // Select option\r\n function _select(index, close) {\r\n // Parameter index is required\r\n if ( index == undefined ) {\r\n return;\r\n }\r\n\r\n // If element is disabled, can't select it\r\n if ( !_this.items[index].disabled ) {\r\n // If 'close' is false (default), the options box won't close after\r\n // each selected item, this is necessary for keyboard navigation\r\n $li\r\n .removeClass('selected')\r\n .eq(selected = index)\r\n .addClass('selected');\r\n\r\n _detectItemVisibility(index);\r\n close && _close();\r\n }\r\n }\r\n\r\n // Detect if currently selected option is visible and scroll the options box to show it\r\n function _detectItemVisibility(index) {\r\n var liHeight = $li.eq(index).outerHeight(),\r\n liTop = $li[index].offsetTop,\r\n itemsScrollTop = $itemsScroll.scrollTop(),\r\n scrollT = liTop + liHeight * 2;\r\n\r\n $itemsScroll.scrollTop(\r\n scrollT > itemsScrollTop + itemsHeight ? scrollT - itemsHeight :\r\n liTop - liHeight < itemsScrollTop ? liTop - liHeight :\r\n itemsScrollTop\r\n );\r\n }\r\n\r\n // Unbind and remove\r\n function _destroy(preserveData) {\r\n if ( isEnabled ) {\r\n $items.add($wrapper).add($input).remove();\r\n !preserveData && $original.removeData(pluginName).removeData('value');\r\n $original.prop('tabindex', tabindex).off(bindSufix).off(eventTriggers).unwrap().unwrap();\r\n isEnabled = false;\r\n }\r\n }\r\n\r\n _init(opts);\r\n };\r\n\r\n // A really lightweight plugin wrapper around the constructor,\r\n // preventing against multiple instantiations\r\n $.fn[pluginName] = function(args) {\r\n return this.each(function() {\r\n var data = $.data(this, pluginName);\r\n\r\n if ( data && !data.disableOnMobile )\r\n (''+args === args && data[args]) ? data[args]() : data.init(args);\r\n else\r\n $.data(this, pluginName, new Selectric(this, args));\r\n });\r\n };\r\n\r\n $.fn[pluginName].hooks = hooks;\r\n}(jQuery));\r\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/selectric/public/jquery.selectric.js\n ** module id = 15\n ** module chunks = 0\n **/"],"sourceRoot":""}