File indexing completed on 2024-05-19 06:00:16
0001 !function($) { 0002 var Selectpicker = function(element, options, e) { 0003 if (e ) { 0004 e.stopPropagation(); 0005 e.preventDefault(); 0006 } 0007 this.$element = $(element); 0008 this.$newElement = null; 0009 this.button = null; 0010 0011 //Merge defaults, options and data-attributes to make our options 0012 this.options = $.extend({}, $.fn.selectpicker.defaults, this.$element.data(), typeof options == 'object' && options); 0013 0014 //If we have no title yet, check the attribute 'title' (this is missed by jq as its not a data-attribute 0015 if(this.options.title==null) 0016 this.options.title = this.$element.attr('title'); 0017 0018 //Expose public methods 0019 this.val = Selectpicker.prototype.val; 0020 this.render = Selectpicker.prototype.render; 0021 this.init(); 0022 }; 0023 0024 Selectpicker.prototype = { 0025 0026 constructor: Selectpicker, 0027 0028 init: function (e) { 0029 var _this = this; 0030 this.$element.hide(); 0031 this.multiple = this.$element.prop('multiple'); 0032 0033 0034 var classList = this.$element.attr('class') !== undefined ? this.$element.attr('class').split(/\s+/) : ''; 0035 var id = this.$element.attr('id'); 0036 this.$element.after( this.createView() ); 0037 this.$newElement = this.$element.next('.select'); 0038 var select = this.$newElement; 0039 var menu = this.$newElement.find('.dropdown-menu'); 0040 var menuArrow = this.$newElement.find('.dropdown-arrow'); 0041 var menuA = menu.find('li > a'); 0042 var liHeight = select.addClass('open').find('.dropdown-menu li > a').outerHeight(); 0043 select.removeClass('open'); 0044 var divHeight = menu.find('li .divider').outerHeight(true); 0045 var selectOffset_top = this.$newElement.offset().top; 0046 var size = 0; 0047 var menuHeight = 0; 0048 var selectHeight = this.$newElement.outerHeight(); 0049 this.button = this.$newElement.find('> button'); 0050 if (id !== undefined) { 0051 this.button.attr('id', id); 0052 $('label[for="' + id + '"]').click(function(){ select.find('button#'+id).focus(); }) 0053 } 0054 for (var i = 0; i < classList.length; i++) { 0055 if(classList[i] != 'selectpicker') { 0056 this.$newElement.addClass(classList[i]); 0057 } 0058 } 0059 //If we are multiple, then add the show-tick class by default 0060 if(this.multiple) { 0061 this.$newElement.addClass('select-multiple'); 0062 } 0063 this.button.addClass(this.options.style); 0064 menu.addClass(this.options.menuStyle); 0065 menuArrow.addClass(function() { 0066 if (_this.options.menuStyle) { 0067 return _this.options.menuStyle.replace('dropdown-', 'dropdown-arrow-'); 0068 } 0069 }); 0070 this.checkDisabled(); 0071 this.checkTabIndex(); 0072 this.clickListener(); 0073 var menuPadding = parseInt(menu.css('padding-top')) + parseInt(menu.css('padding-bottom')) + parseInt(menu.css('border-top-width')) + parseInt(menu.css('border-bottom-width')); 0074 if (this.options.size == 'auto') { 0075 function getSize() { 0076 var selectOffset_top_scroll = selectOffset_top - $(window).scrollTop(); 0077 var windowHeight = window.innerHeight; 0078 var menuExtras = menuPadding + parseInt(menu.css('margin-top')) + parseInt(menu.css('margin-bottom')) + 2; 0079 var selectOffset_bot = windowHeight - selectOffset_top_scroll - selectHeight - menuExtras; 0080 menuHeight = selectOffset_bot; 0081 if (select.hasClass('dropup')) { 0082 menuHeight = selectOffset_top_scroll - menuExtras; 0083 } 0084 menu.css({'max-height' : menuHeight + 'px', 'overflow-y' : 'auto', 'min-height' : liHeight*3 + 'px'}); 0085 } 0086 getSize(); 0087 $(window).resize(getSize); 0088 $(window).scroll(getSize); 0089 this.$element.bind('DOMNodeInserted', getSize); 0090 } else if (this.options.size && this.options.size != 'auto' && menu.find('li').length > this.options.size) { 0091 var optIndex = menu.find("li > *").filter(':not(.divider)').slice(0,this.options.size).last().parent().index(); 0092 var divLength = menu.find("li").slice(0,optIndex + 1).find('.divider').length; 0093 menuHeight = liHeight*this.options.size + divLength*divHeight + menuPadding; 0094 menu.css({'max-height' : menuHeight + 'px', 'overflow-y' : 'scroll'}); 0095 } 0096 0097 //Listen for updates to the DOM and re render... 0098 this.$element.bind('DOMNodeInserted', $.proxy(this.reloadLi, this)); 0099 0100 this.render(); 0101 }, 0102 0103 createDropdown: function() { 0104 var drop = 0105 "<div class='btn-group select'>" + 0106 "<i class='dropdown-arrow'></i>" + 0107 "<button class='btn dropdown-toggle clearfix' data-toggle='dropdown'>" + 0108 "<span class='filter-option pull-left'></span> " + 0109 "<span class='caret'></span>" + 0110 "</button>" + 0111 "<ul class='dropdown-menu' role='menu'>" + 0112 "</ul>" + 0113 "</div>"; 0114 0115 return $(drop); 0116 }, 0117 0118 0119 createView: function() { 0120 var $drop = this.createDropdown(); 0121 var $li = this.createLi(); 0122 $drop.find('ul').append($li); 0123 return $drop; 0124 }, 0125 0126 reloadLi: function() { 0127 //Remove all children. 0128 this.destroyLi(); 0129 //Re build 0130 $li = this.createLi(); 0131 this.$newElement.find('ul').append( $li ); 0132 //render view 0133 this.render(); 0134 }, 0135 0136 destroyLi:function() { 0137 this.$newElement.find('li').remove(); 0138 }, 0139 0140 createLi: function() { 0141 0142 var _this = this; 0143 var _li = []; 0144 var _liA = []; 0145 var _liHtml = ''; 0146 0147 this.$element.find('option').each(function(){ 0148 _li.push($(this).text()); 0149 }); 0150 0151 this.$element.find('option').each(function(index) { 0152 //Get the class and text for the option 0153 var optionClass = $(this).attr("class") !== undefined ? $(this).attr("class") : ''; 0154 var text = $(this).text(); 0155 var subtext = $(this).data('subtext') !== undefined ? '<small class="muted">'+$(this).data('subtext')+'</small>' : ''; 0156 0157 //Append any subtext to the main text. 0158 text+=subtext; 0159 0160 if ($(this).parent().is('optgroup') && $(this).data('divider') != true) { 0161 if ($(this).index() == 0) { 0162 //Get the opt group label 0163 var label = $(this).parent().attr('label'); 0164 var labelSubtext = $(this).parent().data('subtext') !== undefined ? '<small class="muted">'+$(this).parent().data('subtext')+'</small>' : ''; 0165 label += labelSubtext; 0166 0167 if ($(this)[0].index != 0) { 0168 _liA.push( 0169 '<div class="divider"></div>'+ 0170 '<dt>'+label+'</dt>'+ 0171 _this.createA(text, "opt " + optionClass ) 0172 ); 0173 } else { 0174 _liA.push( 0175 '<dt>'+label+'</dt>'+ 0176 _this.createA(text, "opt " + optionClass )); 0177 } 0178 } else { 0179 _liA.push( _this.createA(text, "opt " + optionClass ) ); 0180 } 0181 } else if ($(this).data('divider') == true) { 0182 _liA.push('<div class="divider"></div>'); 0183 } else { 0184 _liA.push( _this.createA(text, optionClass ) ); 0185 } 0186 }); 0187 0188 if (_li.length > 0) { 0189 for (var i = 0; i < _li.length; i++) { 0190 var $option = this.$element.find('option').eq(i); 0191 _liHtml += "<li rel=" + i + ">" + _liA[i] + "</li>"; 0192 } 0193 } 0194 0195 //If we dont have a selected item, and we dont have a title, select the first element so something is set in the button 0196 if(this.$element.find('option:selected').length==0 && !_this.options.title) { 0197 this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected'); 0198 } 0199 0200 return $(_liHtml); 0201 }, 0202 0203 createA:function(test, classes) { 0204 return '<a tabindex="-1" href="#" class="'+classes+'">' + 0205 '<span class="pull-left">' + test + '</span>' + 0206 '</a>'; 0207 0208 }, 0209 0210 render:function() { 0211 var _this = this; 0212 0213 //Set width of select 0214 if (this.options.width == 'auto') { 0215 var ulWidth = this.$newElement.find('.dropdown-menu').css('width'); 0216 this.$newElement.css('width',ulWidth); 0217 } else if (this.options.width && this.options.width != 'auto') { 0218 this.$newElement.css('width',this.options.width); 0219 } 0220 0221 //Update the LI to match the SELECT 0222 this.$element.find('option').each(function(index) { 0223 _this.setDisabled(index, $(this).is(':disabled') || $(this).parent().is(':disabled') ); 0224 _this.setSelected(index, $(this).is(':selected') ); 0225 }); 0226 0227 0228 0229 var selectedItems = this.$element.find('option:selected').map(function(index,value) { 0230 if($(this).attr('title')!=undefined) { 0231 return $(this).attr('title'); 0232 } else { 0233 return $(this).text(); 0234 } 0235 }).toArray(); 0236 0237 //Convert all the values into a comma delimited string 0238 var title = selectedItems.join(", "); 0239 0240 //If this is multi select, and the selectText type is count, the show 1 of 2 selected etc.. 0241 if(_this.multiple && _this.options.selectedTextFormat.indexOf('count') > -1) { 0242 var max = _this.options.selectedTextFormat.split(">"); 0243 if( (max.length>1 && selectedItems.length > max[1]) || (max.length==1 && selectedItems.length>=2)) { 0244 title = selectedItems.length +' of ' + this.$element.find('option').length + ' selected'; 0245 } 0246 } 0247 0248 //If we dont have a title, then use the default, or if nothing is set at all, use the not selected text 0249 if(!title) { 0250 title = _this.options.title != undefined ? _this.options.title : _this.options.noneSelectedText; 0251 } 0252 0253 this.$element.next('.select').find('.filter-option').html( title ); 0254 }, 0255 0256 0257 0258 setSelected:function(index, selected) { 0259 if(selected) { 0260 this.$newElement.find('li').eq(index).addClass('selected'); 0261 } else { 0262 this.$newElement.find('li').eq(index).removeClass('selected'); 0263 } 0264 }, 0265 0266 setDisabled:function(index, disabled) { 0267 if(disabled) { 0268 this.$newElement.find('li').eq(index).addClass('disabled'); 0269 } else { 0270 this.$newElement.find('li').eq(index).removeClass('disabled'); 0271 } 0272 }, 0273 0274 checkDisabled: function() { 0275 if (this.$element.is(':disabled')) { 0276 this.button.addClass('disabled'); 0277 this.button.click(function(e) { 0278 e.preventDefault(); 0279 }); 0280 } 0281 }, 0282 0283 checkTabIndex: function() { 0284 if (this.$element.is('[tabindex]')) { 0285 var tabindex = this.$element.attr("tabindex"); 0286 this.button.attr('tabindex', tabindex); 0287 } 0288 }, 0289 0290 clickListener: function() { 0291 var _this = this; 0292 0293 $('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); }); 0294 0295 0296 0297 this.$newElement.on('click', 'li a', function(e){ 0298 var clickedIndex = $(this).parent().index(), 0299 $this = $(this).parent(), 0300 $select = $this.parents('.select'); 0301 0302 0303 //Dont close on multi choice menu 0304 if(_this.multiple) { 0305 e.stopPropagation(); 0306 } 0307 0308 e.preventDefault(); 0309 0310 //Dont run if we have been disabled 0311 if ($select.prev('select').not(':disabled') && !$(this).parent().hasClass('disabled')){ 0312 //Deselect all others if not multi select box 0313 if (!_this.multiple) { 0314 $select.prev('select').find('option').removeAttr('selected'); 0315 $select.prev('select').find('option').eq(clickedIndex).prop('selected', true).attr('selected', 'selected'); 0316 } 0317 //Else toggle the one we have chosen if we are multi selet. 0318 else { 0319 var selected = $select.prev('select').find('option').eq(clickedIndex).prop('selected'); 0320 0321 if(selected) { 0322 $select.prev('select').find('option').eq(clickedIndex).removeAttr('selected'); 0323 } else { 0324 $select.prev('select').find('option').eq(clickedIndex).prop('selected', true).attr('selected', 'selected'); 0325 } 0326 } 0327 0328 0329 $select.find('.filter-option').html($this.text()); 0330 $select.find('button').focus(); 0331 0332 // Trigger select 'change' 0333 $select.prev('select').trigger('change'); 0334 } 0335 0336 }); 0337 0338 this.$newElement.on('click', 'li.disabled a, li dt, li .divider', function(e) { 0339 e.preventDefault(); 0340 e.stopPropagation(); 0341 $select = $(this).parent().parents('.select'); 0342 $select.find('button').focus(); 0343 }); 0344 0345 this.$element.on('change', function(e) { 0346 _this.render(); 0347 }); 0348 }, 0349 0350 val:function(value) { 0351 0352 if(value!=undefined) { 0353 this.$element.val( value ); 0354 0355 this.$element.trigger('change'); 0356 return this.$element; 0357 } else { 0358 return this.$element.val(); 0359 } 0360 } 0361 0362 }; 0363 0364 $.fn.selectpicker = function(option, event) { 0365 //get the args of the outer function.. 0366 var args = arguments; 0367 var value; 0368 var chain = this.each(function () { 0369 var $this = $(this), 0370 data = $this.data('selectpicker'), 0371 options = typeof option == 'object' && option; 0372 0373 if (!data) { 0374 $this.data('selectpicker', (data = new Selectpicker(this, options, event))); 0375 } else { 0376 for(var i in option) { 0377 data[i]=option[i]; 0378 } 0379 } 0380 0381 if (typeof option == 'string') { 0382 //Copy the value of option, as once we shift the arguments 0383 //it also shifts the value of option. 0384 property = option; 0385 if(data[property] instanceof Function) { 0386 [].shift.apply(args); 0387 value = data[property].apply(data, args); 0388 } else { 0389 value = data[property]; 0390 } 0391 } 0392 }); 0393 0394 if(value!=undefined) { 0395 return value; 0396 } else { 0397 return chain; 0398 } 0399 }; 0400 0401 $.fn.selectpicker.defaults = { 0402 style: null, 0403 size: 'auto', 0404 title: null, 0405 selectedTextFormat : 'values', 0406 noneSelectedText : 'Nothing selected', 0407 width: null, 0408 menuStyle: null, 0409 toggleSize: null 0410 } 0411 0412 }(window.jQuery);