1!function($) { 2 var Selectpicker = function(element, options, e) { 3 if (e ) { 4 e.stopPropagation(); 5 e.preventDefault(); 6 } 7 this.$element = $(element); 8 this.$newElement = null; 9 this.button = null; 10 11 //Merge defaults, options and data-attributes to make our options 12 this.options = $.extend({}, $.fn.selectpicker.defaults, this.$element.data(), typeof options == 'object' && options); 13 14 //If we have no title yet, check the attribute 'title' (this is missed by jq as its not a data-attribute 15 if(this.options.title==null) 16 this.options.title = this.$element.attr('title'); 17 18 //Expose public methods 19 this.val = Selectpicker.prototype.val; 20 this.render = Selectpicker.prototype.render; 21 this.init(); 22 }; 23 24 Selectpicker.prototype = { 25 26 constructor: Selectpicker, 27 28 init: function (e) { 29 var _this = this; 30 this.$element.hide(); 31 this.multiple = this.$element.prop('multiple'); 32 33 34 var classList = this.$element.attr('class') !== undefined ? this.$element.attr('class').split(/\s+/) : ''; 35 var id = this.$element.attr('id'); 36 this.$element.after( this.createView() ); 37 this.$newElement = this.$element.next('.select'); 38 var select = this.$newElement; 39 var menu = this.$newElement.find('.dropdown-menu'); 40 var menuArrow = this.$newElement.find('.dropdown-arrow'); 41 var menuA = menu.find('li > a'); 42 var liHeight = select.addClass('open').find('.dropdown-menu li > a').outerHeight(); 43 select.removeClass('open'); 44 var divHeight = menu.find('li .divider').outerHeight(true); 45 var selectOffset_top = this.$newElement.offset().top; 46 var size = 0; 47 var menuHeight = 0; 48 var selectHeight = this.$newElement.outerHeight(); 49 this.button = this.$newElement.find('> button'); 50 if (id !== undefined) { 51 this.button.attr('id', id); 52 $('label[for="' + id + '"]').click(function(){ select.find('button#'+id).focus(); }) 53 } 54 for (var i = 0; i < classList.length; i++) { 55 if(classList[i] != 'selectpicker') { 56 this.$newElement.addClass(classList[i]); 57 } 58 } 59 //If we are multiple, then add the show-tick class by default 60 if(this.multiple) { 61 this.$newElement.addClass('select-multiple'); 62 } 63 this.button.addClass(this.options.style); 64 menu.addClass(this.options.menuStyle); 65 menuArrow.addClass(function() { 66 if (_this.options.menuStyle) { 67 return _this.options.menuStyle.replace('dropdown-', 'dropdown-arrow-'); 68 } 69 }); 70 this.checkDisabled(); 71 this.checkTabIndex(); 72 this.clickListener(); 73 var menuPadding = parseInt(menu.css('padding-top')) + parseInt(menu.css('padding-bottom')) + parseInt(menu.css('border-top-width')) + parseInt(menu.css('border-bottom-width')); 74 if (this.options.size == 'auto') { 75 function getSize() { 76 var selectOffset_top_scroll = selectOffset_top - $(window).scrollTop(); 77 var windowHeight = window.innerHeight; 78 var menuExtras = menuPadding + parseInt(menu.css('margin-top')) + parseInt(menu.css('margin-bottom')) + 2; 79 var selectOffset_bot = windowHeight - selectOffset_top_scroll - selectHeight - menuExtras; 80 menuHeight = selectOffset_bot; 81 if (select.hasClass('dropup')) { 82 menuHeight = selectOffset_top_scroll - menuExtras; 83 } 84 menuHeight = menuHeight <= 0 ? 500 : menuHeight; 85 menu.css({'max-height' : menuHeight + 'px', 'overflow-y' : 'auto', 'min-height' : liHeight*3 + 'px'}); 86 } 87 getSize(); 88 $(window).resize(getSize); 89 $(window).scroll(getSize); 90 this.$element.bind('DOMNodeInserted', getSize); 91 } else if (this.options.size && this.options.size != 'auto' && menu.find('li').length > this.options.size) { 92 var optIndex = menu.find("li > *").filter(':not(.divider)').slice(0,this.options.size).last().parent().index(); 93 var divLength = menu.find("li").slice(0,optIndex + 1).find('.divider').length; 94 menuHeight = liHeight*this.options.size + divLength*divHeight + menuPadding; 95 menuHeight = menuHeight <= 0 ? 500 : menuHeight; 96 menu.css({'max-height' : menuHeight + 'px', 'overflow-y' : 'scroll'}); 97 } 98 99 //Listen for updates to the DOM and re render... 100 this.$element.bind('DOMNodeInserted', $.proxy(this.reloadLi, this)); 101 102 this.render(); 103 }, 104 105 createDropdown: function() { 106 var drop = 107 "<div style='display:block !important' class='btn-group select'>" + 108 "<button class='btn dropdown-toggle clearfix' data-toggle='dropdown'>" + 109 "<span class='filter-option pull-left'></span> " + 110 "<span class='caret'></span>" + 111 "</button>" + 112 "<ul class='dropdown-menu' role='menu'>" + 113 "</ul>" + 114 "<i class='dropdown-arrow'></i>" + 115 "</div>"; 116 117 return $(drop); 118 }, 119 120 121 createView: function() { 122 var $drop = this.createDropdown(); 123 var $li = this.createLi(); 124 $drop.find('ul').append($li); 125 return $drop; 126 }, 127 128 reloadLi: function() { 129 //Remove all children. 130 this.destroyLi(); 131 //Re build 132 $li = this.createLi(); 133 this.$newElement.find('ul').append( $li ); 134 //render view 135 this.render(); 136 }, 137 138 destroyLi:function() { 139 this.$newElement.find('li').remove(); 140 }, 141 142 createLi: function() { 143 144 var _this = this; 145 var _li = []; 146 var _liA = []; 147 var _liHtml = ''; 148 149 this.$element.find('option').each(function(){ 150 _li.push($(this).text()); 151 }); 152 153 this.$element.find('option').each(function(index) { 154 //Get the class and text for the option 155 var optionClass = $(this).attr("class") !== undefined ? $(this).attr("class") : ''; 156 var text = $(this).text(); 157 var subtext = $(this).data('subtext') !== undefined ? '<small class="muted">'+$(this).data('subtext')+'</small>' : ''; 158 159 //Append any subtext to the main text. 160 text+=subtext; 161 162 if ($(this).parent().is('optgroup') && $(this).data('divider') != true) { 163 if ($(this).index() == 0) { 164 //Get the opt group label 165 var label = $(this).parent().attr('label'); 166 var labelSubtext = $(this).parent().data('subtext') !== undefined ? '<small class="muted">'+$(this).parent().data('subtext')+'</small>' : ''; 167 label += labelSubtext; 168 169 if ($(this)[0].index != 0) { 170 _liA.push( 171 '<div class="divider"></div>'+ 172 '<dt>'+label+'</dt>'+ 173 _this.createA(text, "opt " + optionClass ) 174 ); 175 } else { 176 _liA.push( 177 '<dt>'+label+'</dt>'+ 178 _this.createA(text, "opt " + optionClass )); 179 } 180 } else { 181 _liA.push( _this.createA(text, "opt " + optionClass ) ); 182 } 183 } else if ($(this).data('divider') == true) { 184 _liA.push('<div class="divider"></div>'); 185 } else { 186 _liA.push( _this.createA(text, optionClass ) ); 187 } 188 }); 189 190 if (_li.length > 0) { 191 for (var i = 0; i < _li.length; i++) { 192 var $option = this.$element.find('option').eq(i); 193 _liHtml += "<li rel=" + i + ">" + _liA[i] + "</li>"; 194 } 195 } 196 197 //If we dont have a selected item, and we dont have a title, select the first element so something is set in the button 198 if(this.$element.find('option:selected').length==0 && !_this.options.title) { 199 this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected'); 200 } 201 202 return $(_liHtml); 203 }, 204 205 createA:function(test, classes) { 206 return '<a tabindex="-1" href="#" class="'+classes+'">' + 207 '<span class="pull-left">' + test + '</span>' + 208 '</a>'; 209 210 }, 211 212 render:function() { 213 var _this = this; 214 215 //Set width of select 216 if (this.options.width == 'auto') { 217 var ulWidth = this.$newElement.find('.dropdown-menu').css('width'); 218 this.$newElement.css('width',ulWidth); 219 } else if (this.options.width && this.options.width != 'auto') { 220 this.$newElement.css('width',this.options.width); 221 } 222 223 //Update the LI to match the SELECT 224 this.$element.find('option').each(function(index) { 225 _this.setDisabled(index, $(this).is(':disabled') || $(this).parent().is(':disabled') ); 226 _this.setSelected(index, $(this).is(':selected') ); 227 }); 228 229 230 231 var selectedItems = this.$element.find('option:selected').map(function(index,value) { 232 if($(this).attr('title')!=undefined) { 233 return $(this).attr('title'); 234 } else { 235 return $(this).text(); 236 } 237 }).toArray(); 238 239 //Convert all the values into a comma delimited string 240 var title = selectedItems.join(", "); 241 242 //If this is multi select, and the selectText type is count, the show 1 of 2 selected etc.. 243 if(_this.multiple && _this.options.selectedTextFormat.indexOf('count') > -1) { 244 var max = _this.options.selectedTextFormat.split(">"); 245 if( (max.length>1 && selectedItems.length > max[1]) || (max.length==1 && selectedItems.length>=2)) { 246 title = selectedItems.length +' of ' + this.$element.find('option').length + ' selected'; 247 } 248 } 249 250 //If we dont have a title, then use the default, or if nothing is set at all, use the not selected text 251 if(!title) { 252 title = _this.options.title != undefined ? _this.options.title : _this.options.noneSelectedText; 253 } 254 255 this.$element.next('.select').find('.filter-option').html( title ); 256 }, 257 258 259 260 setSelected:function(index, selected) { 261 if(selected) { 262 this.$newElement.find('li').eq(index).addClass('selected'); 263 } else { 264 this.$newElement.find('li').eq(index).removeClass('selected'); 265 } 266 }, 267 268 setDisabled:function(index, disabled) { 269 if(disabled) { 270 this.$newElement.find('li').eq(index).addClass('disabled'); 271 } else { 272 this.$newElement.find('li').eq(index).removeClass('disabled'); 273 } 274 }, 275 276 checkDisabled: function() { 277 if (this.$element.is(':disabled')) { 278 this.button.addClass('disabled'); 279 this.button.click(function(e) { 280 e.preventDefault(); 281 }); 282 } 283 }, 284 285 checkTabIndex: function() { 286 if (this.$element.is('[tabindex]')) { 287 var tabindex = this.$element.attr("tabindex"); 288 this.button.attr('tabindex', tabindex); 289 } 290 }, 291 292 clickListener: function() { 293 var _this = this; 294 295 $('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); }); 296 297 298 299 this.$newElement.on('click', 'li a', function(e){ 300 var clickedIndex = $(this).parent().index(), 301 $this = $(this).parent(), 302 $select = $this.parents('.select'); 303 304 305 //Dont close on multi choice menu 306 if(_this.multiple) { 307 e.stopPropagation(); 308 } 309 310 e.preventDefault(); 311 312 //Dont run if we have been disabled 313 if ($select.prev('select').not(':disabled') && !$(this).parent().hasClass('disabled')){ 314 //Deselect all others if not multi select box 315 if (!_this.multiple) { 316 $select.prev('select').find('option').removeAttr('selected'); 317 $select.prev('select').find('option').eq(clickedIndex).prop('selected', true).attr('selected', 'selected'); 318 } 319 //Else toggle the one we have chosen if we are multi selet. 320 else { 321 var selected = $select.prev('select').find('option').eq(clickedIndex).prop('selected'); 322 323 if(selected) { 324 $select.prev('select').find('option').eq(clickedIndex).removeAttr('selected'); 325 } else { 326 $select.prev('select').find('option').eq(clickedIndex).prop('selected', true).attr('selected', 'selected'); 327 } 328 } 329 330 331 $select.find('.filter-option').html($this.text()); 332 $select.find('button').focus(); 333 334 // Trigger select 'change' 335 $select.prev('select').trigger('change'); 336 } 337 338 }); 339 340 this.$newElement.on('click', 'li.disabled a, li dt, li .divider', function(e) { 341 e.preventDefault(); 342 e.stopPropagation(); 343 $select = $(this).parent().parents('.select'); 344 $select.find('button').focus(); 345 }); 346 347 this.$element.on('change', function(e) { 348 _this.render(); 349 }); 350 }, 351 352 val:function(value) { 353 354 if(value!=undefined) { 355 this.$element.val( value ); 356 357 this.$element.trigger('change'); 358 return this.$element; 359 } else { 360 return this.$element.val(); 361 } 362 } 363 364 }; 365 366 $.fn.selectpicker = function(option, event) { 367 //get the args of the outer function.. 368 var args = arguments; 369 var value; 370 var chain = this.each(function () { 371 var $this = $(this), 372 data = $this.data('selectpicker'), 373 options = typeof option == 'object' && option; 374 375 if (!data) { 376 $this.data('selectpicker', (data = new Selectpicker(this, options, event))); 377 } else { 378 for(var i in option) { 379 data[i]=option[i]; 380 } 381 } 382 383 if (typeof option == 'string') { 384 //Copy the value of option, as once we shift the arguments 385 //it also shifts the value of option. 386 property = option; 387 if(data[property] instanceof Function) { 388 [].shift.apply(args); 389 value = data[property].apply(data, args); 390 } else { 391 value = data[property]; 392 } 393 } 394 }); 395 396 if(value!=unde
396fined) { 397 return value; 398 } else { 399 return chain; 400 } 401 }; 402 403 $.fn.selectpicker.defaults = { 404 style: null, 405 size: 'auto', 406 title: null, 407 selectedTextFormat : 'values', 408 noneSelectedText : 'Nothing selected', 409 width: null, 410 menuStyle: null, 411 toggleSize: null 412 } 413 414}(window.jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.