1(function($) { 2 'use strict'; 3 4 //<editor-fold desc="Shims"> 5 if (!String.prototype.includes) { 6 (function() { 7 'use strict'; // needed to support `apply`/`call` with `undefined`/`null` 8 var toString = {}.toString, 9 defineProperty = (function() { 10 // IE8 only supports `Object.defineProperty` on DOM elements 11 try { 12 var object = {}, 13 $defineProperty = Object.defineProperty, 14 result = $defineProperty(object, object, object) && $defineProperty; 15 } catch (error) {} 16 return result; 17 }()); 18 var indexOf = ''.indexOf, 19 includes = function(search) { 20 if (this===null) { 21 throw TypeError(); 22 } 23 var string = String(this); 24 if (search && toString.call(search)==='[object RegExp]') { 25 throw TypeError(); 26 } 27 var stringLength = string.length, 28 searchString = String(search), 29 searchLength = searchString.length, 30 position = arguments.length > 1 ? arguments[1] : undefined; 31 // `ToInteger` 32 var pos = position ? Number(position) : 0; 33 if (pos!==pos) { // better `isNaN` 34 pos = 0; 35 } 36 var start = Math.min(Math.max(pos, 0), stringLength); 37 // Avoid the `indexOf` call if no match is possible 38 if (searchLength + start > stringLength) { 39 return false; 40 } 41 return indexOf.call(string, searchString, pos)!==-1; 42 }; 43 if (defineProperty) { 44 defineProperty(String.prototype, 'includes', { 45 'value': includes, 46 'configurable': true, 47 'writable': true 48 }); 49 } else { 50 String.prototype.includes = includes; 51 } 52 }()); 53 } 54 55 if (!String.prototype.startsWith) { 56 (function() { 57 'use strict'; // needed to support `apply`/`call` with `undefined`/`null` 58 var defineProperty = (function() { 59 // IE8 only supports `Object.defineProperty` on DOM elements 60 try { 61 var object = {}, 62 $defineProperty = Object.defineProperty, 63 result = $defineProperty(object, object, object) && $defineProperty; 64 } catch (error) {} 65 return result; 66 }()); 67 var toString = {}.toString, 68 startsWith = function(search) { 69 if (this===null) { 70 throw TypeError(); 71 } 72 var string = String(this); 73 if (search && toString.call(search)==='[object RegExp]') { 74 throw TypeError(); 75 } 76 var stringLength = string.length, 77 searchString = String(search), 78 searchLength = searchString.length, 79 position = arguments.length > 1 ? arguments[1] : undefined; 80 // `ToInteger` 81 var pos = position ? Number(position) : 0; 82 if (pos!==pos) { // better `isNaN` 83 pos = 0; 84 } 85 var start = Math.min(Math.max(pos, 0), stringLength); 86 // Avoid the `indexOf` call if no match is possible 87 if (searchLength + start > stringLength) { 88 return false; 89 } 90 var index = -1; 91 while (++index < searchLength) { 92 if (string.charCodeAt(start + index)!==searchString.charCodeAt(index)) { 93 return false; 94 } 95 } 96 return true; 97 }; 98 if (defineProperty) { 99 defineProperty(String.prototype, 'startsWith', { 100 'value': startsWith, 101 'configurable': true, 102 'writable': true 103 }); 104 } else { 105 String.prototype.startsWith = startsWith; 106 } 107 }()); 108 } 109 //</editor-fold> 110 111 // Case insensitive contains search 112 $.expr[':'].icontains = function(obj, index, meta) { 113 var $obj = $(obj), 114 haystack = ($obj.data('tokens') || $obj.text()).toUpperCase(); 115 return haystack.includes(meta[3].toUpperCase()); 116 }; 117 118 // Case insensitive begins search 119 $.expr[':'].ibegins = function(obj, index, meta) { 120 var $obj = $(obj), 121 haystack = ($obj.data('tokens') || $obj.text()).toUpperCase(); 122 return haystack.startsWith(meta[3].toUpperCase()); 123 }; 124 125 // Case and accent insensitive contains search 126 $.expr[':'].aicontains = function(obj, index, meta) { 127 var $obj = $(obj), 128 haystack = ($obj.data('tokens') || $obj.data('normalizedText') || $obj.text()).toUpperCase(); 129 return haystack.includes(haystack, meta[3]); 130 }; 131 132 // Case and accent insensitive begins search 133 $.expr[':'].aibegins = function(obj, index, meta) { 134 var $obj = $(obj), 135 haystack = ($obj.data('tokens') || $obj.data('normalizedText') || $obj.text()).toUpperCase(); 136 return haystack.startsWith(meta[3].toUpperCase()); 137 }; 138 139 /** 140 * Remove all diatrics from the given text. 141 * @access private 142 * @param {String} text 143 * @returns {String} 144 */ 145 function normalizeToBase(text) { 146 var rExps = [ 147 {re: /[\xC0-\xC6]/g, ch: 'A'}, 148 {re: /[\xE0-\xE6]/g, ch: 'a'}, 149 {re: /[\xC8-\xCB]/g, ch: 'E'}, 150 {re: /[\xE8-\xEB]/g, ch: 'e'}, 151 {re: /[\xCC-\xCF]/g, ch: 'I'}, 152 {re: /[\xEC-\xEF]/g, ch: 'i'}, 153 {re: /[\xD2-\xD6]/g, ch: 'O'},
154 {re: /[\xF2-\xF6]/g, ch: 'o'}, 155 {re: /[\xD9-\xDC]/g, ch: 'U'}, 156 {re: /[\xF9-\xFC]/g, ch: 'u'}, 157 {re: /[\xC7-\xE7]/g, ch: 'c'}, 158 {re: /[\xD1]/g, ch: 'N'}, 159 {re: /[\xF1]/g, ch: 'n'} 160 ]; 161 $.each(rExps, function() { 162 text = text.replace(this.re, this.ch); 163 }); 164 return text; 165 } 166 167 168 function htmlEscape(html) { 169 var escapeMap = { 170 '&': '&', 171 '<': '<', 172 '>': '>', 173 '"': '"', 174 "'": ''', 175 '`': '`' 176 }; 177 var source = '(?:' + Object.keys(escapeMap).join('|') + ')', 178 testRegexp = new RegExp(source), 179 replaceRegexp = new RegExp(source, 'g'), 180 string = html===null ? '' : '' + html; 181 return testRegexp.test(string) ? string.replace(replaceRegexp, function(match) { 182 return escapeMap[match]; 183 }) : string; 184 } 185 186 var Selectpicker = function(element, options, e) { 187 if (e) { 188 e.stopPropagation(); 189 e.preventDefault(); 190 } 191 192 this.$element = $(element); 193 this.$newElement = null; 194 this.$button = null; 195 this.$menu = null; 196 this.$lis = null; 197 this.options = options; 198 199 // If we have no title yet, try to pull it from the HTML title attribute 200 // (jQuery doesn't pick it up as it's not a data-attribute) 201 if (this.options.title===null) { 202 this.options.title = this.$element.attr('title'); 203 } 204 205 // Expose public methods 206 this.val = Selectpicker.prototype.val; 207 this.render = Selectpicker.prototype.render; 208 this.refresh = Selectpicker.prototype.refresh; 209 this.setStyle = Selectpicker.prototype.setStyle; 210 this.selectAll = Selectpicker.prototype.selectAll; 211 this.deselectAll = Selectpicker.prototype.deselectAll; 212 this.destroy = Selectpicker.prototype.remove; 213 this.remove = Selectpicker.prototype.remove; 214 this.show = Selectpicker.prototype.show; 215 this.hide = Selectpicker.prototype.hide; 216 217 this.init(); 218 }; 219 220 Selectpicker.VERSION = '1.6.4'; 221 222 // Part of this is duplicated in i18n/defaults-en_US.js (make sure to update both) 223 Selectpicker.DEFAULTS = { 224 noneSelectedText: 'Nothing selected', 225 noneResultsText: 'No results matched {0}', 226 countSelectedText: function(numSelected, numTotal) { 227 return (numSelected===1) ? '{0} item selected' : '{0} items selected'; 228 }, 229 maxOptionsText: function(numAll, numGroup) { 230 return [ 231 (numAll===1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)', 232 (numGroup===1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)' 233 ]; 234 }, 235 selectAllText: 'Select All', 236 deselectAllText: 'Deselect All', 237 doneButton: false, 238 doneButtonText: 'Close', 239 multipleSeparator: ', ', 240 style: 'btn-default', 241 size: 'auto', 242 title: null, 243 selectedTextFormat: 'values', 244 width: false, 245 container: false, 246 hideDisabled: false, 247 dropupAuto: true, 248 header: false, 249 liveSearch: false, 250 liveSearchPlaceholder: null, 251 liveSearchNormalize: false, 252 liveSearchStyle: 'contains', 253 actionsBox: false, 254 tickIcon: 'glyphicon glyphicon-ok', 255 caretIcon: 'caret', 256 maxOptions: false, 257 mobile: false, 258 selectOnTab: false, 259 dropdownAlignRight: false 260 }; 261 262 Selectpicker.prototype = { 263 264 constructor: Selectpicker, 265 266 init: function() { 267 var that = this, 268 id = this.$element.attr('id'); 269 270 this.$element.hide(); 271 this.multiple = this.$element.prop('multiple'); 272 this.autofocus = this.$element.prop('autofocus'); 273 this.$newElement = this.createView(); 274 this.$element.after(this.$newElement); 275 this.$button = this.$newElement.children('button'); 276 this.$menu = this.$newElement.children('.dropdown-menu'); 277 this.$searchbox = this.$menu.find('input'); 278 279 if (this.options.dropdownAlignRight) 280 this.$menu.addClass('dropdown-menu-right'); 281 282 if (id) { 283 this.$button.attr('data-id', id); 284 $('label[for="' + id + '"]').click(function(e) { 285 e.preventDefault(); 286 that.$button.focus(); 287 }); 288 } 289 290 this.checkDisabled(); 291 this.clickListener(); 292 if (this.options.liveSearch) this.liveSearchListener(); 293 this.render(); 294 this.liHeight(); 295 this.setStyle(); 296 this.setWidth(); 297 if (this.options.container) this.selectPosition(); 298 this.$menu.data('this', this); 299 this.$newElement.data('this', this); 300 if (this.options.mobile) this.mobile(); 301 }, 302 303 createDropdown: function() { 304 // Options 305 // If we are multiple, then add the show-tick class by default 306 var multiple = this.multiple ? ' show-tick' : '', 307 inputGroup = this.$element.parent().hasClass('input-group') ? ' input-group-btn' : '', 308 autofocus = this.autofocus ? ' autofocus' : ''; 309 // Elements 310 var header = this.options.header ? 311 '<div class="popover-title">' + 312 '<button type="button" class="close" aria-hidden="true">×</button>' + this.options.header + 313 '</div>' : '', 314 searchbox = this.options.liveSearch ? 315 '<div class="bs-searchbox">' + 316 '<input type="text" class="form-control" autocomplete="off"' + (null===this.options.liveSearchPlaceholder ? '' : ' placeholder="' + htmlEscape(this.options.liveSearchPlaceholder) + '"') + '>
316' + 317 '</div>' : '', 318 actionsbox = this.multiple && this.options.actionsBox ? 319 '<div class="bs-actionsbox">' + 320 '<div class="btn-group btn-group-sm btn-block">' + 321 '<button class="actions-btn bs-select-all btn btn-default">' + this.options.selectAllText + '</button>' + 322 '<button class="actions-btn bs-deselect-all btn btn-default">' + this.options.deselectAllText + '</button>' + 323 '</div>' + 324 '</div>' : '', 325 donebutton = this.multiple && this.options.doneButton ? 326 '<div class="bs-donebutton">' + 327 '<div class="btn-group btn-block">' + 328 '<button class="btn btn-sm btn-default">' + this.options.doneButtonText + '</button>' + 329 '</div>' + 330 '</div>' : '', 331 drop = 332 '<div class="btn-group bootstrap-select' + multiple + inputGroup + '">' + 333 '<button type="button" class="btn dropdown-toggle" data-toggle="dropdown"' + autofocus + '>' + 334 '<span class="filter-option pull-left"></span> ' + 335 '<span class="' + this.options.caretIcon + '" aria-hidden="true"></span>' + 336 '</button>' + 337 '<div class="dropdown-menu open">' + 338 header + 339 searchbox + 340 actionsbox + 341 '<ul class="dropdown-menu inner" role="menu"></ul>' + 342 donebutton + 343 '</div>' + 344 '</div>'; 345 346 return $(drop); 347 }, 348 349 createView: function() { 350 var $drop = this.createDropdown(), 351 $li = this.createLi(); 352 $drop.find('ul').append($li); 353 return $drop; 354 }, 355 356 reloadLi: function() { 357 // Remove all children 358 this.destroyLi(); 359 // Re-build 360 var $li = this.createLi(); 361 this.$menu.find('ul').append($li); 362 }, 363 364 destroyLi: function() { 365 this.$menu.find('li').remove(); 366 }, 367 368 createLi: function() { 369 var that = this, 370 _li = [], 371 optID = 0; 372 373 // Helper functions 374 /** 375 * @param content 376 * @param [index] 377 * @param [classes] 378 * @param [optgroup] 379 * @returns {string} 380 */ 381 var generateLI = function(content, index, classes, optgroup) { 382 return '<li' + 383 ((typeof classes!=='undefined' & classes!=='') ? ' class="' + classes + '"' : '') + 384 ((typeof index!=='undefined' & index!==null) ? ' data-original-index="' + index + '"' : '') + 385 ((typeof optgroup!=='undefined' & optgroup!==null) ? ' data-optgroup="' + optgroup + '"' : '') + 386 '>' + content + '</li>'; 387 }; 388 389 /** 390 * @param text 391 * @param [classes] 392 * @param [inline] 393 * @param [title] 394 * @param [tokens] 395 * @param [multiple] 396 * @returns {string} 397 */ 398 var generateA = function(text, classes, inline, title, tokens, multiple) { 399 return '<a tabindex="0"' + 400 (typeof title!=='undefined' ? ' title="' + title + '"' : '') + 401 (typeof classes!=='undefined' ? ' class="' + classes + '"' : '') + 402 (typeof inline!=='undefined' ? ' style="' + inline + '"' : '') + 403 ' data-normalized-text="' + normalizeToBase(htmlEscape(text)) + '"' + 404 (typeof tokens!=='undefined' || tokens!==null ? ' data-tokens="' + tokens + '"' : '') + 405 '>' + text + 406 (multiple ? '<span class="' + that.options.tickIcon + ' check-mark" aria-hidden="true"></span>' : '') + 407 '</a>'; 408 }; 409 410 this.$element.find('option').each(function(index) { 411 var $this = $(this); 412 413 // Get the class and text for the option 414 var optionClass = $this.attr('class') || '', 415 inline = $this.attr('style'), 416 title = $this.attr('title'), 417 text = $this.data('content') ? $this.data('content') : $this.html(), 418 tokens = $this.data('tokens') ? $this.data('tokens') : null, 419 subtext = $this.data('subtext') ? '<small class="text-muted">' + $this.data('subtext') + '</small>' : '', 420 icon = $this.data('icon') ? '<span class="' + $this.data('icon') + '" aria-hidden="true"></span> ' : '', 421 isDisabled = $this.is(':disabled') || $this.parent().is(':disabled'); 422 if (icon!=='' && isDisabled) { 423 icon = '<span>' + icon + '</span>'; 424 } 425 426 if ($this.data('thumbnail')) { 427 // Prepare thumbnail 428 text = 429 '<span class="media">' + 430 '<span class="media-left"><img src="' + $this.data('thumbnail') + '" class="media-object" onerror="src=\'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\'"></span>' + 431 '<span class="media-body">
431' + text + '</span>' + 432 '</span>'; 433 } else if (!$this.data('content')) { 434 // Prepend any icon and append any subtext to the main text 435 text = icon + '<span class="text">' + text + subtext + '</span>'; 436 } 437 438 if (that.options.hideDisabled && isDisabled) { 439 return; 440 } 441 442 if ($this.parent().is('optgroup') && $this.data('divider')!==true) { 443 if ($this.index()===0) { // Is it the first option of the optgroup? 444 optID += 1; 445 446 // Get the opt group label 447 var label = $this.parent().attr('label'), 448 labelSubtext = $this.parent().data('subtext') ? '<small class="text-muted">' + $this.parent().data('subtext') + '</small>' : '', 449 labelIcon = $this.parent().data('icon') ? '<span class="' + $this.parent().data('icon') + '" aria-hidden="true"></span> ' : ''; 450 label = labelIcon + '<span class="text">' + label + labelSubtext + '</span>'; 451 452 if (index!==0 && _li.length > 0) { // Is it NOT the first option of the select && are there elements in the dropdown? 453 _li.push(generateLI('', null, 'divider', optID + 'div')); 454 } 455 456 _li.push(generateLI(label, null, 'dropdown-header', optID)); 457 } 458 _li.push(generateLI(generateA(text, 'opt ' + optionClass, inline, title, tokens, that.multiple), index, '', optID)); 459 } else if ($this.data('divider')===true) { 460 _li.push(generateLI('', index, 'divider')); 461 } else if ($this.data('hidden')===true) { 462 _li.push(generateLI(generateA(text, optionClass, inline, title, tokens, that.multiple), index, 'hidden is-hidden')); 463 } else { 464 if ($this.prev().is('optgroup')) _li.push(generateLI('', null, 'divider', optID + 'div')); 465 _li.push(generateLI(generateA(text, optionClass, inline, title, tokens, that.multiple), index)); 466 } 467 }); 468 469 // If we are not multiple, we don't have a selected item, and we don't have 470 // a title, select the first element so something is set in the button 471 if (!this.multiple && this.$element.find('option:selected').length===0 && !this.options.title) { 472 this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected'); 473 } 474 475 return $(_li.join('')); 476 }, 477 478 findLis: function() { 479 if (this.$lis===null) this.$lis = this.$menu.find('li'); 480 return this.$lis; 481 }, 482 483 /** 484 * @param [updateLi] defaults to true 485 */ 486 render: function(updateLi) { 487 var that = this; 488 489 // Update the LI to match the SELECT 490 if (updateLi!==false) { 491 this.$element.find('option').each(function(index) { 492 that.setDisabled(index, $(this).is(':disabled') || $(this).parent().is(':disabled')); 493 that.setSelected(index, $(this).is(':selected')); 494 }); 495 } 496 497 this.tabIndex(); 498 var notDisabled = this.options.hideDisabled ? ':enabled' : '', 499 selectedItems = this.$element.find('option:selected' + notDisabled).map(function() { 500 var $this = $(this), 501 icon = $this.data('icon') ? '<i class="' + $this.data('icon') + '" aria-hidden="true"></i> ' : '', 502 subtext; 503 if ($this.data('subtext') && !that.multiple) { 504 subtext = ' <small class="text-muted">' + $this.data('subtext') + '</small>'; 505 } else { 506 subtext = ''; 507 } 508 if ($this.attr('title')) { 509 return $this.attr('title'); 510 } else if ($this.data('content')) { 511 return $this.data('content'); 512 } else { 513 return icon + $this.html() + subtext; 514 } 515 }).toArray(); 516 517 // Fixes issue in IE10 occurring when no default option is selected and at least one option is disabled 518 // Convert all the values into a comma delimited string 519 var title = !this.multiple ? selectedItems[0] : selectedItems.join(this.options.multipleSeparator); 520 521 // If this is multi-select, and the selectText type is count, then show 1 of 2 selected, etc. 522 if (this.multiple && this.options.selectedTextFormat.indexOf('count') > -1) { 523 var max = this.options.selectedTextFormat.split('>'); 524 if ((max.length > 1 && selectedItems.length > max[1]) || (max.length===1 && selectedItems.length >= 2)) { 525 notDisabled = this.options.hideDisabled ? ', [disabled]' : ''; 526 var totalCount = this.$element.find('option').not('[data-divider="true"], [data-hidden="true"]' + notDisabled).length, 527 tr8nText = (typeof this.options.countSelectedText==='function') ? this.options.countSelectedText(selectedItems.length, totalCount) : this.options.countSelectedText; 528 title = tr8nText.replace('{0}', selectedItems.length.toString()).replace('{1}', totalCount.toString()); 529 } 530 } 531 532 // If we dont have a title, then use the default; or if nothing is set at all, use the not selected text 533 if (!title) { 534 title = this.options.title || this.options.noneSelectedText; 535 } 536 537 // Strip all HTML tags and trim the result 538 this.$button.children('.filter-option').html((!this.multiple || this.options.selectedTextFormat==='values') ? title : this.options.title); 539 this.$button.attr('title', this.options.title); 540 }, 541 542 /** 543 * @param [style] 544 * @param [status] 545 */ 546 setStyle: function(style, status) { 547 if (this.$element.attr('class')) { 548 this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|validate\[.*\]/gi, '')); 549 } 550 551 var buttonClass = style ? style : this.options.style; 552 553 if (status==='add') { 554 this.$button.addClass(buttonClass); 555 } else if (status==='remove') { 556 this.$button.removeClass(buttonClass); 557 } else { 558 this.$button.removeClass(this.options.style); 559 this.$button.addClass(buttonClass); 560 } 561 }, 562 563 liHeight: function() { 564 if (this.options.size===false) return; 565 566 var $selectClone = this.$menu.parent().clone().children('.dropdown-toggle').prop('autofocus', false).end().appendTo('body'), 567 $menuClone = $selectClone.addClass('open').children('.dropdown-menu'), 568 liHeight = $menuClone.find('li').not('.divider, .dropdown-header').filter(':visible').children('a').outerHeight(), 569 headerHeight = this.options.header ? $menuClone.find('.popover-title').outerHeight() : 0, 570 searchHeight = this.options.liveSearch ? $menuClone.find('.bs-searchbox').outerHeight() : 0, 571 actionsHeight = this.options.actionsBox ? $menuClone.find('.bs-actionsbox').outerHeight() : 0, 572 doneButtonHeight = this.multiple ? $menuClone.find('.bs-donebutton').outerHeight() : 0; 573 574 $selectClone.remove(); 575 576 this.$newElement 577 .data('liHeight', liHeight) 578 .data('headerHeight', headerHeight) 579 .data('searchHeight', searchHeight) 580 .data('actionsHeight', actionsHeight) 581 .data('doneButtonHeight', doneButtonHeight); 582 }, 583 584 setSize: function() { 585 this.findLis(); 586 var that = this, 587 $menu = this.$menu, 588 $menuInner = $menu.children('.inner'), 589 selectHeight = this.$newElement.outerHeight(), 590 liHeight = this.$newElement.data('liHeight'), 591 headerHeight = this.$newElement.data('headerHeight'), 592 searchHeight = this.$newElement.data('searchHeight'), 593 actionsHeight = this.$newElement.data('actionsHeight'), 594 doneButtonHeight = this.$newElement.data('doneButtonHeight'), 595 divHeight = this.$lis.filter('.divider').outerHeight(true), 596 menuPadding = parseInt($menu.css('padding-top')) + 597 parseInt($menu.css('padding-bottom')) + 598 parseInt($menu.css('border-top-width')) + 599 parseInt($menu.css('border-bottom-width')), 600 notDisabled = this.options.hideDisabled ? '.disabled' : '', 601 $window = $(window), 602 menuExtras = menuPadding + parseInt($menu.css('margin-top')) + parseInt($menu.css('margin-bottom')) + 2, 603 menuHeight, 604 selectOffsetTop, 605 selectOffsetBot, 606 posVert = function() { 607 // jQuery defines a scrollTop function, but in pure JS it's a property 608 //noinspection JSValidateTypes 609 selectOffsetTop = that.$newElement.offset().top - $window.scrollTop(); 610 selectOffsetBot = $window.height() - selectOffsetTop - selectHeight; 611 }; 612 posVert(); 613 if (this.options.header) $menu.css('padding-top', 0); 614 615 if (this.options.size==='auto') { 616 var getSize = function() { 617 var minHeight, 618 lisVis = that.$lis.not('.hidden'); 619 620 posVert(); 621 menuHeight = selectOffsetBot - menuExtras; 622 623 if (that.options.dropupAuto) { 624 that.$newElement.toggleClass('dropup', selectOffsetTop > selectOffsetBot && (menuHeight - menuExtras) < $menu.height()); 625 } 626 if (that.$newElement.hasClass('dropup')) { 627 menuHeight = selectOffsetTop - menuExtras; 628 } 629 630 if ((lisVis.length + lisVis.filter('.dropdown-header').length) > 3) { 631 minHeight = liHeight * 3 + menuExtras - 2; 632 } else { 633 minHeight = 0; 634 } 635 636 $menu.css({ 637 'max-height': menuHeight + 'px', 638 'overflow': 'hidden', 639 'min-height': minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight + 'px' 640 }); 641 $menuInner.css({ 642 'max-height': menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding + 'px', 643 'overflow-y': 'auto', 644 'min-height': Math.max(minHeight - menuPadding, 0) + 'px' 645 }); 646 }; 647 getSize(); 648 this.$searchbox.off('input.getSize propertychange.getSize').on('input.getSize propertychange.getSize', getSize); 649 $window.off('resize.getSize scroll.getSize').on('resize.getSize scroll.getSize', getSize); 650 } else if (this.options.size && this.options.size!=='auto' && $menu.find('li').not(notDisabled).length > this.options.size) { 651 var optIndex = this.$lis.not('.divider').not(notDisabled).children().slice(0, this.options.size).last().parent().index(), 652 divLength = this.$lis.slice(0, optIndex + 1).filter('.divider').length; 653 menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding; 654 if (that.options.dropupAuto) { 655 //noinspection JSUnusedAssignment 656 this.$newElement.toggleClass('dropup', selectOffsetTop > selectOffsetBot && menuHeight < $menu.height()); 657 } 658 $menu.css({ 659 'max-height': menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight + 'px', 660 'overflow': 'hidden' 661 }); 662 $menuInner.css({ 663 'max-height': menuHeight - menuPadding + 'px', 664 'overflow-y': 'auto' 665 }); 666 } 667 }, 668 669 setWidth: function() { 670 if (this.options.width==='auto') { 671 this.$menu.css('min-width', '0'); 672 673 // Get correct width if element hidden 674 var selectClone = this.$newElement.clone().appendTo('body'), 675 ulWidth = selectClone.children('.dropdown-menu').css('width'), 676 btnWidth = selectClone.css('width', 'auto').children('button').css('width'); 677 selectClone.remove(); 678 679 // Set width to whatever's larger, button title or longest option 680 this.$newElement.css('width', Math.max(parseInt(ulWidth), parseInt(btnWidth)) + 'px'); 681 } else if (this.options.width==='fit') { 682 // Remove inline min-width so width can be changed from 'auto' 683 this.$menu.css('min-width', ''); 684 this.$newElement.css('width', '').addClass('fit-width'); 685 } else if (this.options.width) { 686 // Remove inline min-width so width can be changed from 'auto' 687 this.$menu.css('min-width', ''); 688 this.$newElement.css('width', this.options.width); 689 } else { 690 // Remove inline min-width/width so width can be changed 691 this.$menu.css('min-width', ''); 692 this.$newElement.css('width', ''); 693 } 694 // Remove fit-width class if width is changed programmatically 695 if (this.$newElement.hasClass('fit-width') && this.options.width!=='fit') { 696 this.$newElement.removeClass('fit-width'); 697 } 698 }, 699 700 selectPosition: function() { 701 var that = this, 702 drop = '<div />', 703 $drop = $(drop), 704 pos, 705 actualHeight, 706 getPlacement = function($element) { 707 $drop.addClass($element.attr('class').replace(/form-control/gi, '')).toggleClass('dropup', $element.hasClass('dropup')); 708 pos = $element.offset(); 709 actualHeight = $element.hasClass('dropup') ? 0 : $element[0].offsetHeight; 710 $drop.css({ 711 'top': pos.top + actualHeight, 712 'left': pos.left, 713 'width': $element[0].offsetWidth, 714 'position': 'absolute' 715 }); 716 }; 717 this.$newElement.on('click', function() { 718 if (that.isDisabled()) { 719 return; 720 } 721 getPlacement($(this)); 722 $drop.appendTo(that.options.container); 723 $drop.toggleClass('open', !$(this).hasClass('open')); 724 $drop.append(that.$menu); 725 }); 726 $(window).on('resize scroll', function() { 727 getPlacement(that.$newElement); 728 }); 729 $('html').on('click', function(e) { 730 if ($(e.target).closest(that.$newElement).length < 1) { 731 $drop.removeClass('open'); 732 } 733 }); 734 }, 735 736 setSelected: function(index, selected) { 737 this.findLis(); 738 this.$lis.filter('[data-original-index="' + index + '"]').toggleClass('selected', selected); 739 }, 740 741 setDisabled: function(index, disabled) { 742 this.findLis(); 743 if (disabled) { 744 this.$lis.filter('[data-original-index="' + index + '"]').addClass('disabled').children('a').attr('href', '#').attr('tabindex', -1); 745 } else { 746 this.$lis.filter('[data-original-index="' + index + '"]').removeClass('disabled').children('a').removeAttr('href').attr('tabindex', 0); 747 } 748 }, 749 750 isDisabled: function() { 751 return this.$element.is(':disabled'); 752 }, 753 754 checkDisabled: function() { 755 var that = this; 756 757 if (this.isDisabled()) { 758 this.$button.addClass('disabled').attr('tabindex', -1); 759 } else { 760 if (this.$button.hasClass('disabled')) { 761 // Also sync <li> disabled state with <select> disabled state 762 this.$button.add(this.$menu.find('li')).removeClass('disabled'); 763 } 764 if (this.$button.attr('tabindex')===-1 && !this.$element.data('tabindex')) { 765 this.$button.removeAttr('tabindex'); 766 } 767 } 768 769 this.$button.click(function() { 770 return !that.isDisabled(); 771 }); 772 }, 773 774 tabIndex: function() { 775 if (this.$element.is('[tabindex]')) { 776 this.$element.data('tabindex', this.$element.attr('tabindex')); 777 this.$button.attr('tabindex', this.$element.data('tabindex')); 778 } 779 }, 780 781 clickListener: function() { 782 var that = this; 783 784 this.$newElement.on('touchstart.dropdown', '.dropdown-menu', function(e) { 785 e.stopPropagation(); 786 }); 787 788 this.$newElement.on('click', function() { 789 that.setSize(); 790 if (!that.options.liveSearch && !that.multiple) { 791 setTimeout(function() { 792 that.$menu.find('.selected a').focus(); 793 }, 10); 794 } 795 }); 796 797 this.$menu.on('click', 'li a', function(e) { 798 var $this = $(this), 799 clickedIndex = $this.parent().data('originalIndex'),
800 prevValue = that.$element.val(), 801 prevIndex = that.$element.prop('selectedIndex'); 802 803 // Don't close on multi-select menu 804 if (that.multiple) { 805 e.stopPropagation(); 806 } 807 808 e.preventDefault(); 809 810 // Don't run if we have been disabled 811 if (!that.isDisabled() && !$this.parent().hasClass('disabled')) { 812 var $options = that.$element.find('option'), 813 $option = $options.eq(clickedIndex), 814 state = $option.prop('selected'), 815 $optgroup = $option.parent('optgroup'), 816 maxOptions = that.options.maxOptions, 817 maxOptionsGrp = $optgroup.data('maxOptions') || false; 818 819 if (!that.multiple) { // Deselect all others if not multi-select box 820 $options.prop('selected', false); 821 $option.prop('selected', true); 822 that.$menu.find('.selected').removeClass('selected'); 823 that.setSelected(clickedIndex, true); 824 } else { // Toggle the one we have chosen if we are multi-select 825 $option.prop('selected', !state); 826 that.setSelected(clickedIndex, !state); 827 $this.blur(); 828 829 if (maxOptions!==false || maxOptionsGrp!==false) { 830 var maxReached = maxOptions < $options.filter(':selected').length, 831 maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length; 832 833 if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) { 834 if (maxOptions && maxOptions===1) { 835 $options.prop('selected', false); 836 $option.prop('selected', true); 837 that.$menu.find('.selected').removeClass('selected'); 838 that.setSelected(clickedIndex, true); 839 } else if (maxOptionsGrp && maxOptionsGrp===1) { 840 $optgroup.find('option:selected').prop('selected', false); 841 $option.prop('selected', true); 842 var optgroupID = $this.data('optgroup'); 843 844 that.$menu.find('.selected').has('a[data-optgroup="' + optgroupID + '"]').removeClass('selected'); 845 846 that.setSelected(clickedIndex, true); 847 } else { 848 var maxOptionsArr = (typeof that.options.maxOptionsText==='function') ? that.options.maxOptionsText(maxOptions, maxOptionsGrp) : that.options.maxOptionsText, 849 maxTxt = maxOptionsArr[0].replace('{n}', maxOptions), 850 maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp), 851 $notify = $('<div class="notify"></div>'); 852 // If {var} is set in array, replace it 853 /** @deprecated */ 854 if (maxOptionsArr[2]) { 855 maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]); 856 maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]); 857 } 858 859 $option.prop('selected', false); 860 861 that.$menu.append($notify); 862 863 if (maxOptions && maxReached) { 864 $notify.append($('<div>' + maxTxt + '</div>')); 865 that.$element.trigger('maxReached.bs.select'); 866 } 867 868 if (maxOptionsGrp && maxReachedGrp) { 869 $notify.append($('<div>' + maxTxtGrp + '</div>')); 870 that.$element.trigger('maxReachedGrp.bs.select'); 871 } 872 873 setTimeout(function() { 874 that.setSelected(clickedIndex, false); 875 }, 10); 876 877 $notify.delay(750).fadeOut(300, function() { 878 $(this).remove(); 879 }); 880 } 881 } 882 } 883 } 884 885 if (!that.multiple) { 886 that.$button.focus(); 887 } else if (that.options.liveSearch) { 888 that.$searchbox.focus(); 889 } 890 891 // Trigger select 'change' 892 if ((prevValue!==that.$element.val() && that.multiple) || (prevIndex!==that.$element.prop('selectedIndex') && !that.multiple)) {
893 // Support both native addEventListener() and jQuery change() 894 var event; 895 if (typeof Event==='function') { 896 // For modern browsers 897 event = new Event('change', { 898 'bubbles': true 899 }); 900 } else { 901 // For IE since it doesn't support Event constructor 902 event = document.createEvent('Event'); 903 event.initEvent('change', true, false); 904 } 905 that.$element[0].dispatchEvent(event); 906 } 907 } 908 }); 909 910 this.$menu.on('click', 'li.disabled a, .popover-title, .popover-title :not(.close)', function(e) { 911 if (e.currentTarget===this) { 912 e.preventDefault(); 913 e.stopPropagation(); 914 if (that.options.liveSearch) { 915 that.$searchbox.focus(); 916 } else { 917 that.$button.focus(); 918 } 919 } 920 }); 921 922 this.$menu.on('click', 'li.divider, li.dropdown-header', function(e) { 923 e.preventDefault(); 924 e.stopPropagation(); 925 if (that.options.liveSearch) { 926 that.$searchbox.focus(); 927 } else { 928 that.$button.focus(); 929 } 930 }); 931 932 this.$menu.on('click', '.popover-title .close', function() { 933 that.$button.focus(); 934 }); 935 936 this.$searchbox.on('click', function(e) { 937 e.stopPropagation(); 938 }); 939 940 this.$menu.on('click', '.actions-btn', function(e) { 941 if (that.options.liveSearch) { 942 that.$searchbox.focus(); 943 } else { 944 that.$button.focus(); 945 } 946 947 e.preventDefault(); 948 e.stopPropagation(); 949 950 if ($(this).hasClass('bs-select-all')) { 951 that.selectAll(); 952 } else { 953 that.deselectAll(); 954 } 955 that.$element.change(); 956 }); 957 958 this.$element.change(function() { 959 that.checkDisabled(); 960 that.render(false); 961 }); 962 }, 963 964 liveSearchListener: function() { 965 var that = this, 966 $no_results = $('<li class="no-results"></li>'); 967 968 this.$newElement.on('click.dropdown.data-api touchstart.dropdown.data-api', function() { 969 that.$menu.find('.active').removeClass('active'); 970 if (!!that.$searchbox.val()) { 971 that.$searchbox.val(''); 972 that.$lis.not('.is-hidden').removeClass('hidden'); 973 if (!!$no_results.parent().length) $no_results.remove(); 974 } 975 if (!that.multiple) that.$menu.find('.selected').addClass('active'); 976 setTimeout(function() { 977 that.$searchbox.focus(); 978 }, 10); 979 }); 980 981 this.$searchbox.on('click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api', function(e) { 982 e.stopPropagation(); 983 }); 984 985 this.$searchbox.on('input propertychange', function() { 986 if (that.$searchbox.val()) { 987 var $searchBase = that.$lis.not('.is-hidden').removeClass('hidden').children('a'); 988 if (that.options.liveSearchNormalize) { 989 $searchBase = $searchBase.not(':a' + that._searchStyle() + '(' + normalizeToBase(that.$searchbox.val()) + ')'); 990 } else { 991 $searchBase = $searchBase.not(':' + that._searchStyle() + '(' + that.$searchbox.val() + ')'); 992 } 993 $searchBase.parent().addClass('hidden'); 994 995 that.$lis.filter('.dropdown-header').each(function() { 996 var $this = $(this), 997 optgroup = $this.data('optgroup'); 998 999 if (that.$lis.filter('[data-optgroup=' + optgroup + ']').not($this).not('.hidden').length===0) { 1000 $this.addClass('hidden'); 1001 that.$lis.filter('[data-optgroup=' + optgroup + 'div]').addClass('hidden'); 1002 } 1003 }); 1004 1005 var $lisVisible = that.$lis.not('.hidden'); 1006 1007 // Hide divider if first or last visible, or if followed by another divider 1008 $lisVisible.each(function(index) { 1009 var $this = $(this); 1010 1011 if ($this.hasClass('divider') && ( 1012 $this.index()===$lisVisible.eq(0).index() || 1013 $this.index()===$lisVisible.last().index() || 1014 $lisVisible.eq(index + 1).hasClass('divider'))) { 1015 $this.addClass('hidden'); 1016 } 1017 }); 1018 1019 if (!that.$lis.not('.hidden, .no-results').length) { 1020 if (!!$no_results.parent().length) { 1021 $no_results.remove(); 1022 } 1023 $no_results.html(that.options.noneResultsText.replace('{0}', '"' + htmlEscape(that.$searchbox.val()) + '"')).show(); 1024 that.$menu.append($no_results); 1025 } else if (!!$no_results.parent().length) { 1026 $no_results.remove(); 1027 } 1028 1029 } else { 1030 that.$lis.not('.is-hidden').removeClass('hidden'); 1031 if (!!$no_results.parent().length) { 1032 $no_results.remove(); 1033 } 1034 } 1035 1036 that.$lis.filter('.active').removeClass('active'); 1037 that.$lis.not('.hidden, .divider, .dropdown-header').eq(0).addClass('active').children('a').focus(); 1038 $(this).focus(); 1039 }); 1040 }, 1041 1042 _searchStyle: function() { 1043 var style = 'icontains'; 1044 switch (this.options.liveSearchStyle) { 1045 case 'begins': 1046 break; 1047 case 'startsWith': 1048 style = 'ibegins'; 1049 break; 1050 case 'contains': 1051 break; 1052 default: 1053 // No need to change the default 1054 } 1055 1056 return style; 1057 }, 1058 1059 val: function(value) { 1060 if (value) { 1061 this.$element.val(value); 1062 this.render(); 1063 1064 return this.$element; 1065 } else { 1066 return this.$element.val(); 1067 } 1068 }, 1069 1070 selectAll: function() { 1071 this.findLis(); 1072 this.$element.find('option:enabled').not('[data-divider], [data-hidden]').prop('selected', true); 1073 this.$lis.not('.divider, .dropdown-header, .disabled, .hidden').addClass('selected'); 1074 this.render(false); 1075 }, 1076 1077 deselectAll: function() { 1078 this.findLis(); 1079 this.$element.find('option:enabled').not('[data-divider], [data-hidden]').prop('selected', false); 1080 this.$lis.not('.divider, .dropdown-header, .disabled, .hidden').removeClass('selected'); 1081 this.render(false); 1082 }, 1083 1084 keydown: function(e) { 1085 var $this = $(this), 1086 $parent = $this.is('input') ? $this.parent().parent() : $this.parent(), 1087 $items, 1088 that = $parent.data('this'), 1089 index, 1090 next, 1091 first, 1092 last, 1093 prev, 1094 nextPrev, 1095 prevIndex, 1096 isActive, 1097 keyCodeMap = { 1098 32: ' ', 1099 48: '0', 1100 49: '1', 1101 50: '2', 1102 51: '3', 1103 52: '4', 1104 53: '5', 1105 54: '6', 1106 55: '7', 1107 56: '8', 1108 57: '9', 1109 59: ';', 1110 65: 'a', 1111 66: 'b', 1112 67: 'c', 1113 68: 'd', 1114 69: 'e', 1115 70: 'f', 1116 71: 'g', 1117 72: 'h', 1118 73: 'i', 1119 74: 'j', 1120 75: 'k', 1121 76: 'l', 1122 77: 'm', 1123 78: 'n', 1124 79: 'o', 1125 80: 'p', 1126 81: 'q', 1127 82: 'r', 1128 83: 's', 1129 84: 't', 1130 85: 'u', 1131 86: 'v',
1132 87: 'w', 1133 88: 'x', 1134 89: 'y', 1135 90: 'z', 1136 96: '0', 1137 97: '1', 1138 98: '2', 1139 99: '3', 1140 100: '4', 1141 101: '5', 1142 102: '6', 1143 103: '7', 1144 104: '8', 1145 105: '9' 1146 }; 1147 1148 if (that.options.liveSearch) $parent = $this.parent().parent(); 1149 1150 if (that.options.container) $parent = that.$menu; 1151 1152 $items = $('[role=menu] li a', $parent); 1153 1154 isActive = that.$menu.parent().hasClass('open'); 1155 1156 if (!isActive && /([0-9]|[A-z])/.test(String.fromCharCode(e.keyCode))) { 1157 if (!that.options.container) { 1158 that.setSize(); 1159 that.$menu.parent().addClass('open'); 1160 isActive = true; 1161 } else { 1162 that.$newElement.trigger('click'); 1163 } 1164 that.$searchbox.focus(); 1165 } 1166 1167 if (that.options.liveSearch) { 1168 if (/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && that.$menu.find('.active').length===0) { 1169 e.preventDefault(); 1170 that.$menu.parent().removeClass('open'); 1171 that.$button.focus(); 1172 } 1173 $items = $('[role=menu] li:not(.divider):not(.dropdown-header):visible a', $parent); 1174 if (!$this.val() && !/(38|40)/.test(e.keyCode.toString(10))) { 1175 if ($items.filter('.active').length===0) { 1176 $items = that.$newElement.find('li a'); 1177 if (that.options.liveSearchNormalize) { 1178 $items = $items.filter(':a' + that._searchStyle() + '(' + normalizeToBase(keyCodeMap[e.keyCode]) + ')'); 1179 } else { 1180 $items = $items.filter(':' + that._searchStyle() + '(' + keyCodeMap[e.keyCode] + ')'); 1181 } 1182 } 1183 } 1184 } 1185 1186 if (!$items.length) return; 1187 1188 if (/(38|40)/.test(e.keyCode.toString(10))) { 1189 index = $items.index($items.filter(':focus')); 1190 first = $items.parent(':not(.disabled):visible').first().index(); 1191 last = $items.parent(':not(.disabled):visible').last().index(); 1192 next = $items.eq(index).parent().nextAll(':not(.disabled):visible').eq(0).index(); 1193 prev = $items.eq(index).parent().prevAll(':not(.disabled):visible').eq(0).index(); 1194 nextPrev = $items.eq(next).parent().prevAll(':not(.disabled):visible').eq(0).index(); 1195 1196 if (that.options.liveSearch) { 1197 $items.each(function(i) { 1198 if (!$(this).hasClass('disabled')) { 1199 $(this).data('index', i); 1200 } 1201 }); 1202 index = $items.index($items.filter('.active')); 1203 first = $items.filter(':not(.disabled):visible').first().data('index'); 1204 last = $items.filter(':not(.disabled):visible').last().data('index'); 1205 next = $items.eq(index).nextAll(':not(.disabled):visible').eq(0).data('index'); 1206 prev = $items.eq(index).prevAll(':not(.disabled):visible').eq(0).data('index'); 1207 nextPrev = $items.eq(next).prevAll(':not(.disabled):visible').eq(0).data('index'); 1208 } 1209 1210 prevIndex = $this.data('prevIndex'); 1211 1212 if (e.keyCode===38) { 1213 if (that.options.liveSearch) index -= 1; 1214 if (index!==nextPrev && index > prev) index = prev; 1215 if (index < first) index = first; 1216 if (index===prevIndex) index = last; 1217 } else if (e.keyCode===40) { 1218 if (that.options.liveSearch) index += 1; 1219 if (index===-1) index = 0; 1220 if (index!==nextPrev && index < next) index = next; 1221 if (index > last) index = last; 1222 if (index===prevIndex) index = first; 1223 } 1224 1225 $this.data('prevIndex', index); 1226 1227 if (!that.options.liveSearch) { 1228 $items.eq(index).focus(); 1229 } else { 1230 e.preventDefault(); 1231 if (!$this.hasClass('dropdown-toggle')) { 1232 $items.removeClass('active'); 1233 $items.eq(index).addClass('active').children('a').focus(); 1234 $this.focus(); 1235 } 1236 } 1237 1238 } else if (!$this.is('input')) { 1239 var keyIndex = [], 1240 count = $(document).data('keycount') + 1, 1241 prevKey; 1242 1243 $items.each(function() { 1244 if (!$(this).parent().hasClass('disabled')) { 1245 if ($.trim($(this).text().toLowerCase()).substring(0, 1)===keyCodeMap[e.keyCode]) { 1246 keyIndex.push($(this).parent().index()); 1247 } 1248 } 1249 }); 1250 1251 $(document).data('keycount', count); 1252 prevKey = $.trim($(':focus').text().toLowerCase()).substring(0, 1); 1253 1254 if (prevKey!==keyCodeMap[e.keyCode]) { 1255 count = 1; 1256 $(document).data('keycount', count); 1257 } else if (count >= keyIndex.length) { 1258 $(document).data('keycount', 0); 1259 if (count > keyIndex.length) count = 1; 1260 } 1261 1262 $items.eq(keyIndex[count - 1]).focus(); 1263 } 1264 1265 // Select focused option if "Enter", "Spacebar" or "Tab" (when selectOnTab is true) is pressed inside the menu 1266 if ((/(13|32)/.test(e.keyCode.toString(10)) || (/(^9$)/.test(e.keyCode.toString(10)) && that.options.selectOnTab)) && isActive) { 1267 if (!/(32)/.test(e.keyCode.toString(10))) e.preventDefault(); 1268 if (!that.options.liveSearch) { 1269 var elem = $(':focus'); 1270 elem.click(); 1271 // Bring back focus for multiselects 1272 elem.focus(); 1273 // Prevent screen from scrolling if the user hit the spacebar 1274 e.preventDefault(); 1275 } else if (!/(32)/.test(e.keyCode.toString(10))) { 1276 that.$menu.find('.active a').click(); 1277 $this.focus(); 1278 } 1279 $(document).data('keycount', 0); 1280 } 1281 1282 if ((/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && (that.multiple || that.options.liveSearch)) || (/(27)/.test(e.keyCode.toString(10)) && !isActive)) { 1283 that.$menu.parent().removeClass('open'); 1284 that.$button.focus(); 1285 } 1286 }, 1287 1288 mobile: function() { 1289 this.$element.addClass('mobile-device').appendTo(this.$newElement); 1290 if (this.options.container) this.$menu.hide(); 1291 }, 1292 1293 refresh: function() { 1294 this.$lis = null; 1295 this.reloadLi(); 1296 this.render(); 1297 this.setWidth(); 1298 this.setStyle(); 1299 this.checkDisabled(); 1300 this.liHeight(); 1301 }, 1302 1303 hide: function() { 1304 this.$newElement.hide(); 1305 }, 1306 1307 show: function() { 1308 this.$newElement.show(); 1309 }, 1310 1311 remove: function() { 1312 this.$newElement.remove(); 1313 this.$element.remove(); 1314 } 1315 }; 1316 1317 // SELECTPICKER PLUGIN DEFINITION 1318 // ============================== 1319 function Plugin(option, event) { 1320 // Get the args of the outer function 1321 var args = arguments; 1322 // The arguments of the function are explicitly re-defined from the argument list, 1323 // because the shift causes them to get lost/corrupted in android 2.3 and IE9 #715 #775 1324 var _option = option, 1325 _event = event; 1326 [].shift.apply(args); 1327 1328 var value, 1329 chain = this.each(function() { 1330 var $this = $(this); 1331 if ($this.is('select')) { 1332 var data = $this.data('selectpicker'), 1333 options = typeof _option==='object' && _option; 1334 1335 if (!data) { 1336 var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, $this.data(), options); 1337 $this.data('selectpicker', (data = new Selectpicker(this, config, _event))); 1338 } else if (options) { 1339 for (var i in options) { 1340 if (options.hasOwnProperty(i)) { 1341 data.options[i] = options[i]; 1342 } 1343 } 1344 } 1345 1346 if (typeof _option==='string') { 1347 if (data[_option] instanceof Function) { 1348 value = data[_option].apply(data, args); 1349 } else { 1350 value = data.options[_option]; 1351 } 1352 } 1353 } 1354 }); 1355 1356 if (value) { 1357 //noinspection JSUnusedAssignment 1358 return value; 1359 } else { 1360 return chain; 1361 } 1362 } 1363 1364 var old = $.fn.selectpicker; 1365 $.fn.selectpicker = Plugin; 1366 $.fn.selectpicker.Constructor = Selectpicker; 1367 1368 // SELECTPICKER NO CONFLICT 1369 // ======================== 1370 $.fn.selectpicker.noConflict = function() { 1371 $.fn.selectpicker = old; 1372 return this; 1373 }; 1374 1375 $(document) 1376 .data('keycount', 0) 1377 .on('keydown', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bs-searchbox input', Selectpicker.prototype.keydown) 1378 .on('focusin.modal', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bs-searchbox input', function(e) { 1379 e.stopPropagation(); 1380 }); 1381 1382 // SELECTPICKER DATA-API 1383 // ===================== 1384 $(window).on('load.bs.select.data-api', function() { 1385 $('.selectpicker').each(function() { 1386 var $selectpicker = $(this); 1387 Plugin.call($selectpicker, $selectpicker.data()); 1388 }) 1389 }); 1390})(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.