(function($) { // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // // ----------------------------------------- DATA ----------------------------------------- // // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // var Data = { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defaults //default settings values defaults: { //style width: '100%', size: 'medium', themes: [], //texts placeholder: 'Select an item', //controls removable: false, empty: false, search: false, //ajax ajax: false, data: {}, //positionning scrollContainer: null }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ setDefaults //set default settings values setup: function(opts) { //controls provided settings keys var defKeys = Object.keys(this.defaults); var optKeys = Object.keys(opts); var isOk = true; optKeys.forEach(function(k) { if($.inArray(k, defKeys) === -1) { console.error('selectMania | wrong setup settings'); isOk = false; } }); //if provided settings are ok if(isOk) { this.defaults = $.extend(true, {}, Data.defaults, opts); } } }; // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // // ---------------------------------------- ENGINE ---------------------------------------- // // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // var Engine = { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ internalSettings //insert internal data into settings object internalSettings: function($originalSelect, settings) { var thisEngine = this; //initialize interal data settings.multiple = false; settings.values = []; //if select is multiple settings.multiple = $originalSelect.is('[multiple]'); //if select is disabled settings.disabled = $originalSelect.is('[disabled]'); //loop through selected options $originalSelect.find('option:selected').each(function() { //insert selected value data settings.values.push({ value: this.value, text: this.text }); }); //send back settings return settings; }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ getAttrSettings //get selectMania settings stored as attributes getAttrSettings: function($originalSelect) { var attrData = {}; //available attributes var attrs = ['width','size','placeholder','removable','empty','search','scrollContainer']; //loop through attributes attrs.forEach(function(attr) { //if attribute is set on select if($originalSelect.is('[data-'+attr+']')) { //insert data var elAttr = $originalSelect.attr('data-'+attr); if(elAttr === 'true' || elAttr === 'false') { elAttr = elAttr === 'true'; } attrData[attr] = elAttr; } }); //send back select attributes data return attrData; }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ initialize //initialize selectMania on original select initialize: function($originalSelect, userSettings) { var thisEngine = this; //clone settings before starting work var settings = $.extend(true, {}, userSettings); //get select settings stored as attributes var attrSettings = thisEngine.getAttrSettings($originalSelect); //merge settings with attributes settings = $.extend(settings, attrSettings); //set selected value as empty if explicitly asked if(settings.empty) { $originalSelect.val(''); } //insert internal data into settings settings = thisEngine.internalSettings($originalSelect, settings); //control ajax function type and size if(thisEngine.controlSettings($originalSelect, settings)) { //build selectMania elements var $builtSelect = Build.build($originalSelect, settings); //attach original select element to selectMania element $builtSelect.data('selectMania-originalSelect', $originalSelect); //attach selectMania element to original select element $originalSelect.data('selectMania-element', $builtSelect); //if ajax is activated if(settings.ajax !== false) { //initialize ajax data thisEngine.initAjax($builtSelect, settings); } //update clean values icon display thisEngine.updateClean($builtSelect); //add witness / hding class original select element $originalSelect.addClass('select-mania-original'); //insert selectMania element before original select $builtSelect.insertBefore($originalSelect); //move original select into selectMania element $originalSelect.appendTo($builtSelect); //bind selectMania element Binds.bind($builtSelect); } }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ update //update selectMania element according to original select element update: function($originalSelect) { var thisEngine = this; //selectMania elements $selectManiaEl = $originalSelect.data('selectMania-element'); $valueList = $selectManiaEl.find('.select-mania-values').first(); $itemList = $selectManiaEl.find('.select-mania-items').first(); //update disabled status if($originalSelect.is('[disabled]')) { $selectManiaEl.addClass('select-mania-disabled'); } else { $selectManiaEl.removeClass('select-mania-disabled'); } //remove selectMania values and items $selectManiaEl.find('.select-mania-value').remove(); $itemList.empty(); //build and insert selected values $originalSelect.find('option:selected').each(function() { if($(this).is(':selected')) { $valueList.append(Build.buildValue({ value: this.value, text: this.text })); } }); //build and insert items $itemList.append(Build.buildItemList($originalSelect.children())); //update clean values icon display thisEngine.updateClean($selectManiaEl); //rebind selectMania element Binds.bind($selectManiaEl); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ destroy //destroy selectMania on targeted original select destroy: function($originalSelect) { //selectMania element $selectManiaEl = $originalSelect.data('selectMania-element'); //move original select out of the selectMania element $originalSelect.insertAfter($selectManiaEl); //remove selectMania element $selectManiaEl.remove(); //remove class from original select $originalSelect.removeClass('select-mania-original'); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ openDropdown / closeDropdown //open items dropdown openDropdown: function($dropdown) { var thisEngine = this; //select-mania element var $selectManiaEl = $dropdown.closest('.select-mania'); //if scroll container option is set if($selectManiaEl.is('[data-selectMania-scrollContainer]')) { //scroll container element var $scrollContainer = $($selectManiaEl.attr('data-selectMania-scrollContainer')); //position absolute dropdown Engine.positionDropdown($dropdown); //apply positionning class $dropdown.addClass('select-mania-absolute'); //bind scroll container to close dropdown on scroll $scrollContainer.off('scroll.selectMania').on('scroll.selectMania', function() { //unbind close dropdown on scrolling $scrollContainer.off('scroll.selectMania'); //close open dropdown Engine.closeDropdown($('.select-mania-dropdown.open')); }); //reposition dropdown when window is resized $(window).off('resize.selectMania').on('resize.selectMania', function() { //position absolute dropdown Engine.positionDropdown($dropdown); }); } //open dropdown $dropdown.stop().addClass('open').slideDown(100); //scroll dropdown to top $dropdown.find('.select-mania-items').scrollTop(0); //focus search input thisEngine.focusSearch($dropdown); //bind keyboard control $(document).off('keydown.selectMania').on('keydown.selectMania', Binds.keyboardControl); }, //close items dropdown closeDropdown: function($dropdown) { var $selectManiaEl = $dropdown.data('selectMania-element'); //unbind keyboard control $(document).off('keydown.selectMania'); //remove every hover class from items $dropdown.find('.select-mania-item').removeClass('select-mania-hover'); //if dropdown has aboslute positionning if($dropdown.hasClass('select-mania-absolute')) { //select-mania inner element var $selectManiaInner = $dropdown .data('selectMania-element') .find('.select-mania-inner') .first(); //move back the dropdown inside select-mania element $dropdown .removeClass('open') .hide() .insertAfter( $selectManiaInner ); //unbind repositioning on resize $(window).off('resize.selectMania'); //unbind close dropdown on scrolling var $scrollContainer = $($selectManiaEl.attr('data-selectMania-scrollContainer')); if($scrollContainer.length > 0) { $scrollContainer.off('scroll.selectMania'); } } //if dropdown has standard positionning else { //close dropdown $dropdown.stop().removeClass('open').slideUp(100); } }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ positionDropdown //position dropdown relative to its select-mania element positionDropdown: function($dropdown) { var $selectManiaEl = $dropdown.data('selectMania-element'); //item list scroll data var $itemList = $dropdown.find('.select-mania-items'); var itemListScroll = $itemList.scrollTop(); //data for calculating dropdown absolute position var selectManiaElPos = $selectManiaEl.offset(); var selectManiaElWidth = $selectManiaEl.outerWidth(); var selectManiaElHeight = $selectManiaEl.outerHeight(); //append dropdown to body in absolute position $dropdown.appendTo('body').css({ position: 'absolute', top: selectManiaElPos.top + selectManiaElHeight, left: selectManiaElPos.left, width: selectManiaElWidth }); //force item list scroll to its initial state $itemList.scrollTop(itemListScroll); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ selectItem //perform item selection in dropdown selectItem: function($item) { //dropdown element var $dropdown = $item.closest('.select-mania-dropdown'); //selectMania element var $selectManiaEl = $dropdown.data('selectMania-element'); //select original element var $originalSelect = $selectManiaEl.data('selectMania-originalSelect'); //if item not already selected if(!$item.is('.select-mania-selected')) { //clicked item value var itemVal = $item.attr('data-value'); //build value element var $value = Build.buildValue({ value: itemVal, text: $item.text() }); //if select multiple if($selectManiaEl.is('.select-mania-multiple')) { //insert value element in selectMania values $selectManiaEl.find('.select-mania-values').append($value); //add value in original select element Engine.addMultipleVal($originalSelect, itemVal); } //if select not multiple else { //unselect every other items $dropdown.find('.select-mania-item').removeClass('select-mania-selected'); //insert value element in selectMania values $selectManiaEl.find('.select-mania-values .select-mania-value').remove(); $selectManiaEl.find('.select-mania-values').append($value); //change value in original select element $originalSelect.val(itemVal); } //set clicked item as selected $item.addClass('select-mania-selected'); //trigger original select change event $originalSelect.trigger('change'); } //if absolute position dropdown if($dropdown.is('.select-mania-absolute')) { //position absolute dropdown Engine.positionDropdown($dropdown); } //if select not multiple if(!$selectManiaEl.is('.select-mania-multiple')) { //close dropdown Engine.closeDropdown($dropdown); } //update clear values icon display Engine.updateClean($selectManiaEl); //rebind selectMania element Binds.bind($selectManiaEl); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ focusSearch //focus search input in dropdown focusSearch: function($dropdown) { $dropdown.find('.select-mania-search-input').focus(); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ addMultipleVal //add value to multiple original select addMultipleVal: function($originalSelect, val) { var originalVals = $originalSelect.val(); if(!(originalVals instanceof Array)) { originalVals = []; } originalVals.push(val); $originalSelect.val(originalVals); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ removeMultipleVal //remove value from multiple original select removeMultipleVal: function($originalSelect, val) { var originalVals = $originalSelect.val(); if(!(originalVals instanceof Array)) { originalVals = []; } originalVals.splice($.inArray(val, originalVals), 1); $originalSelect.val(originalVals); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ updateClean //display / hide clean values icon according to current values updateClean: function($selectManiaEl) { //original select element var $originalSelect = $selectManiaEl.data('selectMania-originalSelect'); //if value is not empty if($originalSelect.val() !== null && $originalSelect.val().length > 0) { //display clean values icon $selectManiaEl.find('.select-mania-clear-icon').show(); } //if empty value else { //hide clean values icon $selectManiaEl.find('.select-mania-clear-icon').hide(); } }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ doSearch //do search in items dropdown doSearch: function($selectManiaEl) { //dropdown var $dropdown = $selectManiaEl.data('selectMania-dropdown'); //search value var searchVal = $dropdown.find('.select-mania-search-input').first().val(); searchVal = searchVal.toLowerCase().trim(); //if empty search value if(searchVal === '') { //display all items $dropdown.find('.select-mania-group, .select-mania-item').removeClass('select-mania-hidden'); //stop function return; } //loop through dropdown items $dropdown.find('.select-mania-item').each(function() { //if item text matches search value if($(this).text().toLowerCase().indexOf(searchVal) !== -1) { //display item $(this).removeClass('select-mania-hidden'); } //if item text don't match search value else { //hide item $(this).addClass('select-mania-hidden'); } }); //show / hide optgroups if contain results / empty $dropdown.find('.select-mania-group').each(function() { if($(this).find('.select-mania-item:not(.select-mania-hidden)').length > 0) { $(this).removeClass('select-mania-hidden'); } else { $(this).addClass('select-mania-hidden'); } }); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ doSearchAjax //do ajax search in items dropdown doSearchAjax: function($selectManiaEl) { var thisEngine = this; //dropdown var $dropdown = $selectManiaEl.data('selectMania-dropdown'); //search value var thisSearch = $dropdown.find('.select-mania-search-input').first().val(); //pause ajax scroll $selectManiaEl.data('selectMania-ajaxReady', false); //reset current page number $selectManiaEl.data('selectMania-ajaxPage', 1); //loading icon thisEngine.dropdownLoading($selectManiaEl); //call ajax function var thisAjaxFunction = $selectManiaEl.data('selectMania-ajaxFunction'); var thisAjaxData = $selectManiaEl.data('selectMania-ajaxData'); thisAjaxFunction(thisSearch, 1, thisAjaxData, function(optHTML) { //remove loading icon thisEngine.dropdownLoading($selectManiaEl, true); //replace current items with sent options Engine.replaceItems($selectManiaEl, optHTML); //rebind select Binds.bind($selectManiaEl); //reset ajax scroll data thisEngine.initAjax($selectManiaEl); }); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ addItems / replaceItems //add items to dropdown addItems: function($selectManiaEl, optionsHTML) { var thisEngine = this; thisEngine.addOrReplaceItems($selectManiaEl, optionsHTML, false); }, //replace dropdown items replaceItems: function($selectManiaEl, optionsHTML) { var thisEngine = this; thisEngine.addOrReplaceItems($selectManiaEl, optionsHTML, true); }, //add / replace dropdown items addOrReplaceItems: function($selectManiaEl, optionsHTML, replace) { var thisEngine = this; //dropdown var $dropdown = $selectManiaEl.data('selectMania-dropdown'); //original select element var $originalSelect = $selectManiaEl.data('selectMania-originalSelect'); //items dropdown var $itemsContainer = $dropdown.find('.select-mania-items'); //options jquery parsing var $options = $(optionsHTML); //get selectMania element values var selectedVals = thisEngine.getVal($selectManiaEl); //loop through selected values selectedVals.forEach(function(val) { $options //search for options matching selected value .filter(function() { return $(this).attr('value') === val.value && $(this).text() === val.text; }) //set matching options as selected .prop('selected', true); }); //build items list $builtItems = Build.buildItemList($options); //if items are meant to be replaced if(replace === true) { //empty old options except selected ones $originalSelect.find('option').remove(':not(:checked)'); //empty items dropdown $itemsContainer.empty(); } //add items to selectMania dropdown $itemsContainer.append($builtItems); //add options to original select element $originalSelect.append($options); //rebind selectMania element Binds.bind($selectManiaEl); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ initAjax //reset selectMania element ajax data and attach ajax function initAjax: function($selectManiaEl, settings) { //if ajax settings are provided to be attached if(typeof settings === 'object') { //attach ajax function if(settings.hasOwnProperty('ajax') && typeof settings.ajax === 'function') { $selectManiaEl.data('selectMania-ajaxFunction', settings.ajax); } //attach ajax data if(settings.hasOwnProperty('data') && typeof settings.data === 'object') { $selectManiaEl.data('selectMania-ajaxData', settings.data); } } //reset ajax data $selectManiaEl.data('selectMania-ajaxPage', 1); $selectManiaEl.data('selectMania-ajaxReady', true); $selectManiaEl.data('selectMania-ajaxScrollDone', false); }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dropdownLoading //display / hide loading icon inside items dropdown dropdownLoading: function($selectManiaEl, hide) { //if hide icon requested var isHide = false; if(typeof hide !== 'undefined' && hide === true) { isHide = true; } //dropdown inner list element $dropdownContainer = $selectManiaEl.find('.select-mania-items-container').first(); //remove loading icon if exists $dropdownContainer.find('.icon-loading-container').remove(); //if show icon requested if(isHide !== true) { //build loading icon var $loadingIcon = $('
'); $loadingIcon.append(''); //insert loading icon $dropdownContainer.append($loadingIcon); } }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ getVal //get parsed selected values getVal: function($selectManiaEl) { var valObjs = []; //loop though values elements $selectManiaEl.find('.select-mania-value').each(function() { //selected value text var thisText = $(this).find('.select-mania-value-text').first().text(); //insert selected value object valObjs.push({ value: $(this).attr('data-value'), text: thisText }); }); //send back parsed selected values return valObjs; }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ clear //clear select values clear: function($selectManiaEl) { //dropdown var $dropdown = $selectManiaEl.data('selectMania-dropdown'); //empty selectMania values $selectManiaEl.find('.select-mania-value').remove(); //unselect items in dropdown $dropdown.find('.select-mania-item').removeClass('select-mania-selected'); //empty values in original select element var $originalSelect = $selectManiaEl.data('selectMania-originalSelect'); if($selectManiaEl.is('.select-mania-multiple')) { $originalSelect.val([]); } else { $originalSelect.val(''); } }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ setVal //set parsed values as selected values setVal: function($selectManiaEl, valObjs) { var thisEngine = this; //original select element var $originalSelect = $selectManiaEl.data('selectMania-originalSelect'); //clear select values before setting provided values thisEngine.clear($selectManiaEl); //if there's more than one value in the values and select is not multiple if(valObjs.length > 1 && !$selectManiaEl.is('.select-mania-multiple')) { //keep only first value valObjs = valObjs.slice(0, 1); } //loop through values valObjs.forEach(function(val) { //parse value object var valObj = $.extend({ value: '', text: '', selected: true }, val); //set value in selectMania element thisEngine.setOneValSelectMania($selectManiaEl, valObj); //set value in original select thisEngine.setOneValOriginal($originalSelect, valObj); }); //update clean values icon display thisEngine.updateClean($selectManiaEl); //rebind selectMania element Binds.bind($selectManiaEl); }, //set one value on selectMania element setOneValSelectMania: function($selectMania, valObj) { //build value element for selectMania element var $value = Build.buildValue(valObj); //insert built value element in selectMania element $selectMania.find('.select-mania-values').append($value); //check if corresponding item exists in dropdown var $searchItem = $selectMania.find('.select-mania-item[data-value="'+valObj.value+'"]').filter(function() { return $(this).text() === valObj.text; }); //if item exists in dropdown if($searchItem.length > 0) { //set item as selected $searchItem.first().addClass('select-mania-selected'); } }, //set one value on original select element setOneValOriginal: function($originalSelect, valObj) { //check if corresponding option exists in original select var $searchOpt = $originalSelect.find('option[value="'+valObj.value+'"]').filter(function() { return $(this).text() === valObj.text; }); //if option doesn't exist in original select if($searchOpt.length < 1) { //build option for original select var $option = Build.buildOption(valObj); //insert built option in original select $originalSelect.append($option); } //if option already exists in original select else { //fond option element var $foundOption = $searchOpt.first(); //set option as selected $foundOption[0].selected = true; } }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ controls //control target element controlTarget: function($target, controls) { //error if element is not a select if($.inArray('isSelect', controls) !== -1 && !$target.is('select')) { console.error('selectMania | invalid select element'); console.log($target[0]); return false; } //error if plugin not initialized if($.inArray('isInitialized', controls) !== -1 && !$target.hasClass('select-mania-original')) { console.error('selectMania | select is not initialized'); console.log($target[0]); return false; } //error if plugin already initialized if($.inArray('notInitialized', controls) !== -1 && $target.hasClass('select-mania-original')) { console.error('selectMania | ignore because already initialized'); console.log($target[0]); return false; } //control method was called on single element if($.inArray('isSingle', controls) !== -1 && $target.length > 1) { console.error('selectMania | check method can be called on single element only'); console.log($target[0]); return false; } //if control ok return true; }, //control selectMania settings controlSettings: function($target, settings) { //control ajax function type if(settings.ajax !== false && typeof settings.ajax !== 'function') { settings.ajax = false; console.error('selectMania | invalid ajax function'); console.log($target[0]); console.log(settings); return false; } //error if invalid size provided if($.inArray(settings.size, ['tiny','small','medium','large']) === -1) { settings.size = 'medium'; console.error('selectMania | invalid size'); console.log($target[0]); console.log(settings); return false; } //error if invalid sroll container provided if(settings.scrollContainer !== null && $(settings.scrollContainer).length < 1) { settings.scrollContainer = null; console.error('selectMania | invalid scroll container'); console.log($target[0]); console.log(settings); return false; } //if control ok return true; }, //control selectMania values controlValues: function($target, values) { //error if values is not an array if(!(values instanceof Array)) { console.error('selectMania | values parameter is not a valid array'); console.log($target[0]); console.log(values); return false; } //if control ok return true; }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ navigateItem //navigate hover to next or previous item in dropdown navigateItem: function($dropdown, nextOrPrevious) { //selectMania element var $selectManiaEl = $dropdown.closest('.select-mania'); //item scrollable list var $itemList = $dropdown.find('.select-mania-items'); //active enabled items var validItemSelector = '.select-mania-item:not(.select-mania-disabled):not(.select-mania-hidden)'; if($selectManiaEl.hasClass('select-mania-multiple')) { validItemSelector += ':not(.select-mania-selected)'; } var $validItems = $dropdown.find(validItemSelector); //current hovered item var $hoveredItem = $dropdown.find(validItemSelector+'.select-mania-hover'); //item to target var $targetItem = $(); //if there is currently a hovered item if($hoveredItem.length > 0) { //if arrow up get previous item if(nextOrPrevious === 'next') { $targetItem = $validItems.slice($validItems.index($hoveredItem) + 1).first(); } //if arrow down get next item else if(nextOrPrevious === 'previous') { $targetItem = $validItems.slice(0, $validItems.index($hoveredItem)).last(); } } //no current hovered item else { //hovers first item $targetItem = $validItems.first(); } //if target item exists hover this item if($targetItem.length > 0) { //remove hover from every item $dropdown.find('.select-mania-item').removeClass('select-mania-hover'); //add hover class to target item $targetItem.addClass('select-mania-hover'); //data for item visibility calculation var $targetItemPosition = $targetItem.position(); var $targetItemHeight = $targetItem.outerHeight(true); var $itemListHeight = $itemList.height(); var $itemListScrollTop = $itemList.scrollTop(); //if target item not visible in item list (above) if($targetItemPosition.top < 0) { //scroll to see item $itemList.scrollTop($itemListScrollTop + $targetItemPosition.top); } //if target item not visible in item list (below) else if($targetItemPosition.top + $targetItemHeight > $itemListHeight) { //scroll to see item $itemList.scrollTop($itemListScrollTop + $targetItemPosition.top + $targetItemHeight - $itemListHeight); } } } }; // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // // ---------------------------------------- BUILD ----------------------------------------- // // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // var Build = { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ build //build selectMania element build: function($originalSelect, settings) { var thisBuild = this; //class for selectMania size var sizeClass = 'select-mania-'+settings.size; //explicit selectMania width style var widthStyle = 'style="width:'+settings.width+';"'; //general selectMania div var $selectManiaEl = $(''); //class for multiple if(settings.multiple) { $selectManiaEl.addClass('select-mania-multiple'); } //class for disabled if(settings.disabled) { $selectManiaEl.addClass('select-mania-disabled'); } //classes for themes if(settings.themes instanceof Array && settings.themes.length > 0) { //loop through themes settings.themes.forEach(function(theme) { //applies theme class $selectManiaEl.addClass('select-mania-theme-'+theme); }); } //class for activated ajax if(settings.ajax !== false) { $selectManiaEl.addClass('select-mania-ajax'); } //attribute for scroll container if(settings.scrollContainer !== null) { $selectManiaEl.attr('data-selectMania-scrollContainer', settings.scrollContainer); } //build inner elements var $innerElements = thisBuild.buildInner(settings); //build dropdown var $dropdown = thisBuild.buildDropdown($originalSelect, settings); //insert elements $selectManiaEl.append($innerElements).append($dropdown); //attach dropdown to select-mania element $selectManiaEl.data('selectMania-dropdown', $dropdown); //attach select-mania element to dropdown $dropdown.data('selectMania-element', $selectManiaEl); //send back selectMania element return $selectManiaEl; }, // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ buildInner //build inner elements buildInner: function(settings) { var thisBuild = this; //inner div var $inner = $(''); //values div var $values = $(''); //insert placeholder var $placeholder = $('