vendor: 10,739 bytes, lines 1-415
1/*! 2 * Bootstrap-select v1.13.2 (https://developer.snapappointments.com/bootstrap-select) 3 * 4 * Copyright 2012-2018 SnapAppointments, LLC 5 * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE) 6 */ 7 8(function(root, factory) { 9 if (root === undefined && window !== undefined) root = window; 10 if (typeof define === 'function' && define.amd) { 11 // AMD. Register as an anonymous module unless amdModuleId is set 12 define(["jquery"], function(a0) { 13 return (factory(a0)); 14 }); 15 } else if (typeof module === 'object' && module.exports) { 16 // Node. Does not work with strict CommonJS, but 17 // only CommonJS-like environments that support module.exports, 18 // like Node. 19 module.exports = factory(require("jquery")); 20 } else { 21 factory(root["jQuery"]); 22 } 23}(this, function(jQuery) { 24 25 (function($) { 26 'use strict'; 27 28 var testElement = document.createElement('_'); 29 30 testElement.classList.toggle('c3', false); 31 32 // Polyfill for IE 10 and Firefox <24, where classList.toggle does not 33 // support the second argument. 34 if (testElement.classList.contains('c3')) { 35 var _toggle = DOMTokenList.prototype.toggle; 36 37 DOMTokenList.prototype.toggle = function(token, force) { 38 if (1 in arguments && !this.contains(token) === !force) { 39 return force; 40 } else { 41 return _toggle.call(this, token); 42 } 43 }; 44 } 45 46 // shallow array comparison 47 function isEqual(array1, array2) { 48 return array1.length === array2.length && array1.every(function(element, index) { 49 return element === array2[index]; 50 }); 51 }; 52 53 //<editor-fold desc="Shims"> 54 if (!String.prototype.startsWith) { 55 (function() { 56 'use strict'; // needed to support `apply`/`call` with `undefined`/`null` 57 var defineProperty = (function() { 58 // IE 8 only supports `Object.defineProperty` on DOM elements 59 try { 60 var object = {}; 61 var $defineProperty = Object.defineProperty; 62 var result = $defineProperty(object, object, object) && $defineProperty; 63 } catch (error) {} 64 return result; 65 }()); 66 var toString = {}.toString; 67 var startsWith = function(search) { 68 if (this == null) { 69 throw new TypeError(); 70 } 71 var string = String(this); 72 if (search && toString.call(search) == '[object RegExp]') { 73 throw new TypeError(); 74 } 75 var stringLength = string.length; 76 var searchString = String(search); 77 var searchLength = searchString.length; 78 var position = arguments.length > 1 ? arguments[1] : undefined; 79 // `ToInteger` 80 var pos = position ? Number(position) : 0; 81 if (pos != pos) { // better `isNaN` 82 pos = 0; 83 } 84 var start = Math.min(Math.max(pos, 0), stringLength); 85 // Avoid the `indexOf` call if no match is possible 86 if (searchLength + start > stringLength) { 87 return false; 88 } 89 var index = -1; 90 while (++index < searchLength) { 91 if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) { 92 return false; 93 } 94 } 95 return true; 96 }; 97 if (defineProperty) { 98 defineProperty(String.prototype, 'startsWith', { 99 'value': startsWith, 100 'configurable': true, 101 'writable': true 102 }); 103 } else { 104 String.prototype.startsWith = startsWith; 105 } 106 }()); 107 } 108 109 if (!Object.keys) { 110 Object.keys = function( 111 o, // object 112 k, // key 113 r // result array 114 ) { 115 // initialize object and result 116 r = []; 117 // iterate over object keys 118 for (k in o) 119 // fill result array with non-prototypical keys 120 r.hasOwnProperty.call(o, k) && r.push(k); 121 // return result 122 return r; 123 }; 124 } 125 126 // much faster than $.val() 127 function getSelectValues(select) { 128 var result = []; 129 var options = select && select.options; 130 var opt; 131 132 if (select.multiple) { 133 for (var i = 0, len = options.length; i < len; i++) { 134 opt = options[i]; 135 136 if (opt.selected) { 137 result.push(opt.value || opt.text); 138 } 139 } 140 } else { 141 result = select.value; 142 } 143 144 return result; 145 } 146 147 // set data-selected on select element if the value has been programmatically selected 148 // prior to initialization of bootstrap-select 149 // * consider removing or replacing an alternative method * 150 var valHooks = { 151 useDefault: false, 152 _set: $.valHooks.select.set 153 }; 154 155 $.valHooks.select.set = function(elem, value) { 156 if (value && !valHooks.useDefault) $(elem).data('selected', true); 157 158 return valHooks._set.apply(this, arguments); 159 }; 160 161 var changed_arguments = null; 162 163 var EventIsSupported = (function() { 164 try { 165 new Event('change'); 166 return true; 167 } catch (e) { 168 return false; 169 } 170 })(); 171 172 $.fn.triggerNative = function(eventName) { 173 var el = this[0], 174 event; 175 176 if (el.dispatchEvent) { // for modern browsers & IE9+ 177 if (EventIsSupported) { 178 // For modern browsers 179 event = new Event(eventName, { 180 bubbles: true 181 }); 182 } else { 183 // For IE since it doesn't support Event constructor 184 event = document.createEvent('Event'); 185 event.initEvent(eventName, true, false); 186 } 187 188 el.dispatchEvent(event); 189 } else if (el.fireEvent) { // for IE8 190 event = document.createEventObject(); 191 event.eventType = eventName; 192 el.fireEvent('on' + eventName, event); 193 } else { 194 // fall back to jQuery.trigger 195 this.trigger(eventName); 196 } 197 }; 198 //</editor-fold> 199 200 function stringSearch(li, searchString, method, normalize) { 201 var stringTypes = [ 202 'content', 203 'subtext', 204 'tokens' 205 ], 206 searchSuccess = false; 207 208 for (var i = 0; i < stringTypes.length; i++) { 209 var stringType = stringTypes[i], 210 string = li[stringType]; 211 212 if (string) { 213 string = string.toString(); 214 215 // Strip HTML tags. This isn't perfect, but it's much faster than any other method 216 if (stringType === 'content') { 217 string = string.replace(/<[^>]+>/g, ''); 218 } 219 220 if (normalize) string = normalizeToBase(string); 221 string = string.toUpperCase(); 222 223 if (method === 'contains') { 224 searchSuccess = string.indexOf(searchString) >= 0; 225 } else { 226 searchSuccess = string.startsWith(searchString); 227 } 228 229 if (searchSuccess) break; 230 } 231 } 232 233 return searchSuccess; 234 } 235 236 function toInteger(value) { 237 return parseInt(value, 10) || 0; 238 } 239 240 /** 241 * Remove all diatrics from the given text. 242 * @access private 243 * @param {String} text 244 * @returns {String} 245 */ 246 function normalizeToBase(text) { 247 var rExps = [{ 248 re: /[\xC0-\xC6]/g, 249 ch: "A" 250 }, 251 { 252 re: /[\xE0-\xE6]/g, 253 ch: "a" 254 }, 255 { 256 re: /[\xC8-\xCB]/g, 257 ch: "E" 258 }, 259 { 260 re: /[\xE8-\xEB]/g, 261 ch: "e" 262 }, 263 { 264 re: /[\xCC-\xCF]/g, 265 ch: "I" 266 }, 267 { 268 re: /[\xEC-\xEF]/g, 269 ch: "i" 270 }, 271 { 272 re: /[\xD2-\xD6]/g, 273 ch: "O" 274 }, 275 { 276 re: /[\xF2-\xF6]/g, 277 ch: "o" 278 }, 279 { 280 re: /[\xD9-\xDC]/g, 281 ch: "U" 282 }, 283 { 284 re: /[\xF9-\xFC]/g, 285 ch: "u" 286 }, 287 { 288 re: /[\xC7-\xE7]/g, 289 ch: "c" 290 }, 291 { 292 re: /[\xD1]/g, 293 ch: "N" 294 }, 295 { 296 re: /[\xF1]/g, 297 ch: "n" 298 } 299 ]; 300 $.each(rExps, function() { 301 text = text ? text.replace(this.re, this.ch) : ''; 302 }); 303 return text; 304 } 305 306 307 // List of HTML entities for escaping. 308 var escapeMap = { 309 '&': '&', 310 '<': '<', 311 '>': '>', 312 '"': '"', 313 "'": ''', 314 '`': '`' 315 }; 316 317 var unescapeMap = { 318 '&': '&', 319 '<': '<', 320 '>': '>', 321 '"': '"', 322 ''': "'", 323 '`': '`' 324 }; 325 326 // Functions for escaping and unescaping strings to/from HTML interpolation. 327 var createEscaper = function(map) { 328 var escaper = function(match) { 329 return map[match]; 330 }; 331 // Regexes for identifying a key that needs to be escaped. 332 var source = '(?:' + Object.keys(map).join('|') + ')'; 333 var testRegexp = RegExp(source); 334 var replaceRegexp = RegExp(source, 'g'); 335 return function(string) { 336 string = string == null ? '' : '' + string; 337 return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; 338 }; 339 }; 340 341 var htmlEscape = createEscaper(escapeMap); 342 var htmlUnescape = createEscaper(unescapeMap); 343 344 /** 345 * ------------------------------------------------------------------------ 346 * Constants 347 * ------------------------------------------------------------------------ 348 */ 349 350 var keyCodeMap = { 351 32: ' ', 352 48: '0', 353 49: '1', 354 50: '2', 355 51: '3', 356 52: '4', 357 53: '5', 358 54: '6', 359 55: '7', 360 56: '8', 361 57: '9', 362 59: ';', 363 65: 'A', 364 66: 'B', 365 67: 'C', 366 68: 'D', 367 69: 'E', 368 70: 'F', 369 71: 'G', 370 72: 'H', 371 73: 'I', 372 74: 'J', 373 75: 'K', 374 76: 'L', 375 77: 'M', 376 78: 'N', 377 79: 'O', 378 80: 'P', 379 81: 'Q', 380 82: 'R', 381 83: 'S', 382 84: 'T', 383 85: 'U', 384 86: 'V', 385 87: 'W', 386 88: 'X', 387 89: 'Y', 388 90: 'Z', 389 96: '0', 390 97: '1', 391 98: '2', 392 99: '3', 393 100: '4', 394 101: '5', 395 102: '6', 396 103: '7', 397 104: '8', 398 105: '9' 399 }; 400 401 var keyCodes = { 402 ESCAPE: 27, // KeyboardEvent.which value for Escape (Esc) key 403 ENTER: 13, // KeyboardEvent.which value for Enter key 404 SPACE: 32, // KeyboardEvent.which value for space key 405 TAB: 9, // KeyboardEvent.which value for tab key 406 ARROW_UP: 38, // KeyboardEvent.which value for up arrow key 407 ARROW_DOWN: 40 // KeyboardEvent.which value for down arrow key 408 } 409 410 var version = { 411 success: false, 412 major: '3' 413 }; 414 415 try {
416 version.full = ($.fn.dropdown.Constructor.VERSION || '').split(' ')[0].split('.'); 417 version.major = version.full[0]; 418 version.success = true; 419 } catch (err) { 420 console.warn( 421 'There was an issue retrieving Bootstrap\'s version. ' + 422 'Ensure Bootstrap is being loaded before bootstrap-select and there is no namespace collision. ' + 423 'If loading Bootstrap asynchronously, the version may need to be manually specified via $.fn.selectpicker.Constructor.BootstrapVersion.', err); 424 } 425 426 var classNames = { 427 DISABLED: 'disabled', 428 DIVIDER: 'divider', 429 SHOW: 'open', 430 DROPUP: 'dropup', 431 MENU: 'dropdown-menu', 432 MENURIGHT: 'dropdown-menu-right', 433 MENULEFT: 'dropdown-menu-left', 434 // to-do: replace with more advanced template/customization options 435 BUTTONCLASS: 'btn-default', 436 POPOVERHEADER: 'popover-title' 437 } 438 439 var Selector = { 440 MENU: '.' + classNames.MENU 441 } 442 443 if (version.major === '4') { 444 classNames.DIVIDER = 'dropdown-divider'; 445 classNames.SHOW = 'show'; 446 classNames.BUTTONCLASS = 'btn-light'; 447 classNames.POPOVERHEADER = 'popover-header'; 448 } 449 450 var REGEXP_ARROW = new RegExp(keyCodes.ARROW_UP + '|' + keyCodes.ARROW_DOWN); 451 var REGEXP_TAB_OR_ESCAPE = new RegExp('^' + keyCodes.TAB + '$|' + keyCodes.ESCAPE); 452 var REGEXP_ENTER_OR_SPACE = new RegExp(keyCodes.ENTER + '|' + keyCodes.SPACE); 453 454 var Selectpicker = function(element, options) { 455 var that = this; 456 457 // bootstrap-select has been initialized - revert valHooks.select.set back to its original function 458 if (!valHooks.useDefault) { 459 $.valHooks.select.set = valHooks._set; 460 valHooks.useDefault = true; 461 } 462 463 this.$element = $(element); 464 this.$newElement = null; 465 this.$button = null; 466 this.$menu = null; 467 this.options = options; 468 this.selectpicker = { 469 main: { 470 // store originalIndex (key) and newIndex (value) in this.selectpicker.main.map.newIndex for fast accessibility 471 // allows us to do this.main.elements[this.selectpicker.main.map.newIndex[index]] to select an element based on the originalIndex 472 map: { 473 newIndex: {}, 474 originalIndex: {} 475 } 476 }, 477 current: { 478 map: {} 479 }, // current changes if a search is in progress 480 search: { 481 map: {} 482 }, 483 view: {}, 484 keydown: { 485 keyHistory: '', 486 resetKeyHistory: { 487 start: function() { 488 return setTimeout(function() { 489 that.selectpicker.keydown.keyHistory = ''; 490 }, 800); 491 } 492 } 493 } 494 }; 495 // If we have no title yet, try to pull it from the html title attribute (jQuery doesnt' pick it up as it's not a 496 // data-attribute) 497 if (this.options.title === null) { 498 this.options.title = this.$element.attr('title'); 499 } 500 501 // Format window padding 502 var winPad = this.options.windowPadding; 503 if (typeof winPad === 'number') { 504 this.options.windowPadding = [winPad, winPad, winPad, winPad]; 505 } 506 507 //Expose public methods 508 this.val = Selectpicker.prototype.val; 509 this.render = Selectpicker.prototype.render; 510 this.refresh = Selectpicker.prototype.refresh; 511 this.setStyle = Selectpicker.prototype.setStyle; 512 this.selectAll = Selectpicker.prototype.selectAll; 513 this.deselectAll = Selectpicker.prototype.deselectAll; 514 this.destroy = Selectpicker.prototype.destroy; 515 this.remove = Selectpicker.prototype.remove; 516 this.show = Selectpicker.prototype.show; 517 this.hide = Selectpicker.prototype.hide; 518 519 this.init(); 520 }; 521 522 Selectpicker.VERSION = '1.13.2'; 523 524 Selectpicker.BootstrapVersion = version.major; 525 526 // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both. 527 Selectpicker.DEFAULTS = { 528 noneSelectedText: 'Nothing selected', 529 noneResultsText: 'No results matched {0}', 530 countSelectedText: function(numSelected, numTotal) { 531 return (numSelected == 1) ? "{0} item selected" : "{0} items selected"; 532 }, 533 maxOptionsText: function(numAll, numGroup) { 534 return [ 535 (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)', 536 (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)' 537 ]; 538 }, 539 selectAllText: 'Select All', 540 deselectAllText: 'Deselect All',
541 doneButton: false, 542 doneButtonText: 'Close', 543 multipleSeparator: ', ', 544 styleBase: 'btn', 545 style: classNames.BUTTONCLASS, 546 size: 'auto', 547 title: null, 548 selectedTextFormat: 'values', 549 width: false, 550 container: false, 551 hideDisabled: false, 552 showSubtext: false, 553 showIcon: true, 554 showContent: true, 555 dropupAuto: true, 556 header: false, 557 liveSearch: false, 558 liveSearchPlaceholder: null, 559 liveSearchNormalize: false, 560 liveSearchStyle: 'contains', 561 actionsBox: false, 562 iconBase: 'glyphicon', 563 tickIcon: 'glyphicon-ok', 564 showTick: false, 565 template: { 566 caret: '<span class="caret"></span>' 567 }, 568 maxOptions: false, 569 mobile: false, 570 selectOnTab: false, 571 dropdownAlignRight: false, 572 windowPadding: 0, 573 virtualScroll: 600, 574 display: false 575 }; 576 577 if (version.major === '4') { 578 Selectpicker.DEFAULTS.style = 'btn-light'; 579 Selectpicker.DEFAULTS.iconBase = ''; 580 Selectpicker.DEFAULTS.tickIcon = 'bs-ok-default'; 581 } 582 583 Selectpicker.prototype = { 584 585 constructor: Selectpicker, 586 587 init: function() { 588 var that = this, 589 id = this.$element.attr('id'); 590 591 this.$element.addClass('bs-select-hidden'); 592 593 this.multiple = this.$element.prop('multiple'); 594 this.autofocus = this.$element.prop('autofocus'); 595 this.$newElement = this.createDropdown(); 596 this.createLi(); 597 this.$element 598 .after(this.$newElement) 599 .prependTo(this.$newElement); 600 this.$button = this.$newElement.children('button'); 601 this.$menu = this.$newElement.children(Selector.MENU); 602 this.$menuInner = this.$menu.children('.inner'); 603 this.$searchbox = this.$menu.find('input'); 604 605 this.$element.removeClass('bs-select-hidden'); 606 607 if (this.options.dropdownAlignRight === true) this.$menu.addClass(classNames.MENURIGHT); 608 609 if (typeof id !== 'undefined') { 610 this.$button.attr('data-id', id); 611 } 612 613 this.checkDisabled(); 614 this.clickListener(); 615 if (this.options.liveSearch) this.liveSearchListener(); 616 this.render(); 617 this.setStyle(); 618 this.setWidth(); 619 if (this.options.container) { 620 this.selectPosition(); 621 } else { 622 this.$element.on('hide.bs.select', function() { 623 if (that.isVirtual()) { 624 // empty menu on close 625 var menuInner = that.$menuInner[0], 626 emptyMenu = menuInner.firstChild.cloneNode(false); 627 628 // replace the existing UL with an empty one - this is faster than $.empty() or innerHTML = '' 629 menuInner.replaceChild(emptyMenu, menuInner.firstChild); 630 menuInner.scrollTop = 0; 631 } 632 }); 633 } 634 this.$menu.data('this', this); 635 this.$newElement.data('this', this); 636 if (this.options.mobile) this.mobile(); 637 638 this.$newElement.on({ 639 'hide.bs.dropdown': function(e) { 640 that.$menuInner.attr('aria-expanded', false); 641 that.$element.trigger('hide.bs.select', e); 642 }, 643 'hidden.bs.dropdown': function(e) { 644 that.$element.trigger('hidden.bs.select', e); 645 }, 646 'show.bs.dropdown': function(e) { 647 that.$menuInner.attr('aria-expanded', true); 648 that.$element.trigger('show.bs.select', e); 649 }, 650 'shown.bs.dropdown': function(e) { 651 that.$element.trigger('shown.bs.select', e); 652 } 653 }); 654 655 if (that.$element[0].hasAttribute('required')) { 656 this.$element.on('invalid', function() { 657 that.$button.addClass('bs-invalid'); 658 659 that.$element.on({ 660 'shown.bs.select': function() { 661 that.$element 662 .val(that.$element.val()) // set the value to hide the validation message in Chrome when menu is opened 663 .off('shown.bs.select'); 664 }, 665 'rendered.bs.select': function() { 666 // if select is no longer invalid, remove the bs-invalid class 667 if (this.validity.valid) that.$button.removeClass('bs-invalid'); 668 that.$element.off('rendered.bs.select'); 669 } 670 }); 671 672 that.$button.on('blur.bs.select', function() { 673 that.$element.focus().blur(); 674 that.$button.off('blur.bs.select'); 675 }); 676 }); 677 } 678 679 setTimeout(function() { 680 that.$element.trigger('loaded.bs.select'); 681 }); 682 }, 683 684 createDropdown: function() { 685 // Options 686 // If we are multiple or showTick option is set, then add the show-tick class 687 var showTick = (this.multiple || this.options.showTick) ? ' show-tick' : '', 688 autofocus = this.autofocus ? ' autofocus' : ''; 689 // Elements 690 var header = this.options.header ? '<div class="' + classNames.POPOVERHEADER + '"><button type="button" class="close" aria-hidden="true">×</button>' + this.options.header + '</div>' : ''; 691 var searchbox = this.options.liveSearch ? 692 '<div class="bs-searchbox">' + 693 '<input type="text" class="form-control" autocomplete="off"' + 694 (null === this.options.liveSearchPlaceholder ? '' : ' placeholder="' + htmlEscape(this.options.liveSearchPlaceholder) + '"') + ' role="textbox" aria-label="Search">' + 695 '</div>' : 696 ''; 697 var actionsbox = this.multiple && this.options.actionsBox ? 698 '<div class="bs-actionsbox">' + 699 '<div class="btn-group btn-group-sm btn-block">' + 700 '<button type="button" class="actions-btn bs-select-all btn ' + classNames.BUTTONCLASS + '">' + 701 this.options.selectAllText + 702 '</button>' + 703 '<button type="button" class="actions-btn bs-deselect-all btn ' + classNames.BUTTONCLASS + '">' + 704 this.options.deselectAllText + 705 '</button>' + 706 '</div>' + 707 '</div>' : 708 ''; 709 var donebutton = this.multiple && this.options.doneButton ? 710 '<div class="bs-donebutton">' + 711 '<div class="btn-group btn-block">' + 712 '<button type="button" class="btn btn-sm ' + classNames.BUTTONCLASS + '">' + 713 this.options.doneButtonText + 714 '</button>' + 715 '</div>' + 716 '</div>' : 717 ''; 718 var drop = 719 '<div class="dropdown bootstrap-select' + showTick + '">' + 720 '<button type="button" class="' + this.options.styleBase + ' dropdown-toggle" ' + (this.options.display === 'static' ? 'data-display="static"' : '') + 'data-toggle="dropdown"' + autofocus + ' role="button">' + 721 '<div class="filter-option">' + 722 '<div class="filter-option-inner">' + 723 '<div class="filter-option-inner-inner"></div>' + 724 '</div> ' + 725 '</div>' + 726 (version.major === '4' ? 727 '' : 728 '<span class="bs-caret">' + 729 this.options.template.caret + 730 '</span>' 731 ) + 732 '</button>' + 733 '<div class="' + classNames.MENU + ' ' + (version.major === '4' ? '' : classNames.SHOW) + '" role="combobox">' + 734 header + 735 searchbox + 736 actionsbox + 737 '<div class="inner ' + classNames.SHOW + '" role="listbox" aria-expanded="false" tabindex="-1">' + 738 '<ul class="' + classNames.MENU + ' inner ' + (version.major === '4' ? classNames.SHOW : '') + '">' + 739 '</ul>' + 740 '</div>' + 741 donebutton + 742 '</div>' + 743 '</div>'; 744 745 return $(drop); 746 }, 747 748 setPositionData: function() { 749 this.selectpicker.view.canHighlight = []; 750 751 for (var i = 0; i < this.selectpicker.current.data.length; i++) { 752 var li = this.selectpicker.current.data[i], 753 canHighlight = true; 754 755 if (li.type === 'divider') { 756 canHighlight = false;
757 li.height = this.sizeInfo.dividerHeight; 758 } else if (li.type === 'optgroup-label') { 759 canHighlight = false; 760 li.height = this.sizeInfo.dropdownHeaderHeight; 761 } else { 762 li.height = this.sizeInfo.liHeight; 763 } 764 765 if (li.disabled) canHighlight = false; 766 767 this.selectpicker.view.canHighlight.push(canHighlight); 768 769 li.position = (i === 0 ? 0 : this.selectpicker.current.data[i - 1].position) + li.height; 770 } 771 }, 772 773 isVirtual: function() { 774 return (this.options.virtualScroll !== false) && this.selectpicker.main.elements.length >= this.options.virtualScroll || this.options.virtualScroll === true; 775 }, 776 777 createView: function(isSearching, scrollTop) { 778 scrollTop = scrollTop || 0; 779 780 var that = this; 781 782 this.selectpicker.current = isSearching ? this.selectpicker.search : this.selectpicker.main; 783 784 var $lis; 785 var active = []; 786 var selected; 787 var prevActive; 788 var activeIndex; 789 var prevActiveIndex; 790 791 this.setPositionData(); 792 793 scroll(scrollTop, true); 794 795 this.$menuInner.off('scroll.createView').on('scroll.createView', function(e, updateValue) { 796 if (!that.noScroll) scroll(this.scrollTop, updateValue); 797 that.noScroll = false; 798 }); 799 800 function scroll(scrollTop, init) { 801 var size = that.selectpicker.current.elements.length, 802 chunks = [], 803 chunkSize, 804 chunkCount, 805 firstChunk, 806 lastChunk, 807 currentChunk = undefined, 808 prevPositions, 809 positionIsDifferent, 810 previousElements, 811 menuIsDifferent = true, 812 isVirtual = that.isVirtual(); 813 814 that.selectpicker.view.scrollTop = scrollTop; 815 816 if (isVirtual === true) { 817 // if an option that is encountered that is wider than the current menu width, update the menu width accordingly 818 if (that.sizeInfo.hasScrollBar && that.$menu[0].offsetWidth > that.sizeInfo.totalMenuWidth) { 819 that.sizeInfo.menuWidth = that.$menu[0].offsetWidth; 820 that.sizeInfo.totalMenuWidth = that.sizeInfo.menuWidth + that.sizeInfo.scrollBarWidth; 821 that.$menu.css('min-width', that.sizeInfo.menuWidth); 822 } 823 } 824 825 chunkSize = Math.ceil(that.sizeInfo.menuInnerHeight / that.sizeInfo.liHeight * 1.5); // number of options in a chunk 826 chunkCount = Math.round(size / chunkSize) || 1; // number of chunks 827 828 for (var i = 0; i < chunkCount; i++) { 829 var end_of_chunk = (i + 1) * chunkSize; 830 831 if (i === chunkCount - 1) { 832 end_of_chunk = size; 833 } 834 835 chunks[i] = [ 836 (i) * chunkSize + (!i ? 0 : 1), 837 end_of_chunk 838 ]; 839 840 if (!size) break; 841 842 if (currentChunk === undefined && scrollTop <= that.selectpicker.current.data[end_of_chunk - 1].position - that.sizeInfo.menuInnerHeight) { 843 currentChunk = i; 844 } 845 } 846 847 if (currentChunk === undefined) currentChunk = 0; 848 849 prevPositions = [that.selectpicker.view.position0, that.selectpicker.view.position1]; 850 851 // always display previous, current, and next chunks 852 firstChunk = Math.max(0, currentChunk - 1); 853 lastChunk = Math.min(chunkCount - 1, currentChunk + 1); 854 855 that.selectpicker.view.position0 = Math.max(0, chunks[firstChunk][0]) || 0; 856 that.selectpicker.view.position1 = Math.min(size, chunks[lastChunk][1]) || 0; 857 858 positionIsDifferent = prevPositions[0] !== that.selectpicker.view.position0 || prevPositions[1] !== that.selectpicker.view.position1; 859 860 if (that.activeIndex !== undefined) { 861 prevActive = that.selectpicker.current.elements[that.selectpicker.current.map.newIndex[that.prevActiveIndex]]; 862 active = that.selectpicker.current.elements[that.selectpicker.current.map.newIndex[that.activeIndex]]; 863 selected = that.selectpicker.current.elements[that.selectpicker.current.map.newIndex[that.selectedIndex]]; 864 865 if (init) {
866 if (that.activeIndex !== that.selectedIndex) { 867 active.classList.remove('active'); 868 if (active.firstChild) active.firstChild.classList.remove('active'); 869 } 870 that.activeIndex = undefined; 871 } 872 873 if (that.activeIndex && that.activeIndex !== that.selectedIndex && selected && selected.length) { 874 selected.classList.remove('active'); 875 if (selected.firstChild) selected.firstChild.classList.remove('active'); 876 } 877 } 878 879 if (that.prevActiveIndex !== undefined && that.prevActiveIndex !== that.activeIndex && that.prevActiveIndex !== that.selectedIndex && prevActive && prevActive.length) { 880 prevActive.classList.remove('active'); 881 if (prevActive.firstChild) prevActive.firstChild.classList.remove('active'); 882 } 883 884 if (init || positionIsDifferent) { 885 previousElements = that.selectpicker.view.visibleElements ? that.selectpicker.view.visibleElements.slice() : []; 886 887 that.selectpicker.view.visibleElements = that.selectpicker.current.elements.slice(that.selectpicker.view.position0, that.selectpicker.view.position1); 888 889 that.setOptionStatus(); 890 891 // if searching, check to make sure the list has actually been updated before updating DOM 892 // this prevents unnecessary repaints 893 if (isSearching || (isVirtual === false && init)) menuIsDifferent = !isEqual(previousElements, that.selectpicker.view.visibleElements); 894 895 // if virtual scroll is disabled and not searching, 896 // menu should never need to be updated more than once 897 if ((init || isVirtual === true) && menuIsDifferent) { 898 var menuInner = that.$menuInner[0], 899 menuFragment = document.createDocumentFragment(), 900 emptyMenu = menuInner.firstChild.cloneNode(false), 901 marginTop, 902 marginBottom, 903 elements = isVirtual === true ? that.selectpicker.view.visibleElements : that.selectpicker.current.elements; 904 905 // replace the existing UL with an empty one - this is faster than $.empty() 906 menuInner.replaceChild(emptyMenu, menuInner.firstChild); 907 908 for (var i = 0, visibleElementsLen = elements.length; i < visibleElementsLen; i++) { 909 menuFragment.appendChild(elements[i]); 910 } 911 912 if (isVirtual === true) { 913 marginTop = (that.selectpicker.view.position0 === 0 ? 0 : that.selectpicker.current.data[that.selectpicker.view.position0 - 1].position), 914 marginBottom = (that.selectpicker.view.position1 > size - 1 ? 0 : that.selectpicker.current.data[size - 1].position - that.selectpicker.current.data[that.selectpicker.view.position1 - 1].position); 915 916 menuInner.firstChild.style.marginTop = marginTop + 'px'; 917 menuInner.firstChild.style.marginBottom = marginBottom + 'px'; 918 } 919 920 menuInner.firstChild.appendChild(menuFragment); 921 } 922 } 923 924 that.prevActiveIndex = that.activeIndex; 925 926 if (!that.options.liveSearch) { 927 that.$menuInner.focus(); 928 } else if (isSearching && init) { 929 var index = 0, 930 newActive; 931 932 if (!that.selectpicker.view.canHighlight[index]) { 933 index = 1 + that.selectpicker.view.canHighlight.slice(1).indexOf(true); 934 } 935 936 newActive = that.selectpicker.view.visibleElements[index]; 937 938 if (that.selectpicker.view.currentActive) { 939 that.selectpicker.view.currentActive.classList.remove('active'); 940 if (that.selectpicker.view.currentActive.firstChild) that.selectpicker.view.currentActive.firstChild.classList.remove('active'); 941 } 942 943 if (newActive) { 944 newActive.classList.add('active'); 945 if (newActive.firstChild) newActive.firstChild.classList.add('active'); 946 } 947 948 that.activeIndex = that.selectpicker.current.map.originalIndex[index]; 949 } 950 } 951 952 $(window).off('resize.createView').on('resize.createView', function() { 953 scroll(that.$menuInner[0].scrollTop); 954 }); 955 }, 956 957 createLi: function() { 958 var that = this, 959 mainElements = [], 960 widestOption, 961 availableOptionsCount = 0, 962 widestOptionLength = 0, 963 mainData = [], 964 optID = 0, 965 headerIndex = 0, 966 liIndex = -1; // increment liIndex whenever a new <li> element is created to ensure newIndex is correct 967 968 if (!this.selectpicker.view.titleOption) this.selectpicker.view.titleOption = document.createElement('option'); 969 970 var elementTemplates = { 971 span: document.createElement('span'), 972 subtext: document.createElement('small'), 973 a: document.createElement('a'), 974 li: document.createElement('li'), 975 whitespace: document.createTextNode("\u00A0") 976 }, 977 checkMark = elementTemplates.span.cloneNode(false), 978 fragment = document.createDocumentFragment(); 979 980 checkMark.className = that.options.iconBase + ' ' + that.options.tickIcon + ' check-mark'; 981 elementTemplates.a.appendChild(checkMark); 982 elementTemplates.a.setAttribute('role', 'option'); 983 984 elementTemplates.subtext.className = 'text-muted'; 985 986 elementTemplates.text = elementTemplates.span.cloneNode(false); 987 elementTemplates.text.className = 'text'; 988 989 // Helper functions 990 /** 991 * @param content 992 * @param [index] 993 * @param [classes] 994 * @param [optgroup] 995 * @returns {HTMLElement} 996 */ 997 var generateLI = function(content, index, classes, optgroup) { 998 var li = elementTemplates.li.cloneNode(false); 999 1000 if (content) { 1001 if (content.nodeType === 1 || content.nodeType === 11) { 1002 li.appendChild(content); 1003 } else { 1004 li.innerHTML = content; 1005 } 1006 } 1007 1008 if (typeof classes !== 'undefined' && '' !== classes) li.className = classes; 1009 if (typeof optgroup !== 'undefined' && null !== optgroup) li.classList.add('optgroup-' + optgroup); 1010 1011 return li; 1012 }; 1013 1014 /** 1015 * @param text 1016 * @param [classes] 1017 * @param [inline] 1018 * @returns {string} 1019 */ 1020 var generateA = function(text, classes, inline) { 1021 var a = elementTemplates.a.cloneNode(true); 1022 1023 if (text) { 1024 if (text.nodeType === 11) { 1025 a.appendChild(text); 1026 } else { 1027 a.insertAdjacentHTML('beforeend', text); 1028 } 1029 } 1030 1031 if (typeof classes !== 'undefined' & '' !== classes) a.className = classes; 1032 if (version.major === '4') a.classList.add('dropdown-item'); 1033 if (inline) a.setAttribute('style', inline); 1034 1035 return a; 1036 }; 1037 1038 var generateText = function(options) { 1039 var textElement = elementTemplates.text.cloneNode(false), 1040 optionSubtextElement, 1041 optionIconElement; 1042 1043 if (options.optionContent) { 1044 textElement.innerHTML = options.optionContent; 1045 } else { 1046 textElement.textContent = options.text; 1047 1048 if (options.optionIcon) { 1049 var whitespace = elementTemplates.whitespace.cloneNode(false); 1050 1051 optionIconElement = elementTemplates.span.cloneNode(false); 1052 optionIconElement.className = that.options.iconBase + ' ' + options.optionIcon; 1053 1054 fragment.appendChild(optionIconElement); 1055 fragment.appendChild(whitespace); 1056 } 1057 1058 if (options.optionSubtext) { 1059 optionSubtextElement = elementTemplates.subtext.cloneNode(false); 1060 optionSubtextElement.innerHTML = options.optionSubtext; 1061 textElement.appendChild(optionSubtextElement); 1062 } 1063 } 1064 1065 fragment.appendChild(textElement); 1066 1067 return fragment; 1068 }; 1069 1070 var generateLabel = function(options) { 1071 var labelTextElement = elementTemplates.text.cloneNode(false), 1072 labelSubtextElement, 1073 labelIconElement; 1074 1075 labelTextElement.innerHTML = options.labelEscaped; 1076 1077 if (options.labelIcon) { 1078 var whitespace = elementTemplates.whitespace.cloneNode(false); 1079 1080 labelIconElement = elementTemplates.span.cloneNode(false); 1081 labelIconElement.className = that.options.iconBase + ' ' + options.labelIcon; 1082 1083 fragment.appendChild(labelIconElement); 1084 fragment.appendChild(whitespace); 1085 } 1086 1087 if (options.labelSubtext) { 1088 labelSubtextElement = elementTemplates.subtext.cloneNode(false); 1089 labelSubtextElement.textContent = options.labelSubtext; 1090 labelTextElement.appendChild(labelSubtextElement); 1091 } 1092 1093 fragment.appendChild(labelTextElement); 1094 1095 return fragment; 1096 } 1097 1098 if (this.options.title && !this.multiple) { 1099 // this option doesn't create a new <li> element, but does add a new option, so liIndex is decreased 1100 // since newIndex is recalculated on every refresh, liIndex needs to be decreased even if the titleOption is already appended 1101 liIndex--; 1102 1103 var element = this.$element[0], 1104 isSelected = false, 1105 titleNotAppended = !this.selectpicker.view.titleOption.parentNode; 1106 1107 if (titleNotAppended) {
1108 // Use native JS to prepend option (faster) 1109 this.selectpicker.view.titleOption.className = 'bs-title-option'; 1110 this.selectpicker.view.titleOption.value = ''; 1111 1112 // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option. 1113 // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs, 1114 // if so, the select will have the data-selected attribute 1115 var $opt = $(element.options[element.selectedIndex]); 1116 isSelected = $opt.attr('selected') === undefined && this.$element.data('selected') === undefined; 1117 } 1118 1119 if (titleNotAppended || this.selectpicker.view.titleOption.index !== 0) { 1120 element.insertBefore(this.selectpicker.view.titleOption, element.firstChild); 1121 } 1122 1123 // Set selected *after* appending to select, 1124 // otherwise the option doesn't get selected in IE 1125 // set using selectedIndex, as setting the selected attr to true here doesn't work in IE11 1126 if (isSelected) element.selectedIndex = 0; 1127 } 1128 1129 var $selectOptions = this.$element.find('option'); 1130 1131 $selectOptions.each(function(index) { 1132 var $this = $(this); 1133 1134 liIndex++; 1135 1136 if ($this.hasClass('bs-title-option')) return; 1137 1138 var thisData = $this.data(); 1139 1140 // Get the class and text for the option 1141 var optionClass = this.className || '', 1142 inline = htmlEscape(this.style.cssText), 1143 optionContent = thisData.content, 1144 text = this.textContent, 1145 tokens = thisData.tokens, 1146 subtext = thisData.subtext, 1147 icon = thisData.icon, 1148 $parent = $this.parent(), 1149 parent = $parent[0], 1150 isOptgroup = parent.tagName === 'OPTGROUP', 1151 isOptgroupDisabled = isOptgroup && parent.disabled, 1152 isDisabled = this.disabled || isOptgroupDisabled, 1153 prevHiddenIndex, 1154 showDivider = this.previousElementSibling && this.previousElementSibling.tagName === 'OPTGROUP', 1155 textElement; 1156 1157 var parentData = $parent.data(); 1158 1159 if (thisData.hidden === true || that.options.hideDisabled && (isDisabled && !isOptgroup || isOptgroupDisabled)) { 1160 // set prevHiddenIndex - the index of the first hidden option in a group of hidden options 1161 // used to determine whether or not a divider should be placed after an optgroup if there are 1162 // hidden options between the optgroup and the first visible option 1163 prevHiddenIndex = thisData.prevHiddenIndex; 1164 $this.next().data('prevHiddenIndex', (prevHiddenIndex !== undefined ? prevHiddenIndex : index)); 1165 1166 liIndex--; 1167 1168 // if previous element is not an optgroup 1169 if (!showDivider) { 1170 if (prevHiddenIndex !== undefined) { 1171 // select the element **before** the first hidden element in the group 1172 var prevHidden = $selectOptions[prevHiddenIndex].previousElementSibling; 1173 1174 if (prevHidden && prevHidden.tagName === 'OPTGROUP' && !prevHidden.disabled) { 1175 showDivider = true; 1176 } 1177 } 1178 } 1179 1180 if (showDivider && mainData[mainData.length - 1].type !== 'divider') { 1181 liIndex++; 1182 mainElements.push( 1183 generateLI( 1184 false, 1185 null, 1186 classNames.DIVIDER, 1187 optID + 'div' 1188 ) 1189 ); 1190 mainData.push({ 1191 type: 'divider', 1192 optID: optID 1193 }); 1194 } 1195 1196 return; 1197 } 1198 1199 if (isOptgroup && thisData.divider !== true) { 1200 if (that.options.hideDisabled && isDisabled) { 1201 if (parentData.allOptionsDisabled === undefined) { 1202 var $options = $parent.children(); 1203 $parent.data('allOptionsDisabled', $options.filter(':disabled').length === $options.length); 1204 } 1205 1206 if ($parent.data('allOptionsDisabled')) { 1207 liIndex--; 1208 return; 1209 } 1210 } 1211 1212 var optGroupClass = ' ' + parent.className || ''; 1213 1214 if (!this.previousElementSibling) { // Is it the first option of the optgroup? 1215 optID += 1; 1216 1217 // Get the opt group label 1218 var label = parent.label, 1219 labelEscaped = htmlEscape(label), 1220 labelSubtext = parentData.subtext, 1221 labelIcon = parentData.icon; 1222 1223 if (index !== 0 && mainElements.length > 0) { // Is it NOT the first option of the select && are there elements in the dropdown? 1224 liIndex++; 1225 mainElements.push( 1226 generateLI( 1227 false, 1228 null, 1229 classNames.DIVIDER, 1230 optID + 'div' 1231 ) 1232 ); 1233 mainData.push({ 1234 type: 'divider', 1235 optID: optID 1236 }); 1237 } 1238 liIndex++; 1239 1240 var labelElement = generateLabel({ 1241 labelEscaped: labelEscaped, 1242 labelSubtext: labelSubtext, 1243 labelIcon: labelIcon 1244 }); 1245 1246 mainElements.push(generateLI(labelElement, null, 'dropdown-header' + optGroupClass, optID)); 1247 mainData.push({ 1248 content: labelEscaped, 1249 subtext: labelSubtext, 1250 type: 'optgroup-label', 1251 optID: optID 1252 }); 1253 1254 headerIndex = liIndex - 1; 1255 } 1256 1257 if (that.options.hideDisabled && isDisabled || thisData.hidden === true) { 1258 liIndex--; 1259 return; 1260 } 1261 1262 textElement = generateText({ 1263 text: text, 1264 optionContent: optionContent, 1265 optionSubtext: subtext, 1266 optionIcon: icon 1267 }); 1268 1269 mainElements.push(generateLI(generateA(textElement, 'opt ' + optionClass + optGroupClass, inline), index, '', optID)); 1270 mainData.push({ 1271 content: optionContent || text, 1272 subtext: subtext, 1273 tokens: tokens, 1274 type: 'option', 1275 optID: optID, 1276 headerIndex: headerIndex, 1277 lastIndex: headerIndex + parent.childElementCount, 1278 originalIndex: index, 1279 data: thisData 1280 }); 1281 1282 availableOptionsCount++; 1283 } else if (thisData.divider === true) { 1284 mainElements.push(generateLI(false, index, classNames.DIVIDER)); 1285 mainData.push({ 1286 type: 'divider', 1287 originalIndex: index, 1288 data: thisData 1289 }); 1290 } else { 1291 // if previous element is not an optgroup and hideDisabled is true 1292 if (!showDivider && that.options.hideDisabled) { 1293 prevHiddenIndex = thisData.prevHiddenIndex; 1294 1295 if (prevHiddenIndex !== undefined) { 1296 // select the element **before** the first hidden element in the group 1297 var prevHidden = $selectOptions[prevHiddenIndex].previousElementSibling; 1298 1299 if (prevHidden && prevHidden.tagName === 'OPTGROUP' && !prevHidden.disabled) { 1300 showDivider = true; 1301 } 1302 } 1303 } 1304
1305 if (showDivider && mainData[mainData.length - 1].type !== 'divider') { 1306 liIndex++; 1307 mainElements.push( 1308 generateLI( 1309 false, 1310 null, 1311 classNames.DIVIDER, 1312 optID + 'div' 1313 ) 1314 ); 1315 mainData.push({ 1316 type: 'divider', 1317 optID: optID 1318 }); 1319 } 1320 1321 textElement = generateText({ 1322 text: text, 1323 optionContent: optionContent, 1324 optionSubtext: subtext, 1325 optionIcon: icon 1326 }); 1327 1328 mainElements.push(generateLI(generateA(textElement, optionClass, inline), index)); 1329 mainData.push({ 1330 content: optionContent || text, 1331 subtext: subtext, 1332 tokens: tokens, 1333 type: 'option', 1334 originalIndex: index, 1335 data: thisData 1336 }); 1337 1338 availableOptionsCount++; 1339 } 1340 1341 that.selectpicker.main.map.newIndex[index] = liIndex; 1342 that.selectpicker.main.map.originalIndex[liIndex] = index; 1343 1344 // get the most recent option info added to mainData 1345 var _mainDataLast = mainData[mainData.length - 1]; 1346 1347 _mainDataLast.disabled = isDisabled; 1348 1349 var combinedLength = 0; 1350 1351 // count the number of characters in the option - not perfect, but should work in most cases 1352 if (_mainDataLast.content) combinedLength += _mainDataLast.content.length; 1353 if (_mainDataLast.subtext) combinedLength += _mainDataLast.subtext.length; 1354 // if there is an icon, ensure this option's width is checked
1355 if (icon) combinedLength += 1; 1356 1357 if (combinedLength > widestOptionLength) { 1358 widestOptionLength = combinedLength; 1359 1360 // guess which option is the widest 1361 // use this when calculating menu width 1362 // not perfect, but it's fast, and the width will be updating accordingly when scrolling 1363 widestOption = mainElements[mainElements.length - 1]; 1364 } 1365 }); 1366 1367 this.selectpicker.main.elements = mainElements; 1368 this.selectpicker.main.data = mainData; 1369 1370 this.selectpicker.current = this.selectpicker.main; 1371 1372 this.selectpicker.view.widestOption = widestOption; 1373 this.selectpicker.view.availableOptionsCount = availableOptionsCount; // faster way to get # of available options without filter 1374 }, 1375 1376 findLis: function() { 1377 return this.$menuInner.find('.inner > li'); 1378 }, 1379 1380 render: function() { 1381 var that = this, 1382 $selectOptions = this.$element.find('option'), 1383 selectedItems = [], 1384 selectedItemsInTitle = []; 1385 1386 this.togglePlaceholder(); 1387 1388 this.tabIndex(); 1389 1390 for (var i = 0, len = this.selectpicker.main.elements.length; i < len; i++) { 1391 var index = this.selectpicker.main.map.originalIndex[i], 1392 option = $selectOptions[index]; 1393 1394 if (option && option.selected) { 1395 selectedItems.push(option); 1396 1397 if (selectedItemsInTitle.length < 100 && that.options.selectedTextFormat !== 'count' || selectedItems.length === 1) { 1398 if (that.options.hideDisabled && (option.disabled || option.parentNode.tagName === 'OPTGROUP' && option.parentNode.disabled)) return; 1399 1400 var thisData = this.selectpicker.main.data[i].data, 1401 icon = thisData.icon && that.options.showIcon ? '<i class="' + that.options.iconBase + ' ' + thisData.icon + '"></i> ' : '', 1402 subtext, 1403 titleItem; 1404 1405 if (that.options.showSubtext && thisData.subtext && !that.multiple) { 1406 subtext = ' <small class="text-muted">' + thisData.subtext + '</small>'; 1407 } else { 1408 subtext = ''; 1409 } 1410 1411 if (option.title) { 1412 titleItem = option.title; 1413 } else if (thisData.content && that.options.showContent) { 1414 titleItem = thisData.content.toString(); 1415 } else { 1416 titleItem = icon + option.innerHTML.trim() + subtext; 1417 } 1418 1419 selectedItemsInTitle.push(titleItem); 1420 } 1421 } 1422 } 1423 1424 //Fixes issue in IE10 occurring when no default option is selected and at least one option is disabled 1425 //Convert all the values into a comma delimited string 1426 var title = !this.multiple ? selectedItemsInTitle[0] : selectedItemsInTitle.join(this.options.multipleSeparator); 1427 1428 // add ellipsis 1429 if (selectedItems.length > 50) title += '...'; 1430 1431 // If this is a multiselect, and selectedTextFormat is count, then show 1 of 2 selected etc.. 1432 if (this.multiple && this.options.selectedTextFormat.indexOf('count') !== -1) { 1433 var max = this.options.selectedTextFormat.split('>'); 1434 1435 if ((max.length > 1 && selectedItems.length > max[1]) || (max.length === 1 && selectedItems.length >= 2)) { 1436 var totalCount = this.selectpicker.view.availableOptionsCount, 1437 tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedItems.length, totalCount) : this.options.countSelectedText; 1438 1439 title = tr8nText.replace('{0}', selectedItems.length.toString()).replace('{1}', totalCount.toString()); 1440 } 1441 } 1442 1443 if (this.options.title == undefined) { 1444 // use .attr to ensure undefined is returned if title attribute is not set 1445 this.options.title = this.$element.attr('title'); 1446 } 1447 1448 if (this.options.selectedTextFormat == 'static') { 1449 title = this.options.title; 1450 } 1451 1452 //If we dont have a title, then use the default, or if nothing is set at all, use the not selected text 1453 if (!title) { 1454 title = typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText; 1455 } 1456 1457 //strip all HTML tags and trim the result, then unescape any escaped tags 1458 this.$button[0].title = htmlUnescape(title.replace(/<[^>]*>?/g, '').trim()); 1459 this.$button.find('.filter-option-inner-inner')[0].innerHTML = title; 1460 1461 this.$element.trigger('rendered.bs.select'); 1462 }, 1463 1464 /** 1465 * @param [style] 1466 * @param [status] 1467 */ 1468 setStyle: function(style, status) { 1469 if (this.$element.attr('class')) { 1470 this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi, '')); 1471 } 1472 1473 var buttonClass = style ? style : this.options.style; 1474 1475 if (status == 'add') { 1476 this.$button.addClass(buttonClass); 1477 } else if (status == 'remove') { 1478 this.$button.removeClass(buttonClass); 1479 } else { 1480 this.$button.removeClass(this.options.style); 1481 this.$button.addClass(buttonClass); 1482 } 1483 }, 1484 1485 liHeight: function(refresh) { 1486 if (!refresh && (this.options.size === false || this.sizeInfo)) return; 1487 1488 if (!this.sizeInfo) this.sizeInfo = {}; 1489 1490 var newElement = document.createElement('div'), 1491 menu = document.createElement('div'), 1492 menuInner = document.createElement('div'), 1493 menuInnerInner = document.createElement('ul'), 1494 divider = document.createElement('li'), 1495 dropdownHeader = document.createElement('li'), 1496 li = document.createElement('li'), 1497 a = document.createElement('a'), 1498 text = document.createElement('span'), 1499 header = this.options.header && this.$menu.find('.' + classNames.POPOVERHEADER).length > 0 ? this.$menu.find('.' + classNames.POPOVERHEADER)[0].cloneNode(true) : null, 1500 search = this.options.liveSearch ? document.createElement('div') : null, 1501 actions = this.options.actionsBox && this.multiple && this.$menu.find('.bs-actionsbox').length > 0 ? this.$menu.find('.bs-actionsbox')[0].cloneNode(true) : null, 1502 doneButton = this.options.doneButton && this.multiple && this.$menu.find('.bs-donebutton').length > 0 ? this.$menu.find('.bs-donebutton')[0].cloneNode(true) : null; 1503 1504 this.sizeInfo.selectWidth = this.$newElement[0].offsetWidth; 1505 1506 text.className = 'text'; 1507 a.className = 'dropdown-item ' + this.$element.find('option')[0].className; 1508 newElement.className = this.$menu[0].parentNode.className + ' ' + classNames.SHOW; 1509 newElement.style.width = this.sizeInfo.selectWidth + 'px'; 1510 if (this.options.width === 'auto') menu.style.minWidth = 0; 1511 menu.className = classNames.MENU + ' ' + classNames.SHOW; 1512 menuInner.className = 'inner ' + classNames.SHOW; 1513 menuInnerInner.className = classNames.MENU + ' inner ' + (version.major === '4' ? classNames.SHOW : ''); 1514 divider.className = classNames.DIVIDER; 1515 dropdownHeader.className = 'dropdown-header'; 1516 1517 text.appendChild(document.createTextNode('Inner text')); 1518 a.appendChild(text); 1519 li.appendChild(a); 1520 dropdownHeader.appendChild(text.cloneNode(true)); 1521 1522 if (this.selectpicker.view.widestOption) { 1523 menuInnerInner.appendChild(this.selectpicker.view.widestOption.cloneNode(true)); 1524 } 1525 1526 menuInnerInner.appendChild(li); 1527 menuInnerInner.appendChild(divider); 1528 menuInnerInner.appendChild(dropdownHeader); 1529 if (header) menu.appendChild(header); 1530 if (search) { 1531 var input = document.createElement('input'); 1532 search.className = 'bs-searchbox'; 1533 input.className = 'form-control'; 1534 search.appendChild(input); 1535 menu.appendChild(search); 1536 } 1537 if (actions) menu.appendChild(actions); 1538 menuInner.appendChild(menuInnerInner); 1539 menu.appendChild(menuInner); 1540 if (doneButton) menu.appendChild(doneButton); 1541 newElement.appendChild(menu); 1542 1543 document.body.appendChild(newElement); 1544 1545 var liHeight = a.offsetHeight, 1546 dropdownHeaderHeight = dropdownHeader ? dropdownHeader.offsetHeight : 0, 1547 headerHeight = header ? header.offsetHeight : 0, 1548 searchHeight = search ? search.offsetHeight : 0, 1549 actionsHeight = actions ? actions.offsetHeight : 0, 1550 doneButtonHeight = doneButton ? doneButton.offsetHeight : 0, 1551 dividerHeight = $(divider).outerHeight(true), 1552 // fall back to jQuery if getComputedStyle is not supported 1553 menuStyle = window.getComputedStyle ? window.getComputedStyle(menu) : false, 1554 menuWidth = menu.offsetWidth, 1555 $menu = menuStyle ? null : $(menu), 1556 menuPadding = { 1557 vert: toInteger(menuStyle ? menuStyle.paddingTop : $menu.css('paddingTop')) + 1558 toInteger(menuStyle ? menuStyle.paddingBottom : $menu.css('paddingBottom')) + 1559 toInteger(menuStyle ? menuStyle.borderTopWidth : $menu.css('borderTopWidth')) + 1560 toInteger(menuStyle ? menuStyle.borderBottomWidth : $menu.css('borderBottomWidth')), 1561 horiz: toInteger(menuStyle ? menuStyle.paddingLeft : $menu.css('paddingLeft')) + 1562 toInteger(menuStyle ? menuStyle.paddingRight : $menu.css('paddingRight')) + 1563 toInteger(menuStyle ? menuStyle.borderLeftWidth : $menu.css('borderLeftWidth')) + 1564 toInteger(menuStyle ? menuStyle.borderRightWidth : $menu.css('borderRightWidth')) 1565 }, 1566 menuExtras = { 1567 vert: menuPadding.vert + 1568 toInteger(menuStyle ? menuStyle.marginTop : $menu.css('marginTop')) + 1569 toInteger(menuStyle ? menuStyle.marginBottom : $menu.css('marginBottom')) + 2, 1570 horiz: menuPadding.horiz + 1571 toInteger(menuStyle ? menuStyle.marginLeft : $menu.css('marginLeft')) + 1572 toInteger(menuStyle ? menuStyle.marginRight : $menu.css('marginRight')) + 2 1573 }, 1574 scrollBarWidth; 1575 1576 menuInner.style.overflowY = 'scroll'; 1577 1578 scrollBarWidth = menu.offsetWidth - menuWidth; 1579 1580 document.body.removeChild(newElement); 1581 1582 this.sizeInfo.liHeight = liHeight; 1583 this.sizeInfo.dropdownHeaderHeight = dropdownHeaderHeight; 1584 this.sizeInfo.headerHeight = headerHeight; 1585 this.sizeInfo.searchHeight = searchHeight; 1586 this.sizeInfo.actionsHeight = actionsHeight; 1587 this.sizeInfo.doneButtonHeight = doneButtonHeight;
vendor: 6,118 bytes, lines 1588-1723
1588 this.sizeInfo.dividerHeight = dividerHeight; 1589 this.sizeInfo.menuPadding = menuPadding; 1590 this.sizeInfo.menuExtras = menuExtras; 1591 this.sizeInfo.menuWidth = menuWidth; 1592 this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth; 1593 this.sizeInfo.scrollBarWidth = scrollBarWidth; 1594 this.sizeInfo.selectHeight = this.$newElement[0].offsetHeight; 1595 1596 this.setPositionData(); 1597 }, 1598 1599 getSelectPosition: function() { 1600 var that = this, 1601 $window = $(window), 1602 pos = that.$newElement.offset(), 1603 $container = $(that.options.container), 1604 containerPos; 1605 1606 if (that.options.container && !$container.is('body')) { 1607 containerPos = $container.offset(); 1608 containerPos.top += parseInt($container.css('borderTopWidth')); 1609 containerPos.left += parseInt($container.css('borderLeftWidth')); 1610 } else { 1611 containerPos = { 1612 top: 0, 1613 left: 0 1614 }; 1615 } 1616 1617 var winPad = that.options.windowPadding; 1618 1619 this.sizeInfo.selectOffsetTop = pos.top - containerPos.top - $window.scrollTop(); 1620 this.sizeInfo.selectOffsetBot = $window.height() - this.sizeInfo.selectOffsetTop - this.sizeInfo['selectHeight'] - containerPos.top - winPad[2]; 1621 this.sizeInfo.selectOffsetLeft = pos.left - containerPos.left - $window.scrollLeft(); 1622 this.sizeInfo.selectOffsetRight = $window.width() - this.sizeInfo.selectOffsetLeft - this.sizeInfo['selectWidth'] - containerPos.left - winPad[1]; 1623 this.sizeInfo.selectOffsetTop -= winPad[0]; 1624 this.sizeInfo.selectOffsetLeft -= winPad[3]; 1625 }, 1626 1627 setMenuSize: function(isAuto) { 1628 this.getSelectPosition(); 1629 1630 var selectWidth = this.sizeInfo['selectWidth'], 1631 liHeight = this.sizeInfo['liHeight'], 1632 headerHeight = this.sizeInfo['headerHeight'], 1633 searchHeight = this.sizeInfo['searchHeight'], 1634 actionsHeight = this.sizeInfo['actionsHeight'], 1635 doneButtonHeight = this.sizeInfo['doneButtonHeight'], 1636 divHeight = this.sizeInfo['dividerHeight'], 1637 menuPadding = this.sizeInfo['menuPadding'], 1638 menuInnerHeight, 1639 menuHeight, 1640 divLength = 0, 1641 minHeight, 1642 _minHeight, 1643 maxHeight, 1644 menuInnerMinHeight, 1645 estimate; 1646 1647 if (this.options.dropupAuto) { 1648 // Get the estimated height of the menu without scrollbars. 1649 // This is useful for smaller menus, where there might be plenty of room 1650 // below the button without setting dropup, but we can't know 1651 // the exact height of the menu until createView is called later 1652 estimate = liHeight * this.selectpicker.current.elements.length + menuPadding.vert; 1653 this.$newElement.toggleClass(classNames.DROPUP, this.sizeInfo.selectOffsetTop - this.sizeInfo.selectOffsetBot > this.sizeInfo.menuExtras.vert && estimate + this.sizeInfo.menuExtras.vert + 50 > this.sizeInfo.selectOffsetBot); 1654 } 1655 1656 if (this.options.size === 'auto') { 1657 _minHeight = this.selectpicker.current.elements.length > 3 ? this.sizeInfo.liHeight * 3 + this.sizeInfo.menuExtras.vert - 2 : 0; 1658 menuHeight = this.sizeInfo.selectOffsetBot - this.sizeInfo.menuExtras.vert; 1659 minHeight = _minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight; 1660 menuInnerMinHeight = Math.max(_minHeight - menuPadding.vert, 0); 1661 1662 if (this.$newElement.hasClass(classNames.DROPUP)) { 1663 menuHeight = this.sizeInfo.selectOffsetTop - this.sizeInfo.menuExtras.vert; 1664 } 1665 1666 maxHeight = menuHeight; 1667 menuInnerHeight = menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert; 1668 } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) { 1669 for (var i = 0; i < this.options.size; i++) { 1670 if (this.selectpicker.current.data[i].type === 'divider') divLength++; 1671 } 1672 1673 menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert; 1674 menuInnerHeight = menuHeight - menuPadding.vert; 1675 maxHeight = menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight; 1676 minHeight = menuInnerMinHeight = ''; 1677 } 1678 1679 if (this.options.dropdownAlignRight === 'auto') { 1680 this.$menu.toggleClass(classNames.MENURIGHT, this.sizeInfo.selectOffsetLeft > this.sizeInfo.selectOffsetRight && this.sizeInfo.selectOffsetRight < (this.$menu[0].offsetWidth - selectWidth)); 1681 } 1682 1683 this.$menu.css({ 1684 'max-height': maxHeight + 'px', 1685 'overflow': 'hidden', 1686 'min-height': minHeight + 'px' 1687 }); 1688 1689 this.$menuInner.css({ 1690 'max-height': menuInnerHeight + 'px', 1691 'overflow-y': 'auto', 1692 'min-height': menuInnerMinHeight + 'px' 1693 }); 1694 1695 this.sizeInfo['menuInnerHeight'] = menuInnerHeight; 1696 1697 if (this.selectpicker.current.data.length && this.selectpicker.current.data[this.selectpicker.current.data.length - 1].position > this.sizeInfo.menuInnerHeight) { 1698 this.sizeInfo.hasScrollBar = true; 1699 this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth + this.sizeInfo.scrollBarWidth; 1700 1701 this.$menu.css('min-width', this.sizeInfo.totalMenuWidth); 1702 } 1703 1704 if (this.dropdown && this.dropdown._popper) this.dropdown._popper.update(); 1705 }, 1706 1707 setSize: function(refresh) { 1708 this.liHeight(refresh); 1709 1710 if (this.options.header) this.$menu.css('padding-top', 0); 1711 if (this.options.size === false) return; 1712 1713 var that = this, 1714 $window = $(window), 1715 selectedIndex, 1716 offset = 0; 1717 1718 this.setMenuSize(); 1719 1720 if (this.options.size === 'auto') { 1721 this.$searchbox.off('input.setMenuSize propertychange.setMenuSize').on('input.setMenuSize propertychange.setMenuSize', function() { 1722 return that.setMenuSize(); 1723 });
1724 $window.off('resize.setMenuSize scroll.setMenuSize').on('resize.setMenuSize scroll.setMenuSize', function() { 1725 return that.setMenuSize(); 1726 }); 1727 } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) { 1728 this.$searchbox.off('input.setMenuSize propertychange.setMenuSize'); 1729 $window.off('resize.setMenuSize scroll.setMenuSize'); 1730 } 1731 1732 if (refresh) { 1733 offset = this.$menuInner[0].scrollTop; 1734 } else if (!that.multiple) { 1735 selectedIndex = that.selectpicker.main.map.newIndex[that.$element[0].selectedIndex]; 1736 1737 if (typeof selectedIndex === 'number' && that.options.size !== false) { 1738 offset = that.sizeInfo.liHeight * selectedIndex; 1739 offset = offset - (that.sizeInfo.menuInnerHeight / 2) + (that.sizeInfo.liHeight / 2); 1740 } 1741 } 1742 1743 that.createView(false, offset); 1744 }, 1745 1746 setWidth: function() { 1747 var that = this; 1748 1749 if (this.options.width === 'auto') { 1750 requestAnimationFrame(function() { 1751 that.$menu.css('min-width', '0'); 1752 that.liHeight(); 1753 that.setMenuSize(); 1754 1755 // Get correct width if element is hidden 1756 var $selectClone = that.$newElement.clone().appendTo('body'), 1757 btnWidth = $selectClone.css('width', 'auto').children('button').outerWidth(); 1758 1759 $selectClone.remove(); 1760 1761 // Set width to whatever's larger, button title or longest option 1762 that.sizeInfo.selectWidth = Math.max(that.sizeInfo.totalMenuWidth, btnWidth); 1763 that.$newElement.css('width', that.sizeInfo.selectWidth + 'px'); 1764 }); 1765 } else if (this.options.width === 'fit') { 1766 // Remove inline min-width so width can be changed from 'auto' 1767 this.$menu.css('min-width', ''); 1768 this.$newElement.css('width', '').addClass('fit-width'); 1769 } else if (this.options.width) { 1770 // Remove inline min-width so width can be changed from 'auto' 1771 this.$menu.css('min-width', ''); 1772 this.$newElement.css('width', this.options.width); 1773 } else { 1774 // Remove inline min-width/width so width can be changed 1775 this.$menu.css('min-width', ''); 1776 this.$newElement.css('width', ''); 1777 } 1778 // Remove fit-width class if width is changed programmatically 1779 if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') { 1780 this.$newElement.removeClass('fit-width'); 1781 } 1782 }, 1783 1784 selectPosition: function() {
1785 this.$bsContainer = $('<div class="bs-container" />'); 1786 1787 var that = this, 1788 $container = $(this.options.container), 1789 pos, 1790 containerPos, 1791 actualHeight, 1792 getPlacement = function($element) { 1793 var containerPosition = {}, 1794 // fall back to dropdown's default display setting if display is not manually set 1795 display = that.options.display || $.fn.dropdown.Constructor.Default.display; 1796 1797 that.$bsContainer.addClass($element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass(classNames.DROPUP, $element.hasClass(classNames.DROPUP)); 1798 pos = $element.offset(); 1799 1800 if (!$container.is('body')) { 1801 containerPos = $container.offset(); 1802 containerPos.top += parseInt($container.css('borderTopWidth')) - $container.scrollTop(); 1803 containerPos.left += parseInt($container.css('borderLeftWidth')) - $container.scrollLeft(); 1804 } else { 1805 containerPos = { 1806 top: 0, 1807 left: 0 1808 }; 1809 } 1810 1811 actualHeight = $element.hasClass(classNames.DROPUP) ? 0 : $element[0].offsetHeight; 1812 1813 // Bootstrap 4+ uses Popper for menu positioning 1814 if (version.major < 4 || display === 'static') { 1815 containerPosition['top'] = pos.top - containerPos.top + actualHeight; 1816 containerPosition['left'] = pos.left - containerPos.left; 1817 } 1818 1819 containerPosition['width'] = $element[0].offsetWidth; 1820 1821 that.$bsContainer.css(containerPosition); 1822 }; 1823 1824 this.$button.on('click.bs.dropdown.data-api', function() { 1825 if (that.isDisabled()) { 1826 return; 1827 } 1828 1829 getPlacement(that.$newElement); 1830 1831 that.$bsContainer 1832 .appendTo(that.options.container) 1833 .toggleClass(classNames.SHOW, !that.$button.hasClass(classNames.SHOW)) 1834 .append(that.$menu); 1835 }); 1836 1837 $(window).on('resize scroll', function() { 1838 getPlacement(that.$newElement); 1839 }); 1840 1841 this.$element.on('hide.bs.select', function() { 1842 that.$menu.data('height', that.$menu.height()); 1843 that.$bsContainer.detach(); 1844 }); 1845 }, 1846 1847 setOptionStatus: function() { 1848 var that = this, 1849 $selectOptions = this.$element.find('option'); 1850 1851 that.noScroll = false; 1852 1853 if (that.selectpicker.view.visibleElements && that.selectpicker.view.visibleElements.length) { 1854 for (var i = 0; i < that.selectpicker.view.visibleElements.length; i++) { 1855 var index = that.selectpicker.current.map.originalIndex[i + that.selectpicker.view.position0], // faster than $(li).data('originalIndex') 1856 option = $selectOptions[index]; 1857 1858 if (option) { 1859 var liIndex = this.selectpicker.main.map.newIndex[index], 1860 li = this.selectpicker.main.elements[liIndex]; 1861 1862 that.setDisabled( 1863 index, 1864 option.disabled || option.parentNode.tagName === 'OPTGROUP' && option.parentNode.disabled, 1865 liIndex, 1866 li 1867 ); 1868 1869 that.setSelected( 1870 index, 1871 option.selected, 1872 liIndex, 1873 li 1874 ); 1875 } 1876 } 1877 } 1878 }, 1879 1880 /** 1881 * @param {number} index - the index of the option that is being changed 1882 * @param {boolean} selected - true if the option is being selected, false if being deselected 1883 */ 1884 setSelected: function(index, selected, liIndex, li) { 1885 var activeIndexIsSet = this.activeIndex !== undefined, 1886 thisIsActive = this.activeIndex === index, 1887 prevActiveIndex, 1888 prevActive, 1889 a, 1890 // if current option is already active 1891 // OR 1892 // if the current option is being selected, it's NOT multiple, and 1893 // activeIndex is undefined: 1894 // - when the menu is first being opened, OR 1895 // - after a search has been performed, OR 1896 // - when retainActive is false when selecting a new option (i.e. index of the newly selected option is not the same as the current activeIndex) 1897 keepActive = thisIsActive || selected && !this.multiple && !activeIndexIsSet; 1898 1899 if (!liIndex) liIndex = this.selectpicker.main.map.newIndex[index]; 1900 if (!li) li = this.selectpicker.main.elements[liIndex]; 1901 1902 a = li.firstChild; 1903 1904 if (selected) { 1905 this.selectedIndex = index; 1906 } 1907 1908 li.classList.toggle('selected', selected); 1909 li.classList.toggle('active', keepActive); 1910 1911 if (keepActive) { 1912 this.selectpicker.view.currentActive = li; 1913 this.activeIndex = index; 1914 } 1915 1916 if (a) { 1917 a.classList.toggle('selected', selected); 1918 a.classList.toggle('active', keepActive); 1919 a.setAttribute('aria-selected', selected); 1920 } 1921 1922 if (!keepActive) { 1923 if (!activeIndexIsSet && selected && this.prevActiveIndex !== undefined) { 1924 prevActiveIndex = this.selectpicker.main.map.newIndex[this.prevActiveIndex]; 1925 prevActive = this.selectpicker.main.elements[prevActiveIndex]; 1926 1927 prevActive.classList.toggle('selected', selected); 1928 prevActive.classList.remove('active'); 1929 if (prevActive.firstChild) { 1930 prevActive.firstChild.classList.toggle('selected', selected); 1931 prevActive.firstChild.classList.remove('active'); 1932 } 1933 } 1934 } 1935 }, 1936 1937 /** 1938 * @param {number} index - the index of the option that is being disabled 1939 * @param {boolean} disabled - true if the option is being disabled, false if being enabled 1940 */ 1941 setDisabled: function(index, disabled, liIndex, li) { 1942 var a; 1943 1944 if (!liIndex) liIndex = this.selectpicker.main.map.newIndex[index]; 1945 if (!li) li = this.selectpicker.main.elements[liIndex]; 1946 1947 a = li.firstChild; 1948 1949 li.classList.toggle(classNames.DISABLED, disabled); 1950 1951 if (a) { 1952 if (version.major === '4') a.classList.toggle(classNames.DISABLED, disabled); 1953 1954 a.setAttribute('aria-disabled', disabled); 1955 1956 if (disabled) { 1957 a.setAttribute('tabindex', -1); 1958 } else { 1959 a.setAttribute('tabindex', 0); 1960 } 1961 } 1962 }, 1963 1964 isDisabled: function() { 1965 return this.$element[0].disabled; 1966 }, 1967 1968 checkDisabled: function() { 1969 var that = this; 1970 1971 if (this.isDisabled()) { 1972 this.$newElement.addClass(classNames.DISABLED); 1973 this.$button.addClass(classNames.DISABLED).attr('tabindex', -1).attr('aria-disabled', true); 1974 } else { 1975 if (this.$button.hasClass(classNames.DISABLED)) { 1976 this.$newElement.removeClass(classNames.DISABLED); 1977 this.$button.removeClass(classNames.DISABLED).attr('aria-disabled', false); 1978 } 1979 1980 if (this.$button.attr('tabindex') == -1 && !this.$element.data('tabindex')) { 1981 this.$button.removeAttr('tabindex'); 1982 } 1983 } 1984 1985 this.$button.click(function() { 1986 return !that.isDisabled(); 1987 }); 1988 }, 1989 1990 togglePlaceholder: function() { 1991 // much faster than calling $.val() 1992 var element = this.$element[0], 1993 selectedIndex = element.selectedIndex, 1994 nothingSelected = selectedIndex === -1; 1995 1996 if (!nothingSelected && !element.options[selectedIndex].value) nothingSelected = true; 1997 1998 this.$button.toggleClass('bs-placeholder', nothingSelected); 1999 }, 2000 2001 tabIndex: function() { 2002 if (this.$element.data('tabindex') !== this.$element.attr('tabindex') && 2003 (this.$element.attr('tabindex') !== -98 && this.$element.attr('tabindex') !== '-98')) { 2004 this.$element.data('tabindex', this.$element.attr('tabindex')); 2005 this.$button.attr('tabindex', this.$element.data('tabindex')); 2006 } 2007 2008 this.$element.attr('tabindex', -98); 2009 }, 2010 2011 clickListener: function() { 2012 var that = this, 2013 $document = $(document); 2014 2015 $document.data('spaceSelect', false); 2016 2017 this.$button.on('keyup', function(e) { 2018 if (/(32)/.test(e.keyCode.toString(10)) && $document.data('spaceSelect')) { 2019 e.preventDefault(); 2020 $document.data('spaceSelect', false); 2021 } 2022 }); 2023 2024 this.$newElement.on('show.bs.dropdown', function() { 2025 if (version.major > 3 && !that.dropdown) { 2026 that.dropdown = that.$button.data('bs.dropdown'); 2027 that.dropdown._menu = that.$menu[0]; 2028 } 2029 }); 2030 2031 this.$button.on('click.bs.dropdown.data-api', function() { 2032 if (!that.$newElement.hasClass(classNames.SHOW)) { 2033 that.setSize(); 2034 } 2035 }); 2036 2037 function setFocus() { 2038 if (that.options.liveSearch) { 2039 that.$searchbox.focus(); 2040 } else { 2041 that.$menuInner.focus(); 2042 } 2043 } 2044 2045 function checkPopperExists() { 2046 if (that.dropdown && that.dropdown._popper && that.dropdown._popper.state.isCreated) { 2047 setFocus(); 2048 } else { 2049 requestAnimationFrame(checkPopperExists); 2050 } 2051 } 2052 2053 this.$element.on('shown.bs.select', function() {
2054 if (that.$menuInner[0].scrollTop !== that.selectpicker.view.scrollTop) { 2055 that.$menuInner[0].scrollTop = that.selectpicker.view.scrollTop; 2056 } 2057 2058 if (version.major > 3) { 2059 requestAnimationFrame(checkPopperExists); 2060 } else { 2061 setFocus(); 2062 } 2063 }); 2064 2065 this.$menuInner.on('click', 'li a', function(e, retainActive) { 2066 var $this = $(this), 2067 position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0, 2068 clickedIndex = that.selectpicker.current.map.originalIndex[$this.parent().index() + position0], 2069 prevValue = getSelectValues(that.$element[0]), 2070 prevIndex = that.$element.prop('selectedIndex'), 2071 triggerChange = true; 2072 2073 // Don't close on multi choice menu 2074 if (that.multiple && that.options.maxOptions !== 1) { 2075 e.stopPropagation(); 2076 } 2077 2078 e.preventDefault(); 2079 2080 //Don't run if we have been disabled 2081 if (!that.isDisabled() && !$this.parent().hasClass(classNames.DISABLED)) { 2082 var $options = that.$element.find('option'), 2083 $option = $options.eq(clickedIndex), 2084 state = $option.prop('selected'), 2085 $optgroup = $option.parent('optgroup'), 2086 $optgroupOptions = $optgroup.find('option'), 2087 maxOptions = that.options.maxOptions, 2088 maxOptionsGrp = $optgroup.data('maxOptions') || false; 2089 2090 if (clickedIndex === that.activeIndex) retainActive = true; 2091 2092 if (!retainActive) { 2093 that.prevActiveIndex = that.activeIndex; 2094 that.activeIndex = undefined; 2095 } 2096 2097 if (!that.multiple) { // Deselect all others if not multi select box 2098 $options.prop('selected', false); 2099 $option.prop('selected', true); 2100 that.setSelected(clickedIndex, true); 2101 } else { // Toggle the one we have chosen if we are multi select. 2102 $option.prop('selected', !state); 2103 2104 that.setSelected(clickedIndex, !state); 2105 $this.blur(); 2106 2107 if (maxOptions !== false || maxOptionsGrp !== false) { 2108 var maxReached = maxOptions < $options.filter(':selected').length, 2109 maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length; 2110 2111 if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) { 2112 if (maxOptions && maxOptions == 1) { 2113 $options.prop('selected', false); 2114 $option.prop('selected', true); 2115 2116 for (var i = 0; i < $options.length; i++) { 2117 that.setSelected(i, false); 2118 } 2119 2120 that.setSelected(clickedIndex, true); 2121 } else if (maxOptionsGrp && maxOptionsGrp == 1) { 2122 $optgroup.find('option:selected').prop('selected', false); 2123 $option.prop('selected', true); 2124 2125 for (var i = 0; i < $optgroupOptions.length; i++) { 2126 var option = $optgroupOptions[i]; 2127 that.setSelected($options.index(option), false); 2128 } 2129 2130 that.setSelected(clickedIndex, true); 2131 } else { 2132 var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText, 2133 maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText, 2134 maxTxt = maxOptionsArr[0].replace('{n}', maxOptions), 2135 maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp), 2136 $notify = $('<div class="notify"></div>'); 2137 // If {var} is set in array, replace it 2138 /** @deprecated */ 2139 if (maxOptionsArr[2]) { 2140 maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]); 2141 maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]); 2142 } 2143 2144 $option.prop('selected', false); 2145 2146 that.$menu.append($notify); 2147 2148 if (maxOptions && maxReached) { 2149 $notify.append($('<div>' + maxTxt + '</div>')); 2150 triggerChange = false;
2151 that.$element.trigger('maxReached.bs.select'); 2152 } 2153 2154 if (maxOptionsGrp && maxReachedGrp) { 2155 $notify.append($('<div>' + maxTxtGrp + '</div>')); 2156 triggerChange = false; 2157 that.$element.trigger('maxReachedGrp.bs.select'); 2158 } 2159 2160 setTimeout(function() { 2161 that.setSelected(clickedIndex, false); 2162 }, 10); 2163 2164 $notify.delay(750).fadeOut(300, function() { 2165 $(this).remove(); 2166 }); 2167 } 2168 } 2169 } 2170 } 2171 2172 if (!that.multiple || (that.multiple && that.options.maxOptions === 1)) { 2173 that.$button.focus(); 2174 } else if (that.options.liveSearch) { 2175 that.$searchbox.focus(); 2176 } 2177 2178 // Trigger select 'change' 2179 if (triggerChange) { 2180 if ((prevValue != getSelectValues(that.$element[0]) && that.multiple) || (prevIndex != that.$element.prop('selectedIndex') && !that.multiple)) { 2181 // $option.prop('selected') is current option state (selected/unselected). prevValue is the value of the select prior to being changed. 2182 changed_arguments = [clickedIndex, $option.prop('selected'), prevValue]; 2183 that.$element 2184 .triggerNative('change'); 2185 } 2186 } 2187 } 2188 }); 2189 2190 this.$menu.on('click', 'li.' + classNames.DISABLED + ' a, .' + classNames.POPOVERHEADER + ', .' + classNames.POPOVERHEADER + ' :not(.close)', function(e) { 2191 if (e.currentTarget == this) { 2192 e.preventDefault(); 2193 e.stopPropagation(); 2194 if (that.options.liveSearch && !$(e.target).hasClass('close')) { 2195 that.$searchbox.focus(); 2196 } else { 2197 that.$button.focus(); 2198 } 2199 } 2200 }); 2201 2202 this.$menuInner.on('click', '.divider, .dropdown-header', function(e) { 2203 e.preventDefault(); 2204 e.stopPropagation(); 2205 if (that.options.liveSearch) { 2206 that.$searchbox.focus(); 2207 } else { 2208 that.$button.focus(); 2209 } 2210 }); 2211 2212 this.$menu.on('click', '.' + classNames.POPOVERHEADER + ' .close', function() { 2213 that.$button.click(); 2214 }); 2215 2216 this.$searchbox.on('click', function(e) { 2217 e.stopPropagation(); 2218 }); 2219 2220 this.$menu.on('click', '.actions-btn', function(e) { 2221 if (that.options.liveSearch) { 2222 that.$searchbox.focus(); 2223 } else { 2224 that.$button.focus(); 2225 } 2226 2227 e.preventDefault(); 2228 e.stopPropagation(); 2229 2230 if ($(this).hasClass('bs-select-all')) { 2231 that.selectAll(); 2232 } else { 2233 that.deselectAll(); 2234 } 2235 }); 2236 2237 this.$element.on({ 2238 'change': function() { 2239 that.render(); 2240 that.$element.trigger('changed.bs.select', changed_arguments); 2241 changed_arguments = null; 2242 }, 2243 'focus': function() { 2244 that.$button.focus(); 2245 } 2246 }); 2247 }, 2248 2249 liveSearchListener: function() { 2250 var that = this, 2251 no_results = document.createElement('li'); 2252 2253 this.$button.on('click.bs.dropdown.data-api', function() { 2254 if (!!that.$searchbox.val()) { 2255 that.$searchbox.val(''); 2256 } 2257 }); 2258 2259 this.$searchbox.on('click.bs.dropdown.data-api focus.bs.dropdown.data-api touchend.bs.dropdown.data-api', function(e) { 2260 e.stopPropagation(); 2261 }); 2262 2263 this.$searchbox.on('input propertychange', function() { 2264 var searchValue = that.$searchbox.val(); 2265 2266 that.selectpicker.search.map.newIndex = {}; 2267 that.selectpicker.search.map.originalIndex = {}; 2268 that.selectpicker.search.elements = []; 2269 that.selectpicker.search.data = []; 2270 2271 if (searchValue) { 2272 var i, 2273 searchMatch = [], 2274 q = searchValue.toUpperCase(), 2275 cache = {}, 2276 cacheArr = [], 2277 searchStyle = that._searchStyle(), 2278 normalizeSearch = that.options.liveSearchNormalize; 2279 2280 that._$lisSelected = that.$menuInner.find('.selected'); 2281 2282 for (var i = 0; i < that.selectpicker.main.data.length; i++) { 2283 var li = that.selectpicker.main.data[i]; 2284 2285 if (!cache[i]) { 2286 cache[i] = stringSearch(li, q, searchStyle, normalizeSearch); 2287 } 2288 2289 if (cache[i] && li.headerIndex !== undefined && cacheArr.indexOf(li.headerIndex) === -1) { 2290 if (li.headerIndex > 0) { 2291 cache[li.headerIndex - 1] = true; 2292 cacheArr.push(li.headerIndex - 1); 2293 } 2294 2295 cache[li.headerIndex] = true; 2296 cacheArr.push(li.headerIndex); 2297 2298 cache[li.lastIndex + 1] = true; 2299 } 2300 2301 if (cache[i] && li.type !== 'optgroup-label') cacheArr.push(i); 2302 } 2303 2304 for (var i = 0, cacheLen = cacheArr.length; i < cacheLen; i++) {
2305 var index = cacheArr[i], 2306 prevIndex = cacheArr[i - 1], 2307 li = that.selectpicker.main.data[index], 2308 liPrev = that.selectpicker.main.data[prevIndex]; 2309 2310 if (li.type !== 'divider' || (li.type === 'divider' && liPrev && liPrev.type !== 'divider' && cacheLen - 1 !== i)) { 2311 that.selectpicker.search.data.push(li); 2312 searchMatch.push(that.selectpicker.main.elements[index]); 2313 2314 if (li.hasOwnProperty('originalIndex')) { 2315 that.selectpicker.search.map.newIndex[li.originalIndex] = searchMatch.length - 1; 2316 that.selectpicker.search.map.originalIndex[searchMatch.length - 1] = li.originalIndex; 2317 } 2318 } 2319 } 2320 2321 that.activeIndex = undefined; 2322 that.noScroll = true; 2323 that.$menuInner.scrollTop(0); 2324 that.selectpicker.search.elements = searchMatch; 2325 that.createView(true); 2326 2327 if (!searchMatch.length) { 2328 no_results.className = 'no-results'; 2329 no_results.innerHTML = that.options.noneResultsText.replace('{0}', '"' + htmlEscape(searchValue) + '"'); 2330 that.$menuInner[0].firstChild.appendChild(no_results); 2331 } 2332 } else { 2333 that.$menuInner.scrollTop(0); 2334 that.createView(false); 2335 } 2336 }); 2337 }, 2338 2339 _searchStyle: function() { 2340 return this.options.liveSearchStyle || 'contains'; 2341 }, 2342 2343 val: function(value) { 2344 if (typeof value !== 'undefined') { 2345 this.$element 2346 .val(value) 2347 .triggerNative('change'); 2348 2349 return this.$element; 2350 } else { 2351 return this.$element.val(); 2352 } 2353 }, 2354 2355 changeAll: function(status) { 2356 if (!this.multiple) return; 2357 if (typeof status === 'undefined') status = true; 2358 2359 var $selectOptions = this.$element.find('option'), 2360 previousSelected = 0, 2361 currentSelected = 0, 2362 prevValue = getSelectValues(this.$element[0]); 2363 2364 this.$element.addClass('bs-select-hidden'); 2365 2366 for (var i = 0; i < this.selectpicker.current.elements.length; i++) { 2367 var liData = this.selectpicker.current.data[i], 2368 index = this.selectpicker.current.map.originalIndex[i], // faster than $(li).data('originalIndex') 2369 option = $selectOptions[index]; 2370 2371 if (option && !option.disabled && liData.type !== 'divider') { 2372 if (option.selected) previousSelected++; 2373 option.selected = status; 2374 if (option.selected) currentSelected++; 2375 } 2376 } 2377 2378 this.$element.removeClass('bs-select-hidden'); 2379 2380 if (previousSelected === currentSelected) return; 2381 2382 this.setOptionStatus(); 2383 2384 this.togglePlaceholder(); 2385 2386 changed_arguments = [null, null, prevValue]; 2387 2388 this.$element 2389 .triggerNative('change'); 2390 }, 2391 2392 selectAll: function() { 2393 return this.changeAll(true); 2394 }, 2395 2396 deselectAll: function() { 2397 return this.changeAll(false); 2398 }, 2399 2400 toggle: function(e) { 2401 e = e || window.event; 2402 2403 if (e) e.stopPropagation(); 2404 2405 this.$button.trigger('click.bs.dropdown.data-api'); 2406 }, 2407 2408 keydown: function(e) { 2409 var $this = $(this), 2410 isToggle = $this.hasClass('dropdown-toggle'), 2411 $parent = isToggle ? $this.closest('.dropdown') : $this.closest(Selector.MENU), 2412 that = $parent.data('this'), 2413 $items = that.findLis(), 2414 index, 2415 isActive, 2416 liActive, 2417 activeLi, 2418 offset, 2419 updateScroll = false, 2420 downOnTab = e.which === keyCodes.TAB && !isToggle && !that.options.selectOnTab, 2421 isArrowKey = REGEXP_ARROW.test(e.which) || downOnTab, 2422 scrollTop = that.$menuInner[0].scrollTop, 2423 isVirtual = that.isVirtual(), 2424 position0 = isVirtual === true ? that.selectpicker.view.position0 : 0; 2425 2426 isActive = that.$newElement.hasClass(classNames.SHOW); 2427 2428 if (!isActive && 2429 ( 2430 isArrowKey ||
2431 e.which >= 48 && e.which <= 57 || 2432 e.which >= 96 && e.which <= 105 || 2433 e.which >= 65 && e.which <= 90 2434 ) 2435 ) { 2436 that.$button.trigger('click.bs.dropdown.data-api'); 2437 } 2438 2439 if (e.which === keyCodes.ESCAPE && isActive) { 2440 e.preventDefault(); 2441 that.$button.trigger('click.bs.dropdown.data-api').focus(); 2442 } 2443 2444 if (isArrowKey) { // if up or down 2445 if (!$items.length) return; 2446 2447 // $items.index/.filter is too slow with a large list and no virtual scroll 2448 index = isVirtual === true ? $items.index($items.filter('.active')) : that.selectpicker.current.map.newIndex[that.activeIndex]; 2449 2450 if (index === undefined) index = -1; 2451 2452 if (index !== -1) { 2453 liActive = that.selectpicker.current.elements[index + position0]; 2454 liActive.classList.remove('active'); 2455 if (liActive.firstChild) liActive.firstChild.classList.remove('active'); 2456 } 2457 2458 if (e.which === keyCodes.ARROW_UP) { // up 2459 if (index !== -1) index--; 2460 if (index + position0 < 0) index += $items.length; 2461 2462 if (!that.selectpicker.view.canHighlight[index + position0]) { 2463 index = that.selectpicker.view.canHighlight.slice(0, index + position0).lastIndexOf(true) - position0; 2464 if (index === -1) index = $items.length - 1; 2465 } 2466 } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down 2467 index++; 2468 if (index + position0 >= that.selectpicker.view.canHighlight.length) index = 0; 2469 2470 if (!that.selectpicker.view.canHighlight[index + position0]) { 2471 index = index + 1 + that.selectpicker.view.canHighlight.slice(index + position0 + 1).indexOf(true); 2472 } 2473 } 2474 2475 e.preventDefault(); 2476 2477 var liActiveIndex = position0 + index; 2478 2479 if (e.which === keyCodes.ARROW_UP) { // up 2480 // scroll to bottom and highlight last option 2481 if (position0 === 0 && index === $items.length - 1) { 2482 that.$menuInner[0].scrollTop = that.$menuInner[0].scrollHeight; 2483 2484 liActiveIndex = that.selectpicker.current.elements.length - 1; 2485 } else { 2486 activeLi = that.selectpicker.current.data[liActiveIndex]; 2487 offset = activeLi.position - activeLi.height; 2488 2489 updateScroll = offset < scrollTop; 2490 } 2491 } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down 2492 // scroll to top and highlight first option 2493 if (index === 0) { 2494 that.$menuInner[0].scrollTop = 0; 2495 2496 liActiveIndex = 0; 2497 } else { 2498 activeLi = that.selectpicker.current.data[liActiveIndex]; 2499 offset = activeLi.position - that.sizeInfo.menuInnerHeight; 2500 2501 updateScroll = offset > scrollTop; 2502 } 2503 } 2504 2505 liActive = that.selectpicker.current.elements[liActiveIndex]; 2506 2507 if (liActive) { 2508 liActive.classList.add('active'); 2509 if (liActive.firstChild) liActive.firstChild.classList.add('active'); 2510 } 2511 2512 that.activeIndex = that.selectpicker.current.map.originalIndex[liActiveIndex]; 2513 2514 that.selectpicker.view.currentActive = liActive; 2515 2516 if (updateScroll) that.$menuInner[0].scrollTop = offset; 2517 2518 if (that.options.liveSearch) { 2519 that.$searchbox.focus(); 2520 } else { 2521 $this.focus(); 2522 } 2523 } else if (!$this.is('input') && 2524 !REGEXP_TAB_OR_ESCAPE.test(e.which) || 2525 (e.which === keyCodes.SPACE && that.selectpicker.keydown.keyHistory) 2526 ) { 2527 var searchMatch, 2528 matches = [], 2529 keyHistory; 2530 2531 e.preventDefault(); 2532 2533 that.selectpicker.keydown.keyHistory += keyCodeMap[e.which]; 2534 2535 if (that.selectpicker.keydown.resetKeyHistory.cancel) clearTimeout(that.selectpicker.keydown.resetKeyHistory.cancel); 2536 that.selectpicker.keydown.resetKeyHistory.cancel = that.selectpicker.keydown.resetKeyHistory.start(); 2537 2538 keyHistory = that.selectpicker.keydown.keyHistory; 2539 2540 // if all letters are the same, set keyHistory to just the first character when searching
2541 if (/^(.)\1+$/.test(keyHistory)) { 2542 keyHistory = keyHistory.charAt(0); 2543 } 2544 2545 // find matches 2546 for (var i = 0; i < that.selectpicker.current.data.length; i++) { 2547 var li = that.selectpicker.current.data[i], 2548 hasMatch; 2549 2550 hasMatch = stringSearch(li, keyHistory, 'startsWith', true); 2551 2552 if (hasMatch && that.selectpicker.view.canHighlight[i]) { 2553 li.index = i; 2554 matches.push(li.originalIndex); 2555 } 2556 } 2557 2558 if (matches.length) { 2559 var matchIndex = 0; 2560 2561 $items.removeClass('active').find('a').removeClass('active'); 2562 2563 // either only one key has been pressed or they are all the same key 2564 if (keyHistory.length === 1) { 2565 matchIndex = matches.indexOf(that.activeIndex); 2566 2567 if (matchIndex === -1 || matchIndex === matches.length - 1) { 2568 matchIndex = 0; 2569 } else { 2570 matchIndex++; 2571 } 2572 } 2573 2574 searchMatch = that.selectpicker.current.map.newIndex[matches[matchIndex]]; 2575 2576 activeLi = that.selectpicker.current.data[searchMatch]; 2577 2578 if (scrollTop - activeLi.position > 0) { 2579 offset = activeLi.position - activeLi.height; 2580 updateScroll = true; 2581 } else { 2582 offset = activeLi.position - that.sizeInfo.menuInnerHeight; 2583 // if the option is already visible at the current scroll position, just keep it the same 2584 updateScroll = activeLi.position > scrollTop + that.sizeInfo.menuInnerHeight; 2585 } 2586 2587 liActive = that.selectpicker.current.elements[searchMatch]; 2588 liActive.classList.add('active'); 2589 if (liActive.firstChild) liActive.firstChild.classList.add('active'); 2590 that.activeIndex = matches[matchIndex]; 2591 2592 liActive.firstChild.focus(); 2593 2594 if (updateScroll) that.$menuInner[0].scrollTop = offset; 2595 2596 $this.focus(); 2597 } 2598 } 2599 2600 // Select focused option if "Enter", "Spacebar" or "Tab" (when selectOnTab is true) are pressed inside the menu. 2601 if ( 2602 isActive && 2603 ( 2604 (e.which === keyCodes.SPACE && !that.selectpicker.keydown.keyHistory) || 2605 e.which === keyCodes.ENTER || 2606 (e.which === keyCodes.TAB && that.options.selectOnTab) 2607 ) 2608 ) { 2609 if (e.which !== keyCodes.SPACE) e.preventDefault(); 2610 2611 if (!that.options.liveSearch || e.which !== keyCodes.SPACE) { 2612 that.$menuInner.find('.active a').trigger('click', true); // retain active class 2613 $this.focus(); 2614 2615 if (!that.options.liveSearch) { 2616 // Prevent screen from scrolling if the user hits the spacebar 2617 e.preventDefault(); 2618 // Fixes spacebar selection of dropdown items in FF & IE 2619 $(document).data('spaceSelect', true); 2620 } 2621 } 2622 } 2623 }, 2624 2625 mobile: function() { 2626 this.$element.addClass('mobile-device'); 2627 }, 2628 2629 refresh: function() { 2630 // update options if data attributes have been changed 2631 var config = $.extend({}, this.options, this.$element.data()); 2632 this.options = config; 2633 2634 this.selectpicker.main.map.newIndex = {}; 2635 this.selectpicker.main.map.originalIndex = {}; 2636 this.createLi(); 2637 this.checkDisabled(); 2638 this.render(); 2639 this.setStyle(); 2640 this.setWidth(); 2641 2642 this.setSize(true); 2643 2644 this.$element.trigger('refreshed.bs.select'); 2645 }, 2646 2647 hide: function() { 2648 this.$newElement.hide(); 2649 }, 2650 2651 show: function() { 2652 this.$newElement.show(); 2653 }, 2654 2655 remove: function() { 2656 this.$newElement.remove(); 2657 this.$element.remove(); 2658 }, 2659 2660 destroy: function() { 2661 this.$newElement.before(this.$element).remove(); 2662 2663 if (this.$bsContainer) { 2664 this.$bsContainer.remove(); 2665 } else { 2666 this.$menu.remove(); 2667 } 2668 2669 this.$element 2670 .off('.bs.select') 2671 .removeData('selectpicker') 2672 .removeClass('bs-select-hidden selectpicker'); 2673 } 2674 }; 2675 2676 // SELECTPICKER PLUGIN DEFINITION 2677 // ============================== 2678 function Plugin(option) { 2679 // get the args of the outer function.. 2680 var args = arguments; 2681 // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them
2682 // to get lost/corrupted in android 2.3 and IE9 #715 #775 2683 var _option = option; 2684 2685 [].shift.apply(args); 2686 2687 // if the version was not set successfully 2688 if (!version.success) { 2689 // try to retreive it again 2690 try { 2691 version.full = ($.fn.dropdown.Constructor.VERSION || '').split(' ')[0].split('.'); 2692 } 2693 // fall back to use BootstrapVersion 2694 catch (err) { 2695 version.full = Selectpicker.BootstrapVersion.split(' ')[0].split('.'); 2696 } 2697 2698 version.major = version.full[0]; 2699 version.success = true; 2700 2701 if (version.major === '4') { 2702 classNames.DIVIDER = 'dropdown-divider'; 2703 classNames.SHOW = 'show'; 2704 classNames.BUTTONCLASS = 'btn-light'; 2705 Selectpicker.DEFAULTS.style = classNames.BUTTONCLASS = 'btn-light'; 2706 classNames.POPOVERHEADER = 'popover-header'; 2707 } 2708 } 2709 2710 var value; 2711 var chain = this.each(function() { 2712 var $this = $(this); 2713 if ($this.is('select')) { 2714 var data = $this.data('selectpicker'), 2715 options = typeof _option == 'object' && _option; 2716 2717 if (!data) { 2718 var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, $this.data(), options); 2719 config.template = $.extend({}, Selectpicker.DEFAULTS.template, ($.fn.selectpicker.defaults ? $.fn.selectpicker.defaults.template : {}), $this.data().template, options.template); 2720 $this.data('selectpicker', (data = new Selectpicker(this, config))); 2721 } else if (options) { 2722 for (var i in options) { 2723 if (options.hasOwnProperty(i)) { 2724 data.options[i] = options[i]; 2725 } 2726 } 2727 } 2728 2729 if (typeof _option == 'string') { 2730 if (data[_option] instanceof Function) { 2731 value = data[_option].apply(data, args); 2732 } else { 2733 value = data.options[_option]; 2734 } 2735 } 2736 } 2737 }); 2738 2739 if (typeof value !== 'undefined') { 2740 //noinspection JSUnusedAssignment 2741 return value; 2742 } else { 2743 return chain; 2744 } 2745 } 2746 2747 var old = $.fn.selectpicker; 2748 $.fn.selectpicker = Plugin; 2749 $.fn.selectpicker.Constructor = Selectpicker; 2750 2751 // SELECTPICKER NO CONFLICT 2752 // ======================== 2753 $.fn.selectpicker.noConflict = function() { 2754 $.fn.selectpicker = old; 2755 return this; 2756 }; 2757 2758 $(document) 2759 .off('keydown.bs.dropdown.data-api') 2760 .on('keydown.bs.select', '.bootstrap-select [data-toggle="dropdown"], .bootstrap-select [role="listbox"], .bs-searchbox input', Selectpicker.prototype.keydown) 2761 .on('focusin.modal', '.bootstrap-select [data-toggle="dropdown"], .bootstrap-select [role="listbox"], .bs-searchbox input', function(e) { 2762 e.stopPropagation(); 2763 }); 2764 2765 // SELECTPICKER DATA-API 2766 // ===================== 2767 $(window).on('load.bs.select.data-api', function() { 2768 $('.selectpicker').each(function() { 2769 var $selectpicker = $(this); 2770 Plugin.call($selectpicker, $selectpicker.data()); 2771 }) 2772 }); 2773 })(jQuery); 2774 2775 2776}));
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.