PageSourceSearch

https://mattandmikegolf.com/assets/js/plugins/bootstrap-selectpicker.js

js mattandmikegolf.com collected 2026-10-07 14:26:02 UTC 116,292 bytes, 3,300 lines download raw bytes

vendor: 13,141 bytes, lines 1-430
1/*!
2 * Bootstrap-select v1.13.12 (https://developer.snapappointments.com/bootstrap-select)
3 *
4 * Copyright 2012-2019 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 DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];
29
30    var uriAttrs = [
31      'background',
32      'cite',
33      'href',
34      'itemtype',
35      'longdesc',
36      'poster',
37      'src',
38      'xlink:href'
39    ];
40
41    var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
42
43    var DefaultWhitelist = {
44      // Global attributes allowed on any supplied element below.
45      '*': ['class', 'dir', 'id', 'lang', 'role', 'tabindex', 'style', ARIA_ATTRIBUTE_PATTERN],
46      a: ['target', 'href', 'title', 'rel'],
47      area: [],
48      b: [],
49      br: [],
50      col: [],
51      code: [],
52      div: [],
53      em: [],
54      hr: [],
55      h1: [],
56      h2: [],
57      h3: [],
58      h4: [],
59      h5: [],
60      h6: [],
61      i: [],
62      img: ['src', 'alt', 'title', 'width', 'height'],
63      li: [],
64      ol: [],
65      p: [],
66      pre: [],
67      s: [],
68      small: [],
69      span: [],
70      sub: [],
71      sup: [],
72      strong: [],
73      u: [],
74      ul: []
75    }
76
77    /**
78     * A pattern that recognizes a commonly useful subset of URLs that are safe.
79     *
80     * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
81     */
82    var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi;
83
84    /**
85     * A pattern that matches safe data URLs. Only matches image, video and audio types.
86     *
87     * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
88     */
89    var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;
90
91    function allowedAttribute(attr, allowedAttributeList) {
92      var attrName = attr.nodeName.toLowerCase()
93
94      if ($.inArray(attrName, allowedAttributeList) !== -1) {
95        if ($.inArray(attrName, uriAttrs) !== -1) {
96          return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
97        }
98
99        return true
100      }
101
102      var regExp = $(allowedAttributeList).filter(function(index, value) {
103        return value instanceof RegExp
104      })
105
106      // Check if a regular expression validates the attribute.
107      for (var i = 0, l = regExp.length; i < l; i++) {
108        if (attrName.match(regExp[i])) {
109          return true
110        }
111      }
112
113      return false
114    }
115
116    function sanitizeHtml(unsafeElements, whiteList, sanitizeFn) {
117      if (sanitizeFn && typeof sanitizeFn === 'function') {
118        return sanitizeFn(unsafeElements);
119      }
120
121      var whitelistKeys = Object.keys(whiteList);
122
123      for (var i = 0, len = unsafeElements.length; i < len; i++) {
124        var elements = unsafeElements[i].querySelectorAll('*');
125
126        for (var j = 0, len2 = elements.length; j < len2; j++) {
127          var el = elements[j];
128          var elName = el.nodeName.toLowerCase();
129
130          if (whitelistKeys.indexOf(elName) === -1) {
131            el.parentNode.removeChild(el);
132
133            continue;
134          }
135
136          var attributeList = [].slice.call(el.attributes);
137          var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);
138
139          for (var k = 0, len3 = attributeList.length; k < len3; k++) {
140            var attr = attributeList[k];
141
142            if (!allowedAttribute(attr, whitelistedAttributes)) {
143              el.removeAttribute(attr.nodeName);
144            }
145          }
146        }
147      }
148    }
149
150    // Polyfill for browsers with no classList support
151    // Remove in v2
152    if (!('classList' in document.createElement('_'))) {
153      (function(view) {
154        if (!('Element' in view)) return;
155
156        var classListProp = 'classList',
157          protoProp = 'prototype',
158          elemCtrProto = view.Element[protoProp],
159          objCtr = Object,
160          classListGetter = function() {
161            var $elem = $(this);
162
163            return {
164              add: function(classes) {
165                classes = Array.prototype.slice.call(arguments).join(' ');
166                return $elem.addClass(classes);
167              },
168              remove: function(classes) {
169                classes = Array.prototype.slice.call(arguments).join(' ');
170                return $elem.removeClass(classes);
171              },
172              toggle: function(classes, force) {
173                return $elem.toggleClass(classes, force);
174              },
175              contains: function(classes) {
176                return $elem.hasClass(classes);
177              }
178            }
179          };
180
181        if (objCtr.defineProperty) {
182          var classListPropDesc = {
183            get: classListGetter,
184            enumerable: true,
185            configurable: true
186          };
187          try {
188            objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
189          } catch (ex) { // IE 8 doesn't support enumerable:true
190            // adding undefined to fight this issue https://github.com/eligrey/classList.js/issues/36
191            // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected
192            if (ex.number === undefined || ex.number === -0x7FF5EC54) {
193              classListPropDesc.enumerable = false;
194              objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
195            }
196          }
197        } else if (objCtr[protoProp].__defineGetter__) {
198          elemCtrProto.__defineGetter__(classListProp, classListGetter);
199        }
200      }(window));
201    }
202
203    var testElement = document.createElement('_');
204
205    testElement.classList.add('c1', 'c2');
206
207    if (!testElement.classList.contains('c2')) {
208      var _add = DOMTokenList.prototype.add,
209        _remove = DOMTokenList.prototype.remove;
210
211      DOMTokenList.prototype.add = function() {
212        Array.prototype.forEach.call(arguments, _add.bind(this));
213      }
214
215      DOMTokenList.prototype.remove = function() {
216        Array.prototype.forEach.call(arguments, _remove.bind(this));
217      }
218    }
219
220    testElement.classList.toggle('c3', false);
221
222    // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
223    // support the second argument.
224    if (testElement.classList.contains('c3')) {
225      var _toggle = DOMTokenList.prototype.toggle;
226
227      DOMTokenList.prototype.toggle = function(token, force) {
228        if (1 in arguments && !this.contains(token) === !force) {
229          return force;
230        } else {
231          return _toggle.call(this, token);
232        }
233      };
234    }
235
236    testElement = null;
237
238    // shallow array comparison
239    function isEqual(array1, array2) {
240      return array1.length === array2.length && array1.every(function(element, index) {
241        return element === array2[index];
242      });
243    };
244
245    // <editor-fold desc="Shims">
246    if (!String.prototype.startsWith) {
247      (function() {
248        'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
249        var defineProperty = (function() {
250          // IE 8 only supports `Object.defineProperty` on DOM elements
251          try {
252            var object = {};
253            var $defineProperty = Object.defineProperty;
254            var result = $defineProperty(object, object, object) && $defineProperty;
255          } catch (error) {}
256          return result;
257        }());
258        var toString = {}.toString;
259        var startsWith = function(search) {
260          if (this == null) {
261            throw new TypeError();
262          }
263          var string = String(this);
264          if (search && toString.call(search) == '[object RegExp]') {
265            throw new TypeError();
266          }
267          var stringLength = string.length;
268          var searchString = String(search);
269          var searchLength = searchString.length;
270          var position = arguments.length > 1 ? arguments[1] : undefined;
271          // `ToInteger`
272          var pos = position ? Number(position) : 0;
273          if (pos != pos) { // better `isNaN`
274            pos = 0;
275          }
276          var start = Math.min(Math.max(pos, 0), stringLength);
277          // Avoid the `indexOf` call if no match is possible
278          if (searchLength + start > stringLength) {
279            return false;
280          }
281          var index = -1;
282          while (++index < searchLength) {
283            if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {
284              return false;
285            }
286          }
287          return true;
288        };
289        if (defineProperty) {
290          defineProperty(String.prototype, 'startsWith', {
291            'value': startsWith,
292            'configurable': true,
293            'writable': true
294          });
295        } else {
296          String.prototype.startsWith = startsWith;
297        }
298      }());
299    }
300
301    if (!Object.keys) {
302      Object.keys = function(
303        o, // object
304        k, // key
305        r // result array
306      ) {
307        // initialize object and result
308        r = [];
309        // iterate over object keys
310        for (k in o) {
311          // fill result array with non-prototypical keys
312          r.hasOwnProperty.call(o, k) && r.push(k);
313        }
314        // return result
315        return r;
316      };
317    }
318
319    if (HTMLSelectElement && !HTMLSelectElement.prototype.hasOwnProperty('selectedOptions')) {
320      Object.defineProperty(HTMLSelectElement.prototype, 'selectedOptions', {
321        get: function() {
322          return this.querySelectorAll(':checked');
323        }
324      });
325    }
326
327    function getSelectedOptions(select, ignoreDisabled) {
328      var selectedOptions = select.selectedOptions,
329        options = [],
330        opt;
331
332      if (ignoreDisabled) {
333        for (var i = 0, len = selectedOptions.length; i < len; i++) {
334          opt = selectedOptions[i];
335
336          if (!(opt.disabled || opt.parentNode.tagName === 'OPTGROUP' && opt.parentNode.disabled)) {
337            options.push(opt);
338          }
339        }
340
341        return options;
342      }
343
344      return selectedOptions;
345    }
346
347    // much faster than $.val()
348    function getSelectValues(select, selectedOptions) {
349      var value = [],
350        options = selectedOptions || select.selectedOptions,
351        opt;
352
353      for (var i = 0, len = options.length; i < len; i++) {
354        opt = options[i];
355
356        if (!(opt.disabled || opt.parentNode.tagName === 'OPTGROUP' && opt.parentNode.disabled)) {
357          value.push(opt.value || opt.text);
358        }
359      }
360
361      if (!select.multiple) {
362        return !value.length ? null : value[0];
363      }
364
365      return value;
366    }
367
368    // set data-selected on select element if the value has been programmatically selected
369    // prior to initialization of bootstrap-select
370    // * consider removing or replacing an alternative method *
371    var valHooks = {
372      useDefault: false,
373      _set: $.valHooks.select.set
374    };
375
376    $.valHooks.select.set = function(elem, value) {
377      if (value && !valHooks.useDefault) $(elem).data('selected', true);
378
379      return valHooks._set.apply(this, arguments);
380    };
381
382    var changedArguments = null;
383
384    var EventIsSupported = (function() {
385      try {
386        new Event('change');
387        return true;
388      } catch (e) {
389        return false;
390      }
391    })();
392
393    $.fn.triggerNative = function(eventName) {
394      var el = this[0],
395        event;
396
397      if (el.dispatchEvent) { // for modern browsers & IE9+
398        if (EventIsSupported) {
399          // For modern browsers
400          event = new Event(eventName, {
401            bubbles: true
402          });
403        } else {
404          // For IE since it doesn't support Event constructor
405          event = document.createEvent('Event');
406          event.initEvent(eventName, true, false);
407        }
408
409        el.dispatchEvent(event);
410      } else if (el.fireEvent) { // for IE8
411        event = document.createEventObject();
412        event.eventType = eventName;
413        el.fireEvent('on' + eventName, event);
414      } else {
415        // fall back to jQuery.trigger
416        this.trigger(eventName);
417      }
418    };
419    // </editor-fold>
420
421    function stringSearch(li, searchString, method, normalize) {
422      var stringTypes = [
423          'display',
424          'subtext',
425          'tokens'
426        ],
427        searchSuccess = false;
428
429      for (var i = 0; i < stringTypes.length; i++) {
430        var stringType = stringTypes[i],
431          string = li[stringType];
432
433        if (string) {
434          string = string.toString();
435
436          // Strip HTML tags. This isn't perfect, but it's much faster than any other method
437          if (stringType === 'display') {
438            string = string.replace(/<[^>]+>/g, '');
439          }
440
441          if (normalize) string = normalizeToBase(string);
442          string = string.toUpperCase();
443
444          if (method === 'contains') {
445            searchSuccess = string.indexOf(searchString) >= 0;
446          } else {
447            searchSuccess = string.startsWith(searchString);
448          }
449
450          if (searchSuccess) break;
451        }
452      }
453
454      return searchSuccess;
455    }
456
457    function toInteger(value) {
458      return parseInt(value, 10) || 0;
459    }
460
461    // Borrowed from Lodash (_.deburr)
462    /** Used to map Latin Unicode letters to basic Latin letters. */
463    var deburredLetters = {
464      // Latin-1 Supplement block.
465      '\xc0': 'A',
466      '\xc1': 'A',
467      '\xc2': 'A',
468      '\xc3': 'A',
469      '\xc4': 'A',
470      '\xc5': 'A',
471      '\xe0': 'a',
472      '\xe1': 'a',
473      '\xe2': 'a',
474      '\xe3': 'a',
475      '\xe4': 'a',
476      '\xe5': 'a',
477      '\xc7': 'C',
478      '\xe7': 'c',
479      '\xd0': 'D',
480      '\xf0': 'd',
481      '\xc8': 'E',
482      '\xc9': 'E',
483      '\xca': 'E',
484      '\xcb': 'E',
485      '\xe8': 'e',
486      '\xe9': 'e',
487      '\xea': 'e',
488      '\xeb': 'e',
489      '\xcc': 'I',
490      '\xcd': 'I',
491      '\xce': 'I',
492      '\xcf': 'I',
493      '\xec': 'i',
494      '\xed': 'i',
495      '\xee': 'i',
496      '\xef': 'i',
497      '\xd1': 'N',
498      '\xf1': 'n',
499      '\xd2': 'O',
500      '\xd3': 'O',
501      '\xd4': 'O',
502      '\xd5': 'O',
503      '\xd6': 'O',
504      '\xd8': 'O',
505      '\xf2': 'o',
506      '\xf3': 'o',
507      '\xf4': 'o',
508      '\xf5': 'o',
509      '\xf6': 'o',
510      '\xf8': 'o',
511      '\xd9': 'U',
512      '\xda': 'U',
513      '\xdb': 'U',
514      '\xdc': 'U',
515      '\xf9': 'u',
516      '\xfa': 'u',
517      '\xfb': 'u',
518      '\xfc': 'u',
519      '\xdd': 'Y',
520      '\xfd': 'y',
521      '\xff': 'y',
522      '\xc6': 'Ae',
523      '\xe6': 'ae',
524      '\xde': 'Th',
525      '\xfe': 'th',
526      '\xdf': 'ss',
527      // Latin Extended-A block.
528      '\u0100': 'A',
529      '\u0102': 'A',
530      '\u0104': 'A',
531      '\u0101': 'a',
532      '\u0103': 'a',
533      '\u0105': 'a',
534      '\u0106': 'C',
535      '\u0108': 'C',
536      '\u010a': 'C',
537      '\u010c': 'C',
538      '\u0107': 'c',
539      '\u0109': 'c',
540      '\u010b': 'c',
541      '\u010d': 'c',
542      '\u010e': 'D',
543      '\u0110': 'D',
544      '\u010f': 'd',
545      '\u0111': 'd',
546      '\u0112': 'E',
547      '\u0114': 'E',
548      '\u0116': 'E',
549      '\u0118': 'E',
550      '\u011a': 'E',
551      '\u0113': 'e',
552      '\u0115': 'e',
553      '\u0117': 'e',
554      '\u0119': 'e',
555      '\u011b': 'e',
556      '\u011c': 'G',
557      '\u011e': 'G',
558      '\u0120': 'G',
559      '\u0122': 'G',
560      '\u011d': 'g',
561      '\u011f': 'g',
562      '\u0121': 'g',
563      '\u0123': 'g',
564      '\u0124': 'H',
565      '\u0126': 'H',
566      '\u0125': 'h',
567      '\u0127': 'h',
568      '\u0128': 'I',
569      '\u012a': 'I',
570      '\u012c': 'I',
571      '\u012e': 'I',
572      '\u0130': 'I',
573      '\u0129': 'i',
574      '\u012b': 'i',
575      '\u012d': 'i',
576      '\u012f': 'i',
577      '\u0131': 'i',
578      '\u0134': 'J',
579      '\u0135': 'j',
580      '\u0136': 'K',
581      '\u0137': 'k',
582      '\u0138': 'k',
583      '\u0139': 'L',
584      '\u013b': 'L',
585      '\u013d': 'L',
586      '\u013f': 'L',
587      '\u0141': 'L',
588      '\u013a': 'l',
589      '\u013c': 'l',
590      '\u013e': 'l',
591      '\u0140': 'l',
592      '\u0142': 'l',
593      '\u0143': 'N',
594      '\u0145': 'N',
595      '\u0147': 'N',
596      '\u014a': 'N',
597      '\u0144': 'n',
598      '\u0146': 'n',
599      '\u0148': 'n',
600      '\u014b': 'n',
601      '\u014c': 'O',
602      '\u014e': 'O',
603      '\u0150': 'O',
604      '\u014d': 'o',
605      '\u014f': 'o',
606      '\u0151': 'o',
607      '\u0154': 'R',
608      '\u0156': 'R',
609      '\u0158': 'R',
610      '\u0155': 'r',
611      '\u0157': 'r',
612      '\u0159': 'r',
613      '\u015a': 'S',
614      '\u015c': 'S',
615      '\u015e': 'S',
616      '\u0160': 'S',
617      '\u015b': 's',
618      '\u015d': 's',
619      '\u015f': 's',
620      '\u0161': 's',
621      '\u0162': 'T',
622      '\u0164': 'T',
623      '\u0166': 'T',
624      '\u0163': 't',
625      '\u0165': 't',
626      '\u0167': 't',
627      '\u0168': 'U',
628      '\u016a': 'U',
629      '\u016c': 'U',
630      '\u016e': 'U',
631      '\u0170': 'U',
632      '\u0172': 'U',
633      '\u0169': 'u',
634      '\u016b': 'u',
635      '\u016d': 'u',
636      '\u016f': 'u',
637      '\u0171': 'u',
638      '\u0173': 'u',
639      '\u0174': 'W',
640      '\u0175': 'w',
641      '\u0176': 'Y',
642      '\u0177': 'y',
643      '\u0178': 'Y',
644      '\u0179': 'Z',
645      '\u017b': 'Z',
646      '\u017d': 'Z',
647      '\u017a': 'z',
648      '\u017c': 'z',
649      '\u017e': 'z',
650      '\u0132': 'IJ',
651      '\u0133': 'ij',
652      '\u0152': 'Oe',
653      '\u0153': 'oe',
654      '\u0149': "'n",
655      '\u017f': 's'
656    };
657
658    /** Used to match Latin Unicode letters (excluding mathematical operators). */
vendor: 31,457 bytes, lines 659-1555
659    var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
660
661    /** Used to compose unicode character classes. */
662    var rsComboMarksRange = '\\u0300-\\u036f',
663      reComboHalfMarksRange = '\\ufe20-\\ufe2f',
664      rsComboSymbolsRange = '\\u20d0-\\u20ff',
665      rsComboMarksExtendedRange = '\\u1ab0-\\u1aff',
666      rsComboMarksSupplementRange = '\\u1dc0-\\u1dff',
667      rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange + rsComboMarksExtendedRange + rsComboMarksSupplementRange;
668
669    /** Used to compose unicode capture groups. */
670    var rsCombo = '[' + rsComboRange + ']';
671
672    /**
673     * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
674     * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
675     */
676    var reComboMark = RegExp(rsCombo, 'g');
677
678    function deburrLetter(key) {
679      return deburredLetters[key];
680    };
681
682    function normalizeToBase(string) {
683      string = string.toString();
684      return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
685    }
686
687    // List of HTML entities for escaping.
688    var escapeMap = {
689      '&': '&amp;',
690      '<': '&lt;',
691      '>': '&gt;',
692      '"': '&quot;',
693      "'": '&#x27;',
694      '`': '&#x60;'
695    };
696
697    // Functions for escaping and unescaping strings to/from HTML interpolation.
698    var createEscaper = function(map) {
699      var escaper = function(match) {
700        return map[match];
701      };
702      // Regexes for identifying a key that needs to be escaped.
703      var source = '(?:' + Object.keys(map).join('|') + ')';
704      var testRegexp = RegExp(source);
705      var replaceRegexp = RegExp(source, 'g');
706      return function(string) {
707        string = string == null ? '' : '' + string;
708        return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
709      };
710    };
711
712    var htmlEscape = createEscaper(escapeMap);
713
714    /**
715     * ------------------------------------------------------------------------
716     * Constants
717     * ------------------------------------------------------------------------
718     */
719
720    var keyCodeMap = {
721      32: ' ',
722      48: '0',
723      49: '1',
724      50: '2',
725      51: '3',
726      52: '4',
727      53: '5',
728      54: '6',
729      55: '7',
730      56: '8',
731      57: '9',
732      59: ';',
733      65: 'A',
734      66: 'B',
735      67: 'C',
736      68: 'D',
737      69: 'E',
738      70: 'F',
739      71: 'G',
740      72: 'H',
741      73: 'I',
742      74: 'J',
743      75: 'K',
744      76: 'L',
745      77: 'M',
746      78: 'N',
747      79: 'O',
748      80: 'P',
749      81: 'Q',
750      82: 'R',
751      83: 'S',
752      84: 'T',
753      85: 'U',
754      86: 'V',
755      87: 'W',
756      88: 'X',
757      89: 'Y',
758      90: 'Z',
759      96: '0',
760      97: '1',
761      98: '2',
762      99: '3',
763      100: '4',
764      101: '5',
765      102: '6',
766      103: '7',
767      104: '8',
768      105: '9'
769    };
770
771    var keyCodes = {
772      ESCAPE: 27, // KeyboardEvent.which value for Escape (Esc) key
773      ENTER: 13, // KeyboardEvent.which value for Enter key
774      SPACE: 32, // KeyboardEvent.which value for space key
775      TAB: 9, // KeyboardEvent.which value for tab key
776      ARROW_UP: 38, // KeyboardEvent.which value for up arrow key
777      ARROW_DOWN: 40 // KeyboardEvent.which value for down arrow key
778    }
779
780    var version = {
781      success: false,
782      major: '3'
783    };
784
785    try {
786      version.full = ($.fn.dropdown.Constructor.VERSION || '').split(' ')[0].split('.');
787      version.major = version.full[0];
788      version.success = true;
789    } catch (err) {
790      // do nothing
791    }
792
793    var selectId = 0;
794
795    var EVENT_KEY = '.bs.select';
796
797    var classNames = {
798      DISABLED: 'disabled',
799      DIVIDER: 'divider',
800      SHOW: 'open',
801      DROPUP: 'dropup',
802      MENU: 'dropdown-menu',
803      MENURIGHT: 'dropdown-menu-right',
804      MENULEFT: 'dropdown-menu-left',
805      // to-do: replace with more advanced template/customization options
806      BUTTONCLASS: 'btn-default',
807      POPOVERHEADER: 'popover-title',
808      ICONBASE: 'material-icons',
809      TICKICON: 'glyphicon-ok'
810    }
811
812    var Selector = {
813      MENU: '.' + classNames.MENU
814    }
815
816    var elementTemplates = {
817      span: document.createElement('span'),
818      i: document.createElement('i'),
819      subtext: document.createElement('small'),
820      a: document.createElement('a'),
821      li: document.createElement('li'),
822      whitespace: document.createTextNode('\u00A0'),
823      fragment: document.createDocumentFragment()
824    }
825
826    elementTemplates.a.setAttribute('role', 'option');
827    elementTemplates.subtext.className = 'text-muted';
828
829    elementTemplates.text = elementTemplates.span.cloneNode(false);
830    elementTemplates.text.className = 'text';
831
832    elementTemplates.checkMark = elementTemplates.span.cloneNode(false);
833
834    var REGEXP_ARROW = new RegExp(keyCodes.ARROW_UP + '|' + keyCodes.ARROW_DOWN);
835    var REGEXP_TAB_OR_ESCAPE = new RegExp('^' + keyCodes.TAB + '$|' + keyCodes.ESCAPE);
836
837    var generateOption = {
838      li: function(content, classes, optgroup) {
839        var li = elementTemplates.li.cloneNode(false);
840
841        if (content) {
842          if (content.nodeType === 1 || content.nodeType === 11) {
843            li.appendChild(content);
844          } else {
845            li.innerHTML = content;
846          }
847        }
848
849        if (typeof classes !== 'undefined' && classes !== '') li.className = classes;
850        if (typeof optgroup !== 'undefined' && optgroup !== null) li.classList.add('optgroup-' + optgroup);
851
852        return li;
853      },
854
855      a: function(text, classes, inline) {
856        var a = elementTemplates.a.cloneNode(true);
857
858        if (text) {
859          if (text.nodeType === 11) {
860            a.appendChild(text);
861          } else {
862            a.insertAdjacentHTML('beforeend', text);
863          }
864        }
865
866        if (typeof classes !== 'undefined' && classes !== '') a.className = classes;
867        if (version.major === '4') a.classList.add('dropdown-item');
868        if (inline) a.setAttribute('style', inline);
869
870        return a;
871      },
872
873      text: function(options, useFragment) {
874        var textElement = elementTemplates.text.cloneNode(false),
875          subtextElement,
876          iconElement;
877
878        if (options.content) {
879          textElement.innerHTML = options.content;
880        } else {
881          textElement.textContent = options.text;
882
883          if (options.icon) {
884            var whitespace = elementTemplates.whitespace.cloneNode(false);
885
886            // need to use <i> for icons in the button to prevent a breaking change
887            // note: switch to span in next major release
888            iconElement = (useFragment === true ? elementTemplates.i : elementTemplates.span).cloneNode(false);
889            iconElement.className = options.iconBase + ' ' + options.icon;
890
891            elementTemplates.fragment.appendChild(iconElement);
892            elementTemplates.fragment.appendChild(whitespace);
893          }
894
895          if (options.subtext) {
896            subtextElement = elementTemplates.subtext.cloneNode(false);
897            subtextElement.textContent = options.subtext;
898            textElement.appendChild(subtextElement);
899          }
900        }
901
902        if (useFragment === true) {
903          while (textElement.childNodes.length > 0) {
904            elementTemplates.fragment.appendChild(textElement.childNodes[0]);
905          }
906        } else {
907          elementTemplates.fragment.appendChild(textElement);
908        }
909
910        return elementTemplates.fragment;
911      },
912
913      label: function(options) {
914        var textElement = elementTemplates.text.cloneNode(false),
915          subtextElement,
916          iconElement;
917
918        textElement.innerHTML = options.label;
919
920        if (options.icon) {
921          var whitespace = elementTemplates.whitespace.cloneNode(false);
922
923          iconElement = elementTemplates.span.cloneNode(false);
924          iconElement.className = options.iconBase + ' ' + options.icon;
925
926          elementTemplates.fragment.appendChild(iconElement);
927          elementTemplates.fragment.appendChild(whitespace);
928        }
929
930        if (options.subtext) {
931          subtextElement = elementTemplates.subtext.cloneNode(false);
932          subtextElement.textContent = options.subtext;
933          textElement.appendChild(subtextElement);
934        }
935
936        elementTemplates.fragment.appendChild(textElement);
937
938        return elementTemplates.fragment;
939      }
940    }
941
942    var Selectpicker = function(element, options) {
943      var that = this;
944
945      // bootstrap-select has been initialized - revert valHooks.select.set back to its original function
946      if (!valHooks.useDefault) {
947        $.valHooks.select.set = valHooks._set;
948        valHooks.useDefault = true;
949      }
950
951      this.$element = $(element);
952      this.$newElement = null;
953      this.$button = null;
954      this.$menu = null;
955      this.options = options;
956      this.selectpicker = {
957        main: {},
958        search: {},
959        current: {}, // current changes if a search is in progress
960        view: {},
961        keydown: {
962          keyHistory: '',
963          resetKeyHistory: {
964            start: function() {
965              return setTimeout(function() {
966                that.selectpicker.keydown.keyHistory = '';
967              }, 800);
968            }
969          }
970        }
971      };
972      // 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
973      // data-attribute)
974      if (this.options.title === null) {
975        this.options.title = this.$element.attr('title');
976      }
977
978      // Format window padding
979      var winPad = this.options.windowPadding;
980      if (typeof winPad === 'number') {
981        this.options.windowPadding = [winPad, winPad, winPad, winPad];
982      }
983
984      // Expose public methods
985      this.val = Selectpicker.prototype.val;
986      this.render = Selectpicker.prototype.render;
987      this.refresh = Selectpicker.prototype.refresh;
988      this.setStyle = Selectpicker.prototype.setStyle;
989      this.selectAll = Selectpicker.prototype.selectAll;
990      this.deselectAll = Selectpicker.prototype.deselectAll;
991      this.destroy = Selectpicker.prototype.destroy;
992      this.remove = Selectpicker.prototype.remove;
993      this.show = Selectpicker.prototype.show;
994      this.hide = Selectpicker.prototype.hide;
995
996      this.init();
997    };
998
999    Selectpicker.VERSION = '1.13.12';
1000
1001    // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.
1002    Selectpicker.DEFAULTS = {
1003      noneSelectedText: 'Nothing selected',
1004      noneResultsText: 'No results matched {0}',
1005      countSelectedText: function(numSelected, numTotal) {
1006        return (numSelected == 1) ? '{0} item selected' : '{0} items selected';
1007      },
1008      maxOptionsText: function(numAll, numGroup) {
1009        return [
1010          (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',
1011          (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'
1012        ];
1013      },
1014      selectAllText: 'Select All',
1015      deselectAllText: 'Deselect All',
1016      doneButton: false,
1017      doneButtonText: 'Close',
1018      multipleSeparator: ', ',
1019      styleBase: 'btn',
1020      style: classNames.BUTTONCLASS,
1021      size: 'auto',
1022      title: null,
1023      selectedTextFormat: 'values',
1024      width: false,
1025      container: false,
1026      hideDisabled: false,
1027      showSubtext: false,
1028      showIcon: true,
1029      showContent: true,
1030      dropupAuto: true,
1031      header: false,
1032      liveSearch: false,
1033      liveSearchPlaceholder: null,
1034      liveSearchNormalize: false,
1035      liveSearchStyle: 'contains',
1036      actionsBox: false,
1037      iconBase: classNames.ICONBASE,
1038      tickIcon: classNames.TICKICON,
1039      showTick: false,
1040      template: {
1041        caret: '<span class="caret"></span>'
1042      },
1043      maxOptions: false,
1044      mobile: false,
1045      selectOnTab: false,
1046      dropdownAlignRight: false,
1047      windowPadding: 0,
1048      virtualScroll: 600,
1049      display: false,
1050      sanitize: true,
1051      sanitizeFn: null,
1052      whiteList: DefaultWhitelist
1053    };
1054
1055    Selectpicker.prototype = {
1056
1057      constructor: Selectpicker,
1058
1059      init: function() {
1060        var that = this,
1061          id = this.$element.attr('id');
1062
1063        selectId++;
1064        this.selectId = 'bs-select-' + selectId;
1065
1066        this.$element[0].classList.add('bs-select-hidden');
1067
1068        this.multiple = this.$element.prop('multiple');
1069        this.autofocus = this.$element.prop('autofocus');
1070
1071        if (this.$element[0].classList.contains('show-tick')) {
1072          this.options.showTick = true;
1073        }
1074
1075        this.$newElement = this.createDropdown();
1076        this.$element
1077          .after(this.$newElement)
1078          .prependTo(this.$newElement);
1079
1080        this.$button = this.$newElement.children('button');
1081        this.$menu = this.$newElement.children(Selector.MENU);
1082        this.$menuInner = this.$menu.children('.inner');
1083        this.$searchbox = this.$menu.find('input');
1084
1085        this.$element[0].classList.remove('bs-select-hidden');
1086
1087        if (this.options.dropdownAlignRight === true) this.$menu[0].classList.add(classNames.MENURIGHT);
1088
1089        if (typeof id !== 'undefined') {
1090          this.$button.attr('data-id', id);
1091        }
1092
1093        this.checkDisabled();
1094        this.clickListener();
1095
1096        if (this.options.liveSearch) {
1097          this.liveSearchListener();
1098          this.focusedParent = this.$searchbox[0];
1099        } else {
1100          this.focusedParent = this.$menuInner[0];
1101        }
1102
1103        this.setStyle();
1104        this.render();
1105        this.setWidth();
1106        if (this.options.container) {
1107          this.selectPosition();
1108        } else {
1109          this.$element.on('hide' + EVENT_KEY, function() {
1110            if (that.isVirtual()) {
1111              // empty menu on close
1112              var menuInner = that.$menuInner[0],
1113                emptyMenu = menuInner.firstChild.cloneNode(false);
1114
1115              // replace the existing UL with an empty one - this is faster than $.empty() or innerHTML = ''
1116              menuInner.replaceChild(emptyMenu, menuInner.firstChild);
1117              menuInner.scrollTop = 0;
1118            }
1119          });
1120        }
1121        this.$menu.data('this', this);
1122        this.$newElement.data('this', this);
1123        if (this.options.mobile) this.mobile();
1124
1125        this.$newElement.on({
1126          'hide.bs.dropdown': function(e) {
1127            that.$element.trigger('hide' + EVENT_KEY, e);
1128          },
1129          'hidden.bs.dropdown': function(e) {
1130            that.$element.trigger('hidden' + EVENT_KEY, e);
1131          },
1132          'show.bs.dropdown': function(e) {
1133            that.$element.trigger('show' + EVENT_KEY, e);
1134          },
1135          'shown.bs.dropdown': function(e) {
1136            that.$element.trigger('shown' + EVENT_KEY, e);
1137          }
1138        });
1139
1140        if (that.$element[0].hasAttribute('required')) {
1141          this.$element.on('invalid' + EVENT_KEY, function() {
1142            that.$button[0].classList.add('bs-invalid');
1143
1144            that.$element
1145              .on('shown' + EVENT_KEY + '.invalid', function() {
1146                that.$element
1147                  .val(that.$element.val()) // set the value to hide the validation message in Chrome when menu is opened
1148                  .off('shown' + EVENT_KEY + '.invalid');
1149              })
1150              .on('rendered' + EVENT_KEY, function() {
1151                // if select is no longer invalid, remove the bs-invalid class
1152                if (this.validity.valid) that.$button[0].classList.remove('bs-invalid');
1153                that.$element.off('rendered' + EVENT_KEY);
1154              });
1155
1156            that.$button.on('blur' + EVENT_KEY, function() {
1157              that.$element.trigger('focus').trigger('blur');
1158              that.$button.off('blur' + EVENT_KEY);
1159            });
1160          });
1161        }
1162
1163        setTimeout(function() {
1164          that.createLi();
1165          that.$element.trigger('loaded' + EVENT_KEY);
1166        });
1167      },
1168
1169      createDropdown: function() {
1170        // Options
1171        // If we are multiple or showTick option is set, then add the show-tick class
1172        var showTick = (this.multiple || this.options.showTick) ? ' show-tick' : '',
1173          multiselectable = this.multiple ? ' aria-multiselectable="true"' : '',
1174          inputGroup = '',
1175          autofocus = this.autofocus ? ' autofocus' : '';
1176
1177        if (version.major < 4 && this.$element.parent().hasClass('input-group')) {
1178          inputGroup = ' input-group-btn';
1179        }
1180
1181        // Elements
1182        var drop,
1183          header = '',
1184          searchbox = '',
1185          actionsbox = '',
1186          donebutton = '';
1187
1188        if (this.options.header) {
1189          header =
1190            '<div class="' + classNames.POPOVERHEADER + '">' +
1191            '<button type="button" class="close" aria-hidden="true">&times;</button>' +
1192            this.options.header +
1193            '</div>';
1194        }
1195
1196        if (this.options.liveSearch) {
1197          searchbox =
1198            '<div class="bs-searchbox">' +
1199            '<input type="search" class="form-control" autocomplete="off"' +
1200            (
1201              this.options.liveSearchPlaceholder === null ? '' :
1202              ' placeholder="' + htmlEscape(this.options.liveSearchPlaceholder) + '"'
1203            ) +
1204            ' role="combobox" aria-label="Search" aria-controls="' + this.selectId + '" aria-autocomplete="list">' +
1205            '</div>';
1206        }
1207
1208        if (this.multiple && this.options.actionsBox) {
1209          actionsbox =
1210            '<div class="bs-actionsbox">' +
1211            '<div class="btn-group btn-group-sm btn-block">' +
1212            '<button type="button" class="actions-btn bs-select-all btn ' + classNames.BUTTONCLASS + '">' +
1213            this.options.selectAllText +
1214            '</button>' +
1215            '<button type="button" class="actions-btn bs-deselect-all btn ' + classNames.BUTTONCLASS + '">' +
1216            this.options.deselectAllText +
1217            '</button>' +
1218            '</div>' +
1219            '</div>';
1220        }
1221
1222        if (this.multiple && this.options.doneButton) {
1223          donebutton =
1224            '<div class="bs-donebutton">' +
1225            '<div class="btn-group btn-block">' +
1226            '<button type="button" class="btn btn-sm ' + classNames.BUTTONCLASS + '">' +
1227            this.options.doneButtonText +
1228            '</button>' +
1229            '</div>' +
1230            '</div>';
1231        }
1232
1233        drop =
1234          '<div class="dropdown bootstrap-select' + showTick + inputGroup + '">' +
1235          '<button type="button" class="' + this.options.styleBase + ' dropdown-toggle" ' + (this.options.display === 'static' ? 'data-display="static"' : '') + 'data-toggle="dropdown"' + autofocus + ' role="combobox" aria-owns="' + this.selectId + '" aria-haspopup="listbox" aria-expanded="false">' +
1236          '<div class="filter-option">' +
1237          '<div class="filter-option-inner">' +
1238          '<div class="filter-option-inner-inner"></div>' +
1239          '</div> ' +
1240          '</div>' +
1241          (
1242            version.major === '4' ? '' :
1243            '<span class="bs-caret">' +
1244            this.options.template.caret +
1245            '</span>'
1246          ) +
1247          '</button>' +
1248          '<div class="' + classNames.MENU + ' ' + (version.major === '4' ? '' : classNames.SHOW) + '">' +
1249          header +
1250          searchbox +
1251          actionsbox +
1252          '<div class="inner ' + classNames.SHOW + '" role="listbox" id="' + this.selectId + '" tabindex="-1" ' + multiselectable + '>' +
1253          '<ul class="' + classNames.MENU + ' inner ' + (version.major === '4' ? classNames.SHOW : '') + '" role="presentation">' +
1254          '</ul>' +
1255          '</div>' +
1256          donebutton +
1257          '</div>' +
1258          '</div>';
1259
1260        return $(drop);
1261      },
1262
1263      setPositionData: function() {
1264        this.selectpicker.view.canHighlight = [];
1265        this.selectpicker.view.size = 0;
1266
1267        for (var i = 0; i < this.selectpicker.current.data.length; i++) {
1268          var li = this.selectpicker.current.data[i],
1269            canHighlight = true;
1270
1271          if (li.type === 'divider') {
1272            canHighlight = false;
1273            li.height = this.sizeInfo.dividerHeight;
1274          } else if (li.type === 'optgroup-label') {
1275            canHighlight = false;
1276            li.height = this.sizeInfo.dropdownHeaderHeight;
1277          } else {
1278            li.height = this.sizeInfo.liHeight;
1279          }
1280
1281          if (li.disabled) canHighlight = false;
1282
1283          this.selectpicker.view.canHighlight.push(canHighlight);
1284
1285          if (canHighlight) {
1286            this.selectpicker.view.size++;
1287            li.posinset = this.selectpicker.view.size;
1288          }
1289
1290          li.position = (i === 0 ? 0 : this.selectpicker.current.data[i - 1].position) + li.height;
1291        }
1292      },
1293
1294      isVirtual: function() {
1295        return (this.options.virtualScroll !== false) && (this.selectpicker.main.elements.length >= this.options.virtualScroll) || this.options.virtualScroll === true;
1296      },
1297
1298      createView: function(isSearching, setSize, refresh) {
1299        var that = this,
1300          scrollTop = 0,
1301          active = [],
1302          selected,
1303          prevActive;
1304
1305        this.selectpicker.current = isSearching ? this.selectpicker.search : this.selectpicker.main;
1306
1307        this.setPositionData();
1308
1309        if (setSize) {
1310          if (refresh) {
1311            scrollTop = this.$menuInner[0].scrollTop;
1312          } else if (!that.multiple) {
1313            var element = that.$element[0],
1314              selectedIndex = (element.options[element.selectedIndex] || {}).liIndex;
1315
1316            if (typeof selectedIndex === 'number' && that.options.size !== false) {
1317              var selectedData = that.selectpicker.main.data[selectedIndex],
1318                position = selectedData && selectedData.position;
1319
1320              if (position) {
1321                scrollTop = position - ((that.sizeInfo.menuInnerHeight + that.sizeInfo.liHeight) / 2);
1322              }
1323            }
1324          }
1325        }
1326
1327        scroll(scrollTop, true);
1328
1329        this.$menuInner.off('scroll.createView').on('scroll.createView', function(e, updateValue) {
1330          if (!that.noScroll) scroll(this.scrollTop, updateValue);
1331          that.noScroll = false;
1332        });
1333
1334        function scroll(scrollTop, init) {
1335          var size = that.selectpicker.current.elements.length,
1336            chunks = [],
1337            chunkSize,
1338            chunkCount,
1339            firstChunk,
1340            lastChunk,
1341            currentChunk,
1342            prevPositions,
1343            positionIsDifferent,
1344            previousElements,
1345            menuIsDifferent = true,
1346            isVirtual = that.isVirtual();
1347
1348          that.selectpicker.view.scrollTop = scrollTop;
1349
1350          chunkSize = Math.ceil(that.sizeInfo.menuInnerHeight / that.sizeInfo.liHeight * 1.5); // number of options in a chunk
1351          chunkCount = Math.round(size / chunkSize) || 1; // number of chunks
1352
1353          for (var i = 0; i < chunkCount; i++) {
1354            var endOfChunk = (i + 1) * chunkSize;
1355
1356            if (i === chunkCount - 1) {
1357              endOfChunk = size;
1358            }
1359
1360            chunks[i] = [
1361              (i) * chunkSize + (!i ? 0 : 1),
1362              endOfChunk
1363            ];
1364
1365            if (!size) break;
1366
1367            if (currentChunk === undefined && scrollTop - 1 <= that.selectpicker.current.data[endOfChunk - 1].position - that.sizeInfo.menuInnerHeight) {
1368              currentChunk = i;
1369            }
1370          }
1371
1372          if (currentChunk === undefined) currentChunk = 0;
1373
1374          prevPositions = [that.selectpicker.view.position0, that.selectpicker.view.position1];
1375
1376          // always display previous, current, and next chunks
1377          firstChunk = Math.max(0, currentChunk - 1);
1378          lastChunk = Math.min(chunkCount - 1, currentChunk + 1);
1379
1380          that.selectpicker.view.position0 = isVirtual === false ? 0 : (Math.max(0, chunks[firstChunk][0]) || 0);
1381          that.selectpicker.view.position1 = isVirtual === false ? size : (Math.min(size, chunks[lastChunk][1]) || 0);
1382
1383          positionIsDifferent = prevPositions[0] !== that.selectpicker.view.position0 || prevPositions[1] !== that.selectpicker.view.position1;
1384
1385          if (that.activeIndex !== undefined) {
1386            prevActive = that.selectpicker.main.elements[that.prevActiveIndex];
1387            active = that.selectpicker.main.elements[that.activeIndex];
1388            selected = that.selectpicker.main.elements[that.selectedIndex];
1389
1390            if (init) {
1391              if (that.activeIndex !== that.selectedIndex) {
1392                that.defocusItem(active);
1393              }
1394              that.activeIndex = undefined;
1395            }
1396
1397            if (that.activeIndex && that.activeIndex !== that.selectedIndex) {
1398              that.defocusItem(selected);
1399            }
1400          }
1401
1402          if (that.prevActiveIndex !== undefined && that.prevActiveIndex !== that.activeIndex && that.prevActiveIndex !== that.selectedIndex) {
1403            that.defocusItem(prevActive);
1404          }
1405
1406          if (init || positionIsDifferent) {
1407            previousElements = that.selectpicker.view.visibleElements ? that.selectpicker.view.visibleElements.slice() : [];
1408
1409            if (isVirtual === false) {
1410              that.selectpicker.view.visibleElements = that.selectpicker.current.elements;
1411            } else {
1412              that.selectpicker.view.visibleElements = that.selectpicker.current.elements.slice(that.selectpicker.view.position0, that.selectpicker.view.position1);
1413            }
1414
1415            that.setOptionStatus();
1416
1417            // if searching, check to make sure the list has actually been updated before updating DOM
1418            // this prevents unnecessary repaints
1419            if (isSearching || (isVirtual === false && init)) menuIsDifferent = !isEqual(previousElements, that.selectpicker.view.visibleElements);
1420
1421            // if virtual scroll is disabled and not searching,
1422            // menu should never need to be updated more than once
1423            if ((init || isVirtual === true) && menuIsDifferent) {
1424              var menuInner = that.$menuInner[0],
1425                menuFragment = document.createDocumentFragment(),
1426                emptyMenu = menuInner.firstChild.cloneNode(false),
1427                marginTop,
1428                marginBottom,
1429                elements = that.selectpicker.view.visibleElements,
1430                toSanitize = [];
1431
1432              // replace the existing UL with an empty one - this is faster than $.empty()
1433              menuInner.replaceChild(emptyMenu, menuInner.firstChild);
1434
1435              for (var i = 0, visibleElementsLen = elements.length; i < visibleElementsLen; i++) {
1436                var element = elements[i],
1437                  elText,
1438                  elementData;
1439
1440                if (that.options.sanitize) {
1441                  elText = element.lastChild;
1442
1443                  if (elText) {
1444                    elementData = that.selectpicker.current.data[i + that.selectpicker.view.position0];
1445
1446                    if (elementData && elementData.content && !elementData.sanitized) {
1447                      toSanitize.push(elText);
1448                      elementData.sanitized = true;
1449                    }
1450                  }
1451                }
1452
1453                menuFragment.appendChild(element);
1454              }
1455
1456              if (that.options.sanitize && toSanitize.length) {
1457                sanitizeHtml(toSanitize, that.options.whiteList, that.options.sanitizeFn);
1458              }
1459
1460              if (isVirtual === true) {
1461                marginTop = (that.selectpicker.view.position0 === 0 ? 0 : that.selectpicker.current.data[that.selectpicker.view.position0 - 1].position);
1462                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);
1463
1464                menuInner.firstChild.style.marginTop = marginTop + 'px';
1465                menuInner.firstChild.style.marginBottom = marginBottom + 'px';
1466              } else {
1467                menuInner.firstChild.style.marginTop = 0;
1468                menuInner.firstChild.style.marginBottom = 0;
1469              }
1470
1471              menuInner.firstChild.appendChild(menuFragment);
1472
1473              // if an option is encountered that is wider than the current menu width, update the menu width accordingly
1474              // switch to ResizeObserver with increased browser support
1475              if (isVirtual === true && that.sizeInfo.hasScrollBar) {
1476                var menuInnerInnerWidth = menuInner.firstChild.offsetWidth;
1477
1478                if (init && menuInnerInnerWidth < that.sizeInfo.menuInnerInnerWidth && that.sizeInfo.totalMenuWidth > that.sizeInfo.selectWidth) {
1479                  menuInner.firstChild.style.minWidth = that.sizeInfo.menuInnerInnerWidth + 'px';
1480                } else if (menuInnerInnerWidth > that.sizeInfo.menuInnerInnerWidth) {
1481                  // set to 0 to get actual width of menu
1482                  that.$menu[0].style.minWidth = 0;
1483
1484                  var actualMenuWidth = menuInner.firstChild.offsetWidth;
1485
1486                  if (actualMenuWidth > that.sizeInfo.menuInnerInnerWidth) {
1487                    that.sizeInfo.menuInnerInnerWidth = actualMenuWidth;
1488                    menuInner.firstChild.style.minWidth = that.sizeInfo.menuInnerInnerWidth + 'px';
1489                  }
1490
1491                  // reset to default CSS styling
1492                  that.$menu[0].style.minWidth = '';
1493                }
1494              }
1495            }
1496          }
1497
1498          that.prevActiveIndex = that.activeIndex;
1499
1500          if (!that.options.liveSearch) {
1501            that.$menuInner.trigger('focus');
1502          } else if (isSearching && init) {
1503            var index = 0,
1504              newActive;
1505
1506            if (!that.selectpicker.view.canHighlight[index]) {
1507              index = 1 + that.selectpicker.view.canHighlight.slice(1).indexOf(true);
1508            }
1509
1510            newActive = that.selectpicker.view.visibleElements[index];
1511
1512            that.defocusItem(that.selectpicker.view.currentActive);
1513
1514            that.activeIndex = (that.selectpicker.current.data[index] || {}).index;
1515
1516            that.focusItem(newActive);
1517          }
1518        }
1519
1520        $(window)
1521          .off('resize' + EVENT_KEY + '.' + this.selectId + '.createView')
1522          .on('resize' + EVENT_KEY + '.' + this.selectId + '.createView', function() {
1523            var isActive = that.$newElement.hasClass(classNames.SHOW);
1524
1525            if (isActive) scroll(that.$menuInner[0].scrollTop);
1526          });
1527      },
1528
1529      focusItem: function(li, liData, noStyle) {
1530        if (li) {
1531          liData = liData || this.selectpicker.main.data[this.activeIndex];
1532          var a = li.firstChild;
1533
1534          if (a) {
1535            a.setAttribute('aria-setsize', this.selectpicker.view.size);
1536            a.setAttribute('aria-posinset', liData.posinset);
1537
1538            if (noStyle !== true) {
1539              this.focusedParent.setAttribute('aria-activedescendant', a.id);
1540              li.classList.add('active');
1541              a.classList.add('active');
1542            }
1543          }
1544        }
1545      },
1546
1547      defocusItem: function(li) {
1548        if (li) {
1549          li.classList.remove('active');
1550          if (li.firstChild) li.firstChild.classList.remove('active');
1551        }
1552      },
1553
1554      setPlaceholder: function() {
1555        var updateIndex = false;
1556
1557        if (this.options.title && !this.multiple) {
1558          if (!this.selectpicker.view.titleOption) this.selectpicker.view.titleOption = document.createElement('option');
1559
1560          // this option doesn't create a new <li> element, but does add a new option at the start,
1561          // so startIndex should increase to prevent having to check every option for the bs-title-option class
1562          updateIndex = true;
1563
1564          var element = this.$element[0],
1565            isSelected = false,
1566            titleNotAppended = !this.selectpicker.view.titleOption.parentNode;
1567
1568          if (titleNotAppended) {
1569            // Use native JS to prepend option (faster)
1570            this.selectpicker.view.titleOption.className = 'bs-title-option';
1571            this.selectpicker.view.titleOption.value = '';
1572
1573            // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.
1574            // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,
1575            // if so, the select will have the data-selected attribute
1576            var $opt = $(element.options[element.selectedIndex]);
1577            isSelected = $opt.attr('selected') === undefined && this.$element.data('selected') === undefined;
1578          }
1579
1580          if (titleNotAppended || this.selectpicker.view.titleOption.index !== 0) {
1581            element.insertBefore(this.selectpicker.view.titleOption, element.firstChild);
1582          }
1583
1584          // Set selected *after* appending to select,
1585          // otherwise the option doesn't get selected in IE
1586          // set using selectedIndex, as setting the selected attr to true here doesn't work in IE11
1587          if (isSelected) element.selectedIndex = 0;
1588        }
1589
1590        return updateIndex;
1591      },
1592
1593      createLi: function() {
1594        var that = this,
1595          iconBase = this.options.iconBase,
1596          optionSelector = ':not([hidden]):not([data-hidden="true"])',
1597          mainElements = [],
1598          mainData = [],
1599          widestOptionLength = 0,
1600          optID = 0,
1601          startIndex = this.setPlaceholder() ? 1 : 0; // append the titleOption if necessary and skip the first option in the loop
1602
1603        if (this.options.hideDisabled) optionSelector += ':not(:disabled)';
1604
1605        if ((that.options.showTick || that.multiple) && !elementTemplates.checkMark.parentNode) {
1606          elementTemplates.checkMark.className = iconBase + ' ' + that.options.tickIcon + ' check-mark';
1607          elementTemplates.checkMark.innerHTML = "done";
1608          elementTemplates.a.appendChild(elementTemplates.checkMark);
1609        }
1610
1611        var selectOptions = this.$element[0].querySelectorAll('select > *' + optionSelector);
1612
1613        function addDivider(config) {
1614          var previousData = mainData[mainData.length - 1];
1615
1616          // ensure optgroup doesn't create back-to-back dividers
1617          if (
1618            previousData &&
1619            previousData.type === 'divider' &&
1620            (previousData.optID || config.optID)
1621          ) {
1622            return;
1623          }
1624
1625          config = config || {};
1626          config.type = 'divider';
1627
1628          mainElements.push(
1629            generateOption.li(
1630              false,
1631              classNames.DIVIDER,
1632              (config.optID ? config.optID + 'div' : undefined)
1633            )
1634          );
1635
1636          mainData.push(config);
1637        }
1638
1639        function addOption(option, config) {
1640          config = config || {};
1641
1642          config.divider = option.getAttribute('data-divider') === 'true';
1643
1644          if (config.divider) {
1645            addDivider({
1646              optID: config.optID
1647            });
1648          } else {
1649            var liIndex = mainData.length,
1650              cssText = option.style.cssText,
1651              inlineStyle = cssText ? htmlEscape(cssText) : '',
1652              optionClass = (option.className || '') + (config.optgroupClass || '');
1653
1654            if (config.optID) optionClass = 'opt ' + optionClass;
1655
1656            config.text = option.textContent;
1657
1658            config.content = option.getAttribute('data-content');
1659            config.tokens = option.getAttribute('data-tokens');
1660            config.subtext = option.getAttribute('data-subtext');
1661            config.icon = option.getAttribute('data-icon');
1662            config.iconBase = iconBase;
1663
1664            var textElement = generateOption.text(config);
1665            var liElement = generateOption.li(
1666              generateOption.a(
1667                textElement,
1668                optionClass,
1669                inlineStyle
1670              ),
1671              '',
1672              config.optID
1673            );
1674
1675            if (liElement.firstChild) {
1676              liElement.firstChild.id = that.selectId + '-' + liIndex;
1677            }
1678
1679            mainElements.push(liElement);
1680
1681            option.liIndex = liIndex;
1682
1683            config.display = config.content || config.text;
1684            config.type = 'option';
1685            config.index = liIndex;
1686            config.option = option;
1687            config.disabled = config.disabled || option.disabled;
1688
1689            mainData.push(config);
1690
1691            var combinedLength = 0;
1692
1693            // count the number of characters in the option - not perfect, but should work in most cases
1694            if (config.display) combinedLength += config.display.length;
1695            if (config.subtext) combinedLength += config.subtext.length;
1696            // if there is an icon, ensure this option's width is checked
vendor: 61,274 bytes, lines 1697-3300
1697            if (config.icon) combinedLength += 1;
1698
1699            if (combinedLength > widestOptionLength) {
1700              widestOptionLength = combinedLength;
1701
1702              // guess which option is the widest
1703              // use this when calculating menu width
1704              // not perfect, but it's fast, and the width will be updating accordingly when scrolling
1705              that.selectpicker.view.widestOption = mainElements[mainElements.length - 1];
1706            }
1707          }
1708        }
1709
1710        function addOptgroup(index, selectOptions) {
1711          var optgroup = selectOptions[index],
1712            previous = selectOptions[index - 1],
1713            next = selectOptions[index + 1],
1714            options = optgroup.querySelectorAll('option' + optionSelector);
1715
1716          if (!options.length) return;
1717
1718          var config = {
1719              label: htmlEscape(optgroup.label),
1720              subtext: optgroup.getAttribute('data-subtext'),
1721              icon: optgroup.getAttribute('data-icon'),
1722              iconBase: iconBase
1723            },
1724            optgroupClass = ' ' + (optgroup.className || ''),
1725            headerIndex,
1726            lastIndex;
1727
1728          optID++;
1729
1730          if (previous) {
1731            addDivider({
1732              optID: optID
1733            });
1734          }
1735
1736          var labelElement = generateOption.label(config);
1737
1738          mainElements.push(
1739            generateOption.li(labelElement, 'dropdown-header' + optgroupClass, optID)
1740          );
1741
1742          mainData.push({
1743            display: config.label,
1744            subtext: config.subtext,
1745            type: 'optgroup-label',
1746            optID: optID
1747          });
1748
1749          for (var j = 0, len = options.length; j < len; j++) {
1750            var option = options[j];
1751
1752            if (j === 0) {
1753              headerIndex = mainData.length - 1;
1754              lastIndex = headerIndex + len;
1755            }
1756
1757            addOption(option, {
1758              headerIndex: headerIndex,
1759              lastIndex: lastIndex,
1760              optID: optID,
1761              optgroupClass: optgroupClass,
1762              disabled: optgroup.disabled
1763            });
1764          }
1765
1766          if (next) {
1767            addDivider({
1768              optID: optID
1769            });
1770          }
1771        }
1772
1773        for (var len = selectOptions.length; startIndex < len; startIndex++) {
1774          var item = selectOptions[startIndex];
1775
1776          if (item.tagName !== 'OPTGROUP') {
1777            addOption(item, {});
1778          } else {
1779            addOptgroup(startIndex, selectOptions);
1780          }
1781        }
1782
1783        this.selectpicker.main.elements = mainElements;
1784        this.selectpicker.main.data = mainData;
1785
1786        this.selectpicker.current = this.selectpicker.main;
1787      },
1788
1789      findLis: function() {
1790        return this.$menuInner.find('.inner > li');
1791      },
1792
1793      render: function() {
1794        // ensure titleOption is appended and selected (if necessary) before getting selectedOptions
1795        this.setPlaceholder();
1796
1797        var that = this,
1798          element = this.$element[0],
1799          selectedOptions = getSelectedOptions(element, this.options.hideDisabled),
1800          selectedCount = selectedOptions.length,
1801          button = this.$button[0],
1802          buttonInner = button.querySelector('.filter-option-inner-inner'),
1803          multipleSeparator = document.createTextNode(this.options.multipleSeparator),
1804          titleFragment = elementTemplates.fragment.cloneNode(false),
1805          showCount,
1806          countMax,
1807          hasContent = false;
1808
1809        button.classList.toggle('bs-placeholder', that.multiple ? !selectedCount : !getSelectValues(element, selectedOptions));
1810
1811        this.tabIndex();
1812
1813        if (this.options.selectedTextFormat === 'static') {
1814          titleFragment = generateOption.text({
1815            text: this.options.title
1816          }, true);
1817        } else {
1818          showCount = this.multiple && this.options.selectedTextFormat.indexOf('count') !== -1 && selectedCount > 1;
1819
1820          // determine if the number of selected options will be shown (showCount === true)
1821          if (showCount) {
1822            countMax = this.options.selectedTextFormat.split('>');
1823            showCount = (countMax.length > 1 && selectedCount > countMax[1]) || (countMax.length === 1 && selectedCount >= 2);
1824          }
1825
1826          // only loop through all selected options if the count won't be shown
1827          if (showCount === false) {
1828            for (var selectedIndex = 0; selectedIndex < selectedCount; selectedIndex++) {
1829              if (selectedIndex < 50) {
1830                var option = selectedOptions[selectedIndex],
1831                  titleOptions = {},
1832                  thisData = {
1833                    content: option.getAttribute('data-content'),
1834                    subtext: option.getAttribute('data-subtext'),
1835                    icon: option.getAttribute('data-icon')
1836                  };
1837
1838                if (this.multiple && selectedIndex > 0) {
1839                  titleFragment.appendChild(multipleSeparator.cloneNode(false));
1840                }
1841
1842                if (option.title) {
1843                  titleOptions.text = option.title;
1844                } else if (thisData.content && that.options.showContent) {
1845                  titleOptions.content = thisData.content.toString();
1846                  hasContent = true;
1847                } else {
1848                  if (that.options.showIcon) {
1849                    titleOptions.icon = thisData.icon;
1850                    titleOptions.iconBase = this.options.iconBase;
1851                  }
1852                  if (that.options.showSubtext && !that.multiple && thisData.subtext) titleOptions.subtext = ' ' + thisData.subtext;
1853                  titleOptions.text = option.textContent.trim();
1854                }
1855
1856                titleFragment.appendChild(generateOption.text(titleOptions, true));
1857              } else {
1858                break;
1859              }
1860            }
1861
1862            // add ellipsis
1863            if (selectedCount > 49) {
1864              titleFragment.appendChild(document.createTextNode('...'));
1865            }
1866          } else {
1867            var optionSelector = ':not([hidden]):not([data-hidden="true"]):not([data-divider="true"])';
1868            if (this.options.hideDisabled) optionSelector += ':not(:disabled)';
1869
1870            // If this is a multiselect, and selectedTextFormat is count, then show 1 of 2 selected, etc.
1871            var totalCount = this.$element[0].querySelectorAll('select > option' + optionSelector + ', optgroup' + optionSelector + ' option' + optionSelector).length,
1872              tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedCount, totalCount) : this.options.countSelectedText;
1873
1874            titleFragment = generateOption.text({
1875              text: tr8nText.replace('{0}', selectedCount.toString()).replace('{1}', totalCount.toString())
1876            }, true);
1877          }
1878        }
1879
1880        if (this.options.title == undefined) {
1881          // use .attr to ensure undefined is returned if title attribute is not set
1882          this.options.title = this.$element.attr('title');
1883        }
1884
1885        // If the select doesn't have a title, then use the default, or if nothing is set at all, use noneSelectedText
1886        if (!titleFragment.childNodes.length) {
1887          titleFragment = generateOption.text({
1888            text: typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText
1889          }, true);
1890        }
1891
1892        // strip all HTML tags and trim the result, then unescape any escaped tags
1893        button.title = titleFragment.textContent.replace(/<[^>]*>?/g, '').trim();
1894
1895        if (this.options.sanitize && hasContent) {
1896          sanitizeHtml([titleFragment], that.options.whiteList, that.options.sanitizeFn);
1897        }
1898
1899        buttonInner.innerHTML = '';
1900        buttonInner.appendChild(titleFragment);
1901
1902        if (version.major < 4 && this.$newElement[0].classList.contains('bs3-has-addon')) {
1903          var filterExpand = button.querySelector('.filter-expand'),
1904            clone = buttonInner.cloneNode(true);
1905
1906          clone.className = 'filter-expand';
1907
1908          if (filterExpand) {
1909            button.replaceChild(clone, filterExpand);
1910          } else {
1911            button.appendChild(clone);
1912          }
1913        }
1914
1915        this.$element.trigger('rendered' + EVENT_KEY);
1916      },
1917
1918      /**
1919       * @param [style]
1920       * @param [status]
1921       */
1922      setStyle: function(newStyle, status) {
1923        var button = this.$button[0],
1924          newElement = this.$newElement[0],
1925          style = this.options.style.trim(),
1926          buttonClass;
1927
1928        if (this.$element.attr('class')) {
1929          this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi, ''));
1930        }
1931
1932        if (version.major < 4) {
1933          newElement.classList.add('bs3');
1934
1935          if (newElement.parentNode.classList.contains('input-group') &&
1936            (newElement.previousElementSibling || newElement.nextElementSibling) &&
1937            (newElement.previousElementSibling || newElement.nextElementSibling).classList.contains('input-group-addon')
1938          ) {
1939            newElement.classList.add('bs3-has-addon');
1940          }
1941        }
1942
1943        if (newStyle) {
1944          buttonClass = newStyle.trim();
1945        } else {
1946          buttonClass = style;
1947        }
1948
1949        if (status == 'add') {
1950          if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));
1951        } else if (status == 'remove') {
1952          if (buttonClass) button.classList.remove.apply(button.classList, buttonClass.split(' '));
1953        } else {
1954          if (style) button.classList.remove.apply(button.classList, style.split(' '));
1955          if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));
1956        }
1957      },
1958
1959      liHeight: function(refresh) {
1960        if (!refresh && (this.options.size === false || this.sizeInfo)) return;
1961
1962        if (!this.sizeInfo) this.sizeInfo = {};
1963
1964        var newElement = document.createElement('div'),
1965          menu = document.createElement('div'),
1966          menuInner = document.createElement('div'),
1967          menuInnerInner = document.createElement('ul'),
1968          divider = document.createElement('li'),
1969          dropdownHeader = document.createElement('li'),
1970          li = document.createElement('li'),
1971          a = document.createElement('a'),
1972          text = document.createElement('span'),
1973          header = this.options.header && this.$menu.find('.' + classNames.POPOVERHEADER).length > 0 ? this.$menu.find('.' + classNames.POPOVERHEADER)[0].cloneNode(true) : null,
1974          search = this.options.liveSearch ? document.createElement('div') : null,
1975          actions = this.options.actionsBox && this.multiple && this.$menu.find('.bs-actionsbox').length > 0 ? this.$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,
1976          doneButton = this.options.doneButton && this.multiple && this.$menu.find('.bs-donebutton').length > 0 ? this.$menu.find('.bs-donebutton')[0].cloneNode(true) : null,
1977          firstOption = this.$element.find('option')[0];
1978
1979        this.sizeInfo.selectWidth = this.$newElement[0].offsetWidth;
1980
1981        text.className = 'text';
1982        a.className = 'dropdown-item ' + (firstOption ? firstOption.className : '');
1983        newElement.className = this.$menu[0].parentNode.className + ' ' + classNames.SHOW;
1984        newElement.style.width = 0; // ensure button width doesn't affect natural width of menu when calculating
1985        if (this.options.width === 'auto') menu.style.minWidth = 0;
1986        menu.className = classNames.MENU + ' ' + classNames.SHOW;
1987        menuInner.className = 'inner ' + classNames.SHOW;
1988        menuInnerInner.className = classNames.MENU + ' inner ' + (version.major === '4' ? classNames.SHOW : '');
1989        divider.className = classNames.DIVIDER;
1990        dropdownHeader.className = 'dropdown-header';
1991
1992        text.appendChild(document.createTextNode('\u200b'));
1993        a.appendChild(text);
1994        li.appendChild(a);
1995        dropdownHeader.appendChild(text.cloneNode(true));
1996
1997        if (this.selectpicker.view.widestOption) {
1998          menuInnerInner.appendChild(this.selectpicker.view.widestOption.cloneNode(true));
1999        }
2000
2001        menuInnerInner.appendChild(li);
2002        menuInnerInner.appendChild(divider);
2003        menuInnerInner.appendChild(dropdownHeader);
2004        if (header) menu.appendChild(header);
2005        if (search) {
2006          var input = document.createElement('input');
2007          search.className = 'bs-searchbox';
2008          input.className = 'form-control';
2009          search.appendChild(input);
2010          menu.appendChild(search);
2011        }
2012        if (actions) menu.appendChild(actions);
2013        menuInner.appendChild(menuInnerInner);
2014        menu.appendChild(menuInner);
2015        if (doneButton) menu.appendChild(doneButton);
2016        newElement.appendChild(menu);
2017
2018        document.body.appendChild(newElement);
2019
2020        var liHeight = li.offsetHeight,
2021          dropdownHeaderHeight = dropdownHeader ? dropdownHeader.offsetHeight : 0,
2022          headerHeight = header ? header.offsetHeight : 0,
2023          searchHeight = search ? search.offsetHeight : 0,
2024          actionsHeight = actions ? actions.offsetHeight : 0,
2025          doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,
2026          dividerHeight = $(divider).outerHeight(true),
2027          // fall back to jQuery if getComputedStyle is not supported
2028          menuStyle = window.getComputedStyle ? window.getComputedStyle(menu) : false,
2029          menuWidth = menu.offsetWidth,
2030          $menu = menuStyle ? null : $(menu),
2031          menuPadding = {
2032            vert: toInteger(menuStyle ? menuStyle.paddingTop : $menu.css('paddingTop')) +
2033              toInteger(menuStyle ? menuStyle.paddingBottom : $menu.css('paddingBottom')) +
2034              toInteger(menuStyle ? menuStyle.borderTopWidth : $menu.css('borderTopWidth')) +
2035              toInteger(menuStyle ? menuStyle.borderBottomWidth : $menu.css('borderBottomWidth')),
2036            horiz: toInteger(menuStyle ? menuStyle.paddingLeft : $menu.css('paddingLeft')) +
2037              toInteger(menuStyle ? menuStyle.paddingRight : $menu.css('paddingRight')) +
2038              toInteger(menuStyle ? menuStyle.borderLeftWidth : $menu.css('borderLeftWidth')) +
2039              toInteger(menuStyle ? menuStyle.borderRightWidth : $menu.css('borderRightWidth'))
2040          },
2041          menuExtras = {
2042            vert: menuPadding.vert +
2043              toInteger(menuStyle ? menuStyle.marginTop : $menu.css('marginTop')) +
2044              toInteger(menuStyle ? menuStyle.marginBottom : $menu.css('marginBottom')) + 2,
2045            horiz: menuPadding.horiz +
2046              toInteger(menuStyle ? menuStyle.marginLeft : $menu.css('marginLeft')) +
2047              toInteger(menuStyle ? menuStyle.marginRight : $menu.css('marginRight')) + 2
2048          },
2049          scrollBarWidth;
2050
2051        menuInner.style.overflowY = 'scroll';
2052
2053        scrollBarWidth = menu.offsetWidth - menuWidth;
2054
2055        document.body.removeChild(newElement);
2056
2057        this.sizeInfo.liHeight = liHeight;
2058        this.sizeInfo.dropdownHeaderHeight = dropdownHeaderHeight;
2059        this.sizeInfo.headerHeight = headerHeight;
2060        this.sizeInfo.searchHeight = searchHeight;
2061        this.sizeInfo.actionsHeight = actionsHeight;
2062        this.sizeInfo.doneButtonHeight = doneButtonHeight;
2063        this.sizeInfo.dividerHeight = dividerHeight;
2064        this.sizeInfo.menuPadding = menuPadding;
2065        this.sizeInfo.menuExtras = menuExtras;
2066        this.sizeInfo.menuWidth = menuWidth;
2067        this.sizeInfo.menuInnerInnerWidth = menuWidth - menuPadding.horiz;
2068        this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth;
2069        this.sizeInfo.scrollBarWidth = scrollBarWidth;
2070        this.sizeInfo.selectHeight = this.$newElement[0].offsetHeight;
2071
2072        this.setPositionData();
2073      },
2074
2075      getSelectPosition: function() {
2076        var that = this,
2077          $window = $(window),
2078          pos = that.$newElement.offset(),
2079          $container = $(that.options.container),
2080          containerPos;
2081
2082        if (that.options.container && $container.length && !$container.is('body')) {
2083          containerPos = $container.offset();
2084          containerPos.top += parseInt($container.css('borderTopWidth'));
2085          containerPos.left += parseInt($container.css('borderLeftWidth'));
2086        } else {
2087          containerPos = {
2088            top: 0,
2089            left: 0
2090          };
2091        }
2092
2093        var winPad = that.options.windowPadding;
2094
2095        this.sizeInfo.selectOffsetTop = pos.top - containerPos.top - $window.scrollTop();
2096        this.sizeInfo.selectOffsetBot = $window.height() - this.sizeInfo.selectOffsetTop - this.sizeInfo.selectHeight - containerPos.top - winPad[2];
2097        this.sizeInfo.selectOffsetLeft = pos.left - containerPos.left - $window.scrollLeft();
2098        this.sizeInfo.selectOffsetRight = $window.width() - this.sizeInfo.selectOffsetLeft - this.sizeInfo.selectWidth - containerPos.left - winPad[1];
2099        this.sizeInfo.selectOffsetTop -= winPad[0];
2100        this.sizeInfo.selectOffsetLeft -= winPad[3];
2101      },
2102
2103      setMenuSize: function(isAuto) {
2104        this.getSelectPosition();
2105
2106        var selectWidth = this.sizeInfo.selectWidth,
2107          liHeight = this.sizeInfo.liHeight,
2108          headerHeight = this.sizeInfo.headerHeight,
2109          searchHeight = this.sizeInfo.searchHeight,
2110          actionsHeight = this.sizeInfo.actionsHeight,
2111          doneButtonHeight = this.sizeInfo.doneButtonHeight,
2112          divHeight = this.sizeInfo.dividerHeight,
2113          menuPadding = this.sizeInfo.menuPadding,
2114          menuInnerHeight,
2115          menuHeight,
2116          divLength = 0,
2117          minHeight,
2118          _minHeight,
2119          maxHeight,
2120          menuInnerMinHeight,
2121          estimate;
2122
2123        if (this.options.dropupAuto) {
2124          // Get the estimated height of the menu without scrollbars.
2125          // This is useful for smaller menus, where there might be plenty of room
2126          // below the button without setting dropup, but we can't know
2127          // the exact height of the menu until createView is called later
2128          estimate = liHeight * this.selectpicker.current.elements.length + menuPadding.vert;
2129          this.$newElement.toggleClass(classNames.DROPUP, this.sizeInfo.selectOffsetTop - this.sizeInfo.selectOffsetBot > this.sizeInfo.menuExtras.vert && estimate + this.sizeInfo.menuExtras.vert + 50 > this.sizeInfo.selectOffsetBot);
2130        }
2131
2132        if (this.options.size === 'auto') {
2133          _minHeight = this.selectpicker.current.elements.length > 3 ? this.sizeInfo.liHeight * 3 + this.sizeInfo.menuExtras.vert - 2 : 0;
2134          menuHeight = this.sizeInfo.selectOffsetBot - this.sizeInfo.menuExtras.vert;
2135          minHeight = _minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;
2136          menuInnerMinHeight = Math.max(_minHeight - menuPadding.vert, 0);
2137
2138          if (this.$newElement.hasClass(classNames.DROPUP)) {
2139            menuHeight = this.sizeInfo.selectOffsetTop - this.sizeInfo.menuExtras.vert;
2140          }
2141
2142          maxHeight = menuHeight;
2143          menuInnerHeight = menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert;
2144        } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {
2145          for (var i = 0; i < this.options.size; i++) {
2146            if (this.selectpicker.current.data[i].type === 'divider') divLength++;
2147          }
2148
2149          menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert;
2150          menuInnerHeight = menuHeight - menuPadding.vert;
2151          maxHeight = menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;
2152          minHeight = menuInnerMinHeight = '';
2153        }
2154
2155        this.$menu.css({
2156          'max-height': maxHeight + 'px',
2157          'overflow': 'hidden',
2158          'min-height': minHeight + 'px'
2159        });
2160
2161        this.$menuInner.css({
2162          'max-height': menuInnerHeight + 'px',
2163          'overflow-y': 'auto',
2164          'min-height': menuInnerMinHeight + 'px'
2165        });
2166
2167        // ensure menuInnerHeight is always a positive number to prevent issues calculating chunkSize in createView
2168        this.sizeInfo.menuInnerHeight = Math.max(menuInnerHeight, 1);
2169
2170        if (this.selectpicker.current.data.length && this.selectpicker.current.data[this.selectpicker.current.data.length - 1].position > this.sizeInfo.menuInnerHeight) {
2171          this.sizeInfo.hasScrollBar = true;
2172          this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth + this.sizeInfo.scrollBarWidth;
2173        }
2174
2175        if (this.options.dropdownAlignRight === 'auto') {
2176          this.$menu.toggleClass(classNames.MENURIGHT, this.sizeInfo.selectOffsetLeft > this.sizeInfo.selectOffsetRight && this.sizeInfo.selectOffsetRight < (this.sizeInfo.totalMenuWidth - selectWidth));
2177        }
2178
2179        if (this.dropdown && this.dropdown._popper) this.dropdown._popper.update();
2180      },
2181
2182      setSize: function(refresh) {
2183        this.liHeight(refresh);
2184
2185        if (this.options.header) this.$menu.css('padding-top', 0);
2186        if (this.options.size === false) return;
2187
2188        var that = this,
2189          $window = $(window);
2190
2191        this.setMenuSize();
2192
2193        if (this.options.liveSearch) {
2194          this.$searchbox
2195            .off('input.setMenuSize propertychange.setMenuSize')
2196            .on('input.setMenuSize propertychange.setMenuSize', function() {
2197              return that.setMenuSize();
2198            });
2199        }
2200
2201        if (this.options.size === 'auto') {
2202          $window
2203            .off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize')
2204            .on('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize', function() {
2205              return that.setMenuSize();
2206            });
2207        } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {
2208          $window.off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize');
2209        }
2210
2211        that.createView(false, true, refresh);
2212      },
2213
2214      setWidth: function() {
2215        var that = this;
2216
2217        if (this.options.width === 'auto') {
2218          requestAnimationFrame(function() {
2219            that.$menu.css('min-width', '0');
2220
2221            that.$element.on('loaded' + EVENT_KEY, function() {
2222              that.liHeight();
2223              that.setMenuSize();
2224
2225              // Get correct width if element is hidden
2226              var $selectClone = that.$newElement.clone().appendTo('body'),
2227                btnWidth = $selectClone.css('width', 'auto').children('button').outerWidth();
2228
2229              $selectClone.remove();
2230
2231              // Set width to whatever's larger, button title or longest option
2232              that.sizeInfo.selectWidth = Math.max(that.sizeInfo.totalMenuWidth, btnWidth);
2233              that.$newElement.css('width', that.sizeInfo.selectWidth + 'px');
2234            });
2235          });
2236        } else if (this.options.width === 'fit') {
2237          // Remove inline min-width so width can be changed from 'auto'
2238          this.$menu.css('min-width', '');
2239          this.$newElement.css('width', '').addClass('fit-width');
2240        } else if (this.options.width) {
2241          // Remove inline min-width so width can be changed from 'auto'
2242          this.$menu.css('min-width', '');
2243          this.$newElement.css('width', this.options.width);
2244        } else {
2245          // Remove inline min-width/width so width can be changed
2246          this.$menu.css('min-width', '');
2247          this.$newElement.css('width', '');
2248        }
2249        // Remove fit-width class if width is changed programmatically
2250        if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {
2251          this.$newElement[0].classList.remove('fit-width');
2252        }
2253      },
2254
2255      selectPosition: function() {
2256        this.$bsContainer = $('<div class="bs-container" />');
2257
2258        var that = this,
2259          $container = $(this.options.container),
2260          pos,
2261          containerPos,
2262          actualHeight,
2263          getPlacement = function($element) {
2264            var containerPosition = {},
2265              // fall back to dropdown's default display setting if display is not manually set
2266              display = that.options.display || (
2267                // Bootstrap 3 doesn't have $.fn.dropdown.Constructor.Default
2268                $.fn.dropdown.Constructor.Default ? $.fn.dropdown.Constructor.Default.display :
2269                false
2270              );
2271
2272            that.$bsContainer.addClass($element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass(classNames.DROPUP, $element.hasClass(classNames.DROPUP));
2273            pos = $element.offset();
2274
2275            if (!$container.is('body')) {
2276              containerPos = $container.offset();
2277              containerPos.top += parseInt($container.css('borderTopWidth')) - $container.scrollTop();
2278              containerPos.left += parseInt($container.css('borderLeftWidth')) - $container.scrollLeft();
2279            } else {
2280              containerPos = {
2281                top: 0,
2282                left: 0
2283              };
2284            }
2285
2286            actualHeight = $element.hasClass(classNames.DROPUP) ? 0 : $element[0].offsetHeight;
2287
2288            // Bootstrap 4+ uses Popper for menu positioning
2289            if (version.major < 4 || display === 'static') {
2290              containerPosition.top = pos.top - containerPos.top + actualHeight;
2291              containerPosition.left = pos.left - containerPos.left;
2292            }
2293
2294            containerPosition.width = $element[0].offsetWidth;
2295
2296            that.$bsContainer.css(containerPosition);
2297          };
2298
2299        this.$button.on('click.bs.dropdown.data-api', function() {
2300          if (that.isDisabled()) {
2301            return;
2302          }
2303
2304          getPlacement(that.$newElement);
2305
2306          that.$bsContainer
2307            .appendTo(that.options.container)
2308            .toggleClass(classNames.SHOW, !that.$button.hasClass(classNames.SHOW))
2309            .append(that.$menu);
2310        });
2311
2312        $(window)
2313          .off('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId)
2314          .on('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId, function() {
2315            var isActive = that.$newElement.hasClass(classNames.SHOW);
2316
2317            if (isActive) getPlacement(that.$newElement);
2318          });
2319
2320        this.$element.on('hide' + EVENT_KEY, function() {
2321          that.$menu.data('height', that.$menu.height());
2322          that.$bsContainer.detach();
2323        });
2324      },
2325
2326      setOptionStatus: function(selectedOnly) {
2327        var that = this;
2328
2329        that.noScroll = false;
2330
2331        if (that.selectpicker.view.visibleElements && that.selectpicker.view.visibleElements.length) {
2332          for (var i = 0; i < that.selectpicker.view.visibleElements.length; i++) {
2333            var liData = that.selectpicker.current.data[i + that.selectpicker.view.position0],
2334              option = liData.option;
2335
2336            if (option) {
2337              if (selectedOnly !== true) {
2338                that.setDisabled(
2339                  liData.index,
2340                  liData.disabled
2341                );
2342              }
2343
2344              that.setSelected(
2345                liData.index,
2346                option.selected
2347              );
2348            }
2349          }
2350        }
2351      },
2352
2353      /**
2354       * @param {number} index - the index of the option that is being changed
2355       * @param {boolean} selected - true if the option is being selected, false if being deselected
2356       */
2357      setSelected: function(index, selected) {
2358        var li = this.selectpicker.main.elements[index],
2359          liData = this.selectpicker.main.data[index],
2360          activeIndexIsSet = this.activeIndex !== undefined,
2361          thisIsActive = this.activeIndex === index,
2362          prevActive,
2363          a,
2364          // if current option is already active
2365          // OR
2366          // if the current option is being selected, it's NOT multiple, and
2367          // activeIndex is undefined:
2368          //  - when the menu is first being opened, OR
2369          //  - after a search has been performed, OR
2370          //  - 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)
2371          keepActive = thisIsActive || (selected && !this.multiple && !activeIndexIsSet);
2372
2373        liData.selected = selected;
2374
2375        a = li.firstChild;
2376
2377        if (selected) {
2378          this.selectedIndex = index;
2379        }
2380
2381        li.classList.toggle('selected', selected);
2382
2383        if (keepActive) {
2384          this.focusItem(li, liData);
2385          this.selectpicker.view.currentActive = li;
2386          this.activeIndex = index;
2387        } else {
2388          this.defocusItem(li);
2389        }
2390
2391        if (a) {
2392          a.classList.toggle('selected', selected);
2393
2394          if (selected) {
2395            a.setAttribute('aria-selected', true);
2396          } else {
2397            if (this.multiple) {
2398              a.setAttribute('aria-selected', false);
2399            } else {
2400              a.removeAttribute('aria-selected');
2401            }
2402          }
2403        }
2404
2405        if (!keepActive && !activeIndexIsSet && selected && this.prevActiveIndex !== undefined) {
2406          prevActive = this.selectpicker.main.elements[this.prevActiveIndex];
2407
2408          this.defocusItem(prevActive);
2409        }
2410      },
2411
2412      /**
2413       * @param {number} index - the index of the option that is being disabled
2414       * @param {boolean} disabled - true if the option is being disabled, false if being enabled
2415       */
2416      setDisabled: function(index, disabled) {
2417        var li = this.selectpicker.main.elements[index],
2418          a;
2419
2420        this.selectpicker.main.data[index].disabled = disabled;
2421
2422        a = li.firstChild;
2423
2424        li.classList.toggle(classNames.DISABLED, disabled);
2425
2426        if (a) {
2427          if (version.major === '4') a.classList.toggle(classNames.DISABLED, disabled);
2428
2429          if (disabled) {
2430            a.setAttribute('aria-disabled', disabled);
2431            a.setAttribute('tabindex', -1);
2432          } else {
2433            a.removeAttribute('aria-disabled');
2434            a.setAttribute('tabindex', 0);
2435          }
2436        }
2437      },
2438
2439      isDisabled: function() {
2440        return this.$element[0].disabled;
2441      },
2442
2443      checkDisabled: function() {
2444        if (this.isDisabled()) {
2445          this.$newElement[0].classList.add(classNames.DISABLED);
2446          this.$button.addClass(classNames.DISABLED).attr('tabindex', -1).attr('aria-disabled', true);
2447        } else {
2448          if (this.$button[0].classList.contains(classNames.DISABLED)) {
2449            this.$newElement[0].classList.remove(classNames.DISABLED);
2450            this.$button.removeClass(classNames.DISABLED).attr('aria-disabled', false);
2451          }
2452
2453          if (this.$button.attr('tabindex') == -1 && !this.$element.data('tabindex')) {
2454            this.$button.removeAttr('tabindex');
2455          }
2456        }
2457      },
2458
2459      tabIndex: function() {
2460        if (this.$element.data('tabindex') !== this.$element.attr('tabindex') &&
2461          (this.$element.attr('tabindex') !== -98 && this.$element.attr('tabindex') !== '-98')) {
2462          this.$element.data('tabindex', this.$element.attr('tabindex'));
2463          this.$button.attr('tabindex', this.$element.data('tabindex'));
2464        }
2465
2466        this.$element.attr('tabindex', -98);
2467      },
2468
2469      clickListener: function() {
2470        var that = this,
2471          $document = $(document);
2472
2473        $document.data('spaceSelect', false);
2474
2475        this.$button.on('keyup', function(e) {
2476          if (/(32)/.test(e.keyCode.toString(10)) && $document.data('spaceSelect')) {
2477            e.preventDefault();
2478            $document.data('spaceSelect', false);
2479          }
2480        });
2481
2482        this.$newElement.on('show.bs.dropdown', function() {
2483          if (version.major > 3 && !that.dropdown) {
2484            that.dropdown = that.$button.data('bs.dropdown');
2485            that.dropdown._menu = that.$menu[0];
2486          }
2487        });
2488
2489        this.$button.on('click.bs.dropdown.data-api', function() {
2490          if (!that.$newElement.hasClass(classNames.SHOW)) {
2491            that.setSize();
2492          }
2493        });
2494
2495        function setFocus() {
2496          if (that.options.liveSearch) {
2497            that.$searchbox.trigger('focus');
2498          } else {
2499            that.$menuInner.trigger('focus');
2500          }
2501        }
2502
2503        function checkPopperExists() {
2504          if (that.dropdown && that.dropdown._popper && that.dropdown._popper.state.isCreated) {
2505            setFocus();
2506          } else {
2507            requestAnimationFrame(checkPopperExists);
2508          }
2509        }
2510
2511        this.$element.on('shown' + EVENT_KEY, function() {
2512          if (that.$menuInner[0].scrollTop !== that.selectpicker.view.scrollTop) {
2513            that.$menuInner[0].scrollTop = that.selectpicker.view.scrollTop;
2514          }
2515
2516          if (version.major > 3) {
2517            requestAnimationFrame(checkPopperExists);
2518          } else {
2519            setFocus();
2520          }
2521        });
2522
2523        // ensure posinset and setsize are correct before selecting an option via a click
2524        this.$menuInner.on('mouseenter', 'li a', function(e) {
2525          var hoverLi = this.parentElement,
2526            position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,
2527            index = Array.prototype.indexOf.call(hoverLi.parentElement.children, hoverLi),
2528            hoverData = that.selectpicker.current.data[index + position0];
2529
2530          that.focusItem(hoverLi, hoverData, true);
2531        });
2532
2533        this.$menuInner.on('click', 'li a', function(e, retainActive) {
2534          var $this = $(this),
2535            element = that.$element[0],
2536            position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,
2537            clickedData = that.selectpicker.current.data[$this.parent().index() + position0],
2538            clickedIndex = clickedData.index,
2539            prevValue = getSelectValues(element),
2540            prevIndex = element.selectedIndex,
2541            prevOption = element.options[prevIndex],
2542            triggerChange = true;
2543
2544          // Don't close on multi choice menu
2545          if (that.multiple && that.options.maxOptions !== 1) {
2546            e.stopPropagation();
2547          }
2548
2549          e.preventDefault();
2550
2551          // Don't run if the select is disabled
2552          if (!that.isDisabled() && !$this.parent().hasClass(classNames.DISABLED)) {
2553            var option = clickedData.option,
2554              $option = $(option),
2555              state = option.selected,
2556              $optgroup = $option.parent('optgroup'),
2557              $optgroupOptions = $optgroup.find('option'),
2558              maxOptions = that.options.maxOptions,
2559              maxOptionsGrp = $optgroup.data('maxOptions') || false;
2560
2561            if (clickedIndex === that.activeIndex) retainActive = true;
2562
2563            if (!retainActive) {
2564              that.prevActiveIndex = that.activeIndex;
2565              that.activeIndex = undefined;
2566            }
2567
2568            if (!that.multiple) { // Deselect all others if not multi select box
2569              if (prevOption) prevOption.selected = false;
2570              option.selected = true;
2571              that.setSelected(clickedIndex, true);
2572            } else { // Toggle the one we have chosen if we are multi select.
2573              option.selected = !state;
2574
2575              that.setSelected(clickedIndex, !state);
2576              $this.trigger('blur');
2577
2578              if (maxOptions !== false || maxOptionsGrp !== false) {
2579                var maxReached = maxOptions < getSelectedOptions(element).length,
2580                  maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length;
2581
2582                if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {
2583                  if (maxOptions && maxOptions == 1) {
2584                    element.selectedIndex = -1;
2585                    option.selected = true;
2586                    that.setOptionStatus(true);
2587                  } else if (maxOptionsGrp && maxOptionsGrp == 1) {
2588                    for (var i = 0; i < $optgroupOptions.length; i++) {
2589                      var _option = $optgroupOptions[i];
2590                      _option.selected = false;
2591                      that.setSelected(_option.liIndex, false);
2592                    }
2593
2594                    option.selected = true;
2595                    that.setSelected(clickedIndex, true);
2596                  } else {
2597                    var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText,
2598                      maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText,
2599                      maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),
2600                      maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),
2601                      $notify = $('<div class="notify"></div>');
2602                    // If {var} is set in array, replace it
2603                    /** @deprecated */
2604                    if (maxOptionsArr[2]) {
2605                      maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);
2606                      maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);
2607                    }
2608
2609                    option.selected = false;
2610
2611                    that.$menu.append($notify);
2612
2613                    if (maxOptions && maxReached) {
2614                      $notify.append($('<div>' + maxTxt + '</div>'));
2615                      triggerChange = false;
2616                      that.$element.trigger('maxReached' + EVENT_KEY);
2617                    }
2618
2619                    if (maxOptionsGrp && maxReachedGrp) {
2620                      $notify.append($('<div>' + maxTxtGrp + '</div>'));
2621                      triggerChange = false;
2622                      that.$element.trigger('maxReachedGrp' + EVENT_KEY);
2623                    }
2624
2625                    setTimeout(function() {
2626                      that.setSelected(clickedIndex, false);
2627                    }, 10);
2628
2629                    $notify[0].classList.add('fadeOut');
2630
2631                    setTimeout(function() {
2632                      $notify.remove();
2633                    }, 1050);
2634                  }
2635                }
2636              }
2637            }
2638
2639            if (!that.multiple || (that.multiple && that.options.maxOptions === 1)) {
2640              that.$button.trigger('focus');
2641            } else if (that.options.liveSearch) {
2642              that.$searchbox.trigger('focus');
2643            }
2644
2645            // Trigger select 'change'
2646            if (triggerChange) {
2647              if (that.multiple || prevIndex !== element.selectedIndex) {
2648                // $option.prop('selected') is current option state (selected/unselected). prevValue is the value of the select prior to being changed.
2649                changedArguments = [option.index, $option.prop('selected'), prevValue];
2650                that.$element
2651                  .triggerNative('change');
2652              }
2653            }
2654          }
2655        });
2656
2657        this.$menu.on('click', 'li.' + classNames.DISABLED + ' a, .' + classNames.POPOVERHEADER + ', .' + classNames.POPOVERHEADER + ' :not(.close)', function(e) {
2658          if (e.currentTarget == this) {
2659            e.preventDefault();
2660            e.stopPropagation();
2661            if (that.options.liveSearch && !$(e.target).hasClass('close')) {
2662              that.$searchbox.trigger('focus');
2663            } else {
2664              that.$button.trigger('focus');
2665            }
2666          }
2667        });
2668
2669        this.$menuInner.on('click', '.divider, .dropdown-header', function(e) {
2670          e.preventDefault();
2671          e.stopPropagation();
2672          if (that.options.liveSearch) {
2673            that.$searchbox.trigger('focus');
2674          } else {
2675            that.$button.trigger('focus');
2676          }
2677        });
2678
2679        this.$menu.on('click', '.' + classNames.POPOVERHEADER + ' .close', function() {
2680          that.$button.trigger('click');
2681        });
2682
2683        this.$searchbox.on('click', function(e) {
2684          e.stopPropagation();
2685        });
2686
2687        this.$menu.on('click', '.actions-btn', function(e) {
2688          if (that.options.liveSearch) {
2689            that.$searchbox.trigger('focus');
2690          } else {
2691            that.$button.trigger('focus');
2692          }
2693
2694          e.preventDefault();
2695          e.stopPropagation();
2696
2697          if ($(this).hasClass('bs-select-all')) {
2698            that.selectAll();
2699          } else {
2700            that.deselectAll();
2701          }
2702        });
2703
2704        this.$element
2705          .on('change' + EVENT_KEY, function() {
2706            that.render();
2707            that.$element.trigger('changed' + EVENT_KEY, changedArguments);
2708            changedArguments = null;
2709          })
2710          .on('focus' + EVENT_KEY, function() {
2711            if (!that.options.mobile) that.$button.trigger('focus');
2712          });
2713      },
2714
2715      liveSearchListener: function() {
2716        var that = this,
2717          noResults = document.createElement('li');
2718
2719        this.$button.on('click.bs.dropdown.data-api', function() {
2720          if (!!that.$searchbox.val()) {
2721            that.$searchbox.val('');
2722          }
2723        });
2724
2725        this.$searchbox.on('click.bs.dropdown.data-api focus.bs.dropdown.data-api touchend.bs.dropdown.data-api', function(e) {
2726          e.stopPropagation();
2727        });
2728
2729        this.$searchbox.on('input propertychange', function() {
2730          var searchValue = that.$searchbox.val();
2731
2732          that.selectpicker.search.elements = [];
2733          that.selectpicker.search.data = [];
2734
2735          if (searchValue) {
2736            var i,
2737              searchMatch = [],
2738              q = searchValue.toUpperCase(),
2739              cache = {},
2740              cacheArr = [],
2741              searchStyle = that._searchStyle(),
2742              normalizeSearch = that.options.liveSearchNormalize;
2743
2744            if (normalizeSearch) q = normalizeToBase(q);
2745
2746            that._$lisSelected = that.$menuInner.find('.selected');
2747
2748            for (var i = 0; i < that.selectpicker.main.data.length; i++) {
2749              var li = that.selectpicker.main.data[i];
2750
2751              if (!cache[i]) {
2752                cache[i] = stringSearch(li, q, searchStyle, normalizeSearch);
2753              }
2754
2755              if (cache[i] && li.headerIndex !== undefined && cacheArr.indexOf(li.headerIndex) === -1) {
2756                if (li.headerIndex > 0) {
2757                  cache[li.headerIndex - 1] = true;
2758                  cacheArr.push(li.headerIndex - 1);
2759                }
2760
2761                cache[li.headerIndex] = true;
2762                cacheArr.push(li.headerIndex);
2763
2764                cache[li.lastIndex + 1] = true;
2765              }
2766
2767              if (cache[i] && li.type !== 'optgroup-label') cacheArr.push(i);
2768            }
2769
2770            for (var i = 0, cacheLen = cacheArr.length; i < cacheLen; i++) {
2771              var index = cacheArr[i],
2772                prevIndex = cacheArr[i - 1],
2773                li = that.selectpicker.main.data[index],
2774                liPrev = that.selectpicker.main.data[prevIndex];
2775
2776              if (li.type !== 'divider' || (li.type === 'divider' && liPrev && liPrev.type !== 'divider' && cacheLen - 1 !== i)) {
2777                that.selectpicker.search.data.push(li);
2778                searchMatch.push(that.selectpicker.main.elements[index]);
2779              }
2780            }
2781
2782            that.activeIndex = undefined;
2783            that.noScroll = true;
2784            that.$menuInner.scrollTop(0);
2785            that.selectpicker.search.elements = searchMatch;
2786            that.createView(true);
2787
2788            if (!searchMatch.length) {
2789              noResults.className = 'no-results';
2790              noResults.innerHTML = that.options.noneResultsText.replace('{0}', '"' + htmlEscape(searchValue) + '"');
2791              that.$menuInner[0].firstChild.appendChild(noResults);
2792            }
2793          } else {
2794            that.$menuInner.scrollTop(0);
2795            that.createView(false);
2796          }
2797        });
2798      },
2799
2800      _searchStyle: function() {
2801        return this.options.liveSearchStyle || 'contains';
2802      },
2803
2804      val: function(value) {
2805        var element = this.$element[0];
2806
2807        if (typeof value !== 'undefined') {
2808          var prevValue = getSelectValues(element);
2809
2810          changedArguments = [null, null, prevValue];
2811
2812          this.$element
2813            .val(value)
2814            .trigger('changed' + EVENT_KEY, changedArguments);
2815
2816          if (this.$newElement.hasClass(classNames.SHOW)) {
2817            if (this.multiple) {
2818              this.setOptionStatus(true);
2819            } else {
2820              var liSelectedIndex = (element.options[element.selectedIndex] || {}).liIndex;
2821
2822              if (typeof liSelectedIndex === 'number') {
2823                this.setSelected(this.selectedIndex, false);
2824                this.setSelected(liSelectedIndex, true);
2825              }
2826            }
2827          }
2828
2829          this.render();
2830
2831          changedArguments = null;
2832
2833          return this.$element;
2834        } else {
2835          return this.$element.val();
2836        }
2837      },
2838
2839      changeAll: function(status) {
2840        if (!this.multiple) return;
2841        if (typeof status === 'undefined') status = true;
2842
2843        var element = this.$element[0],
2844          previousSelected = 0,
2845          currentSelected = 0,
2846          prevValue = getSelectValues(element);
2847
2848        element.classList.add('bs-select-hidden');
2849
2850        for (var i = 0, len = this.selectpicker.current.elements.length; i < len; i++) {
2851          var liData = this.selectpicker.current.data[i],
2852            option = liData.option;
2853
2854          if (option && !liData.disabled && liData.type !== 'divider') {
2855            if (liData.selected) previousSelected++;
2856            option.selected = status;
2857            if (status) currentSelected++;
2858          }
2859        }
2860
2861        element.classList.remove('bs-select-hidden');
2862
2863        if (previousSelected === currentSelected) return;
2864
2865        this.setOptionStatus();
2866
2867        changedArguments = [null, null, prevValue];
2868
2869        this.$element
2870          .triggerNative('change');
2871      },
2872
2873      selectAll: function() {
2874        return this.changeAll(true);
2875      },
2876
2877      deselectAll: function() {
2878        return this.changeAll(false);
2879      },
2880
2881      toggle: function(e) {
2882        e = e || window.event;
2883
2884        if (e) e.stopPropagation();
2885
2886        this.$button.trigger('click.bs.dropdown.data-api');
2887      },
2888
2889      keydown: function(e) {
2890        var $this = $(this),
2891          isToggle = $this.hasClass('dropdown-toggle'),
2892          $parent = isToggle ? $this.closest('.dropdown') : $this.closest(Selector.MENU),
2893          that = $parent.data('this'),
2894          $items = that.findLis(),
2895          index,
2896          isActive,
2897          liActive,
2898          activeLi,
2899          offset,
2900          updateScroll = false,
2901          downOnTab = e.which === keyCodes.TAB && !isToggle && !that.options.selectOnTab,
2902          isArrowKey = REGEXP_ARROW.test(e.which) || downOnTab,
2903          scrollTop = that.$menuInner[0].scrollTop,
2904          isVirtual = that.isVirtual(),
2905          position0 = isVirtual === true ? that.selectpicker.view.position0 : 0;
2906
2907        // do nothing if a function key is pressed
2908        if (e.which >= 112 && e.which <= 123) return;
2909
2910        isActive = that.$newElement.hasClass(classNames.SHOW);
2911
2912        if (
2913          !isActive &&
2914          (
2915            isArrowKey ||
2916            (e.which >= 48 && e.which <= 57) ||
2917            (e.which >= 96 && e.which <= 105) ||
2918            (e.which >= 65 && e.which <= 90)
2919          )
2920        ) {
2921          that.$button.trigger('click.bs.dropdown.data-api');
2922
2923          if (that.options.liveSearch) {
2924            that.$searchbox.trigger('focus');
2925            return;
2926          }
2927        }
2928
2929        if (e.which === keyCodes.ESCAPE && isActive) {
2930          e.preventDefault();
2931          that.$button.trigger('click.bs.dropdown.data-api').trigger('focus');
2932        }
2933
2934        if (isArrowKey) { // if up or down
2935          if (!$items.length) return;
2936
2937          liActive = that.selectpicker.main.elements[that.activeIndex];
2938          index = liActive ? Array.prototype.indexOf.call(liActive.parentElement.children, liActive) : -1;
2939
2940          if (index !== -1) {
2941            that.defocusItem(liActive);
2942          }
2943
2944          if (e.which === keyCodes.ARROW_UP) { // up
2945            if (index !== -1) index--;
2946            if (index + position0 < 0) index += $items.length;
2947
2948            if (!that.selectpicker.view.canHighlight[index + position0]) {
2949              index = that.selectpicker.view.canHighlight.slice(0, index + position0).lastIndexOf(true) - position0;
2950              if (index === -1) index = $items.length - 1;
2951            }
2952          } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down
2953            index++;
2954            if (index + position0 >= that.selectpicker.view.canHighlight.length) index = 0;
2955
2956            if (!that.selectpicker.view.canHighlight[index + position0]) {
2957              index = index + 1 + that.selectpicker.view.canHighlight.slice(index + position0 + 1).indexOf(true);
2958            }
2959          }
2960
2961          e.preventDefault();
2962
2963          var liActiveIndex = position0 + index;
2964
2965          if (e.which === keyCodes.ARROW_UP) { // up
2966            // scroll to bottom and highlight last option
2967            if (position0 === 0 && index === $items.length - 1) {
2968              that.$menuInner[0].scrollTop = that.$menuInner[0].scrollHeight;
2969
2970              liActiveIndex = that.selectpicker.current.elements.length - 1;
2971            } else {
2972              activeLi = that.selectpicker.current.data[liActiveIndex];
2973              offset = activeLi.position - activeLi.height;
2974
2975              updateScroll = offset < scrollTop;
2976            }
2977          } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down
2978            // scroll to top and highlight first option
2979            if (index === 0) {
2980              that.$menuInner[0].scrollTop = 0;
2981
2982              liActiveIndex = 0;
2983            } else {
2984              activeLi = that.selectpicker.current.data[liActiveIndex];
2985              offset = activeLi.position - that.sizeInfo.menuInnerHeight;
2986
2987              updateScroll = offset > scrollTop;
2988            }
2989          }
2990
2991          liActive = that.selectpicker.current.elements[liActiveIndex];
2992
2993          that.activeIndex = that.selectpicker.current.data[liActiveIndex].index;
2994
2995          that.focusItem(liActive);
2996
2997          that.selectpicker.view.currentActive = liActive;
2998
2999          if (updateScroll) that.$menuInner[0].scrollTop = offset;
3000
3001          if (that.options.liveSearch) {
3002            that.$searchbox.trigger('focus');
3003          } else {
3004            $this.trigger('focus');
3005          }
3006        } else if (
3007          (!$this.is('input') && !REGEXP_TAB_OR_ESCAPE.test(e.which)) ||
3008          (e.which === keyCodes.SPACE && that.selectpicker.keydown.keyHistory)
3009        ) {
3010          var searchMatch,
3011            matches = [],
3012            keyHistory;
3013
3014          e.preventDefault();
3015
3016          that.selectpicker.keydown.keyHistory += keyCodeMap[e.which];
3017
3018          if (that.selectpicker.keydown.resetKeyHistory.cancel) clearTimeout(that.selectpicker.keydown.resetKeyHistory.cancel);
3019          that.selectpicker.keydown.resetKeyHistory.cancel = that.selectpicker.keydown.resetKeyHistory.start();
3020
3021          keyHistory = that.selectpicker.keydown.keyHistory;
3022
3023          // if all letters are the same, set keyHistory to just the first character when searching
3024          if (/^(.)\1+$/.test(keyHistory)) {
3025            keyHistory = keyHistory.charAt(0);
3026          }
3027
3028          // find matches
3029          for (var i = 0; i < that.selectpicker.current.data.length; i++) {
3030            var li = that.selectpicker.current.data[i],
3031              hasMatch;
3032
3033            hasMatch = stringSearch(li, keyHistory, 'startsWith', true);
3034
3035            if (hasMatch && that.selectpicker.view.canHighlight[i]) {
3036              matches.push(li.index);
3037            }
3038          }
3039
3040          if (matches.length) {
3041            var matchIndex = 0;
3042
3043            $items.removeClass('active').find('a').removeClass('active');
3044
3045            // either only one key has been pressed or they are all the same key
3046            if (keyHistory.length === 1) {
3047              matchIndex = matches.indexOf(that.activeIndex);
3048
3049              if (matchIndex === -1 || matchIndex === matches.length - 1) {
3050                matchIndex = 0;
3051              } else {
3052                matchIndex++;
3053              }
3054            }
3055
3056            searchMatch = matches[matchIndex];
3057
3058            activeLi = that.selectpicker.main.data[searchMatch];
3059
3060            if (scrollTop - activeLi.position > 0) {
3061              offset = activeLi.position - activeLi.height;
3062              updateScroll = true;
3063            } else {
3064              offset = activeLi.position - that.sizeInfo.menuInnerHeight;
3065              // if the option is already visible at the current scroll position, just keep it the same
3066              updateScroll = activeLi.position > scrollTop + that.sizeInfo.menuInnerHeight;
3067            }
3068
3069            liActive = that.selectpicker.main.elements[searchMatch];
3070
3071            that.activeIndex = matches[matchIndex];
3072
3073            that.focusItem(liActive);
3074
3075            if (liActive) liActive.firstChild.focus();
3076
3077            if (updateScroll) that.$menuInner[0].scrollTop = offset;
3078
3079            $this.trigger('focus');
3080          }
3081        }
3082
3083        // Select focused option if "Enter", "Spacebar" or "Tab" (when selectOnTab is true) are pressed inside the menu.
3084        if (
3085          isActive &&
3086          (
3087            (e.which === keyCodes.SPACE && !that.selectpicker.keydown.keyHistory) ||
3088            e.which === keyCodes.ENTER ||
3089            (e.which === keyCodes.TAB && that.options.selectOnTab)
3090          )
3091        ) {
3092          if (e.which !== keyCodes.SPACE) e.preventDefault();
3093
3094          if (!that.options.liveSearch || e.which !== keyCodes.SPACE) {
3095            that.$menuInner.find('.active a').trigger('click', true); // retain active class
3096            $this.trigger('focus');
3097
3098            if (!that.options.liveSearch) {
3099              // Prevent screen from scrolling if the user hits the spacebar
3100              e.preventDefault();
3101              // Fixes spacebar selection of dropdown items in FF & IE
3102              $(document).data('spaceSelect', true);
3103            }
3104          }
3105        }
3106      },
3107
3108      mobile: function() {
3109        this.$element[0].classList.add('mobile-device');
3110      },
3111
3112      refresh: function() {
3113        // update options if data attributes have been changed
3114        var config = $.extend({}, this.options, this.$element.data());
3115        this.options = config;
3116
3117        this.checkDisabled();
3118        this.setStyle();
3119        this.render();
3120        this.createLi();
3121        this.setWidth();
3122
3123        this.setSize(true);
3124
3125        this.$element.trigger('refreshed' + EVENT_KEY);
3126      },
3127
3128      hide: function() {
3129        this.$newElement.hide();
3130      },
3131
3132      show: function() {
3133        this.$newElement.show();
3134      },
3135
3136      remove: function() {
3137        this.$newElement.remove();
3138        this.$element.remove();
3139      },
3140
3141      destroy: function() {
3142        this.$newElement.before(this.$element).remove();
3143
3144        if (this.$bsContainer) {
3145          this.$bsContainer.remove();
3146        } else {
3147          this.$menu.remove();
3148        }
3149
3150        this.$element
3151          .off(EVENT_KEY)
3152          .removeData('selectpicker')
3153          .removeClass('bs-select-hidden selectpicker');
3154
3155        $(window).off(EVENT_KEY + '.' + this.selectId);
3156      }
3157    };
3158
3159    // SELECTPICKER PLUGIN DEFINITION
3160    // ==============================
3161    function Plugin(option) {
3162      // get the args of the outer function..
3163      var args = arguments;
3164      // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them
3165      // to get lost/corrupted in android 2.3 and IE9 #715 #775
3166      var _option = option;
3167
3168      [].shift.apply(args);
3169
3170      // if the version was not set successfully
3171      if (!version.success) {
3172        // try to retreive it again
3173        try {
3174          version.full = ($.fn.dropdown.Constructor.VERSION || '').split(' ')[0].split('.');
3175        } catch (err) {
3176          // fall back to use BootstrapVersion if set
3177          if (Selectpicker.BootstrapVersion) {
3178            version.full = Selectpicker.BootstrapVersion.split(' ')[0].split('.');
3179          } else {
3180            version.full = [version.major, '0', '0'];
3181
3182            console.warn(
3183              'There was an issue retrieving Bootstrap\'s version. ' +
3184              'Ensure Bootstrap is being loaded before bootstrap-select and there is no namespace collision. ' +
3185              'If loading Bootstrap asynchronously, the version may need to be manually specified via $.fn.selectpicker.Constructor.BootstrapVersion.',
3186              err
3187            );
3188          }
3189        }
3190
3191        version.major = version.full[0];
3192        version.success = true;
3193      }
3194
3195      if (version.major === '4') {
3196        // some defaults need to be changed if using Bootstrap 4
3197        // check to see if they have already been manually changed before forcing them to update
3198        var toUpdate = [];
3199
3200        if (Selectpicker.DEFAULTS.style === classNames.BUTTONCLASS) toUpdate.push({
3201          name: 'style',
3202          className: 'BUTTONCLASS'
3203        });
3204        if (Selectpicker.DEFAULTS.iconBase === classNames.ICONBASE) toUpdate.push({
3205          name: 'iconBase',
3206          className: 'ICONBASE'
3207        });
3208        if (Selectpicker.DEFAULTS.tickIcon === classNames.TICKICON) toUpdate.push({
3209          name: 'tickIcon',
3210          className: 'TICKICON'
3211        });
3212
3213        classNames.DIVIDER = 'dropdown-divider';
3214        classNames.SHOW = 'show';
3215        classNames.BUTTONCLASS = 'btn-light';
3216        classNames.POPOVERHEADER = 'popover-header';
3217        classNames.ICONBASE = '';
3218        classNames.TICKICON = 'material-icons';
3219
3220        for (var i = 0; i < toUpdate.length; i++) {
3221          var option = toUpdate[i];
3222          Selectpicker.DEFAULTS[option.name] = classNames[option.className];
3223        }
3224      }
3225
3226      var value;
3227      var chain = this.each(function() {
3228        var $this = $(this);
3229        if ($this.is('select')) {
3230          var data = $this.data('selectpicker'),
3231            options = typeof _option == 'object' && _option;
3232
3233          if (!data) {
3234            var dataAttributes = $this.data();
3235
3236            for (var dataAttr in dataAttributes) {
3237              if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
3238                delete dataAttributes[dataAttr];
3239              }
3240            }
3241
3242            var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, dataAttributes, options);
3243            config.template = $.extend({}, Selectpicker.DEFAULTS.template, ($.fn.selectpicker.defaults ? $.fn.selectpicker.defaults.template : {}), dataAttributes.template, options.template);
3244            $this.data('selectpicker', (data = new Selectpicker(this, config)));
3245          } else if (options) {
3246            for (var i in options) {
3247              if (options.hasOwnProperty(i)) {
3248                data.options[i] = options[i];
3249              }
3250            }
3251          }
3252
3253          if (typeof _option == 'string') {
3254            if (data[_option] instanceof Function) {
3255              value = data[_option].apply(data, args);
3256            } else {
3257              value = data.options[_option];
3258            }
3259          }
3260        }
3261      });
3262
3263      if (typeof value !== 'undefined') {
3264        // noinspection JSUnusedAssignment
3265        return value;
3266      } else {
3267        return chain;
3268      }
3269    }
3270
3271    var old = $.fn.selectpicker;
3272    $.fn.selectpicker = Plugin;
3273    $.fn.selectpicker.Constructor = Selectpicker;
3274
3275    // SELECTPICKER NO CONFLICT
3276    // ========================
3277    $.fn.selectpicker.noConflict = function() {
3278      $.fn.selectpicker = old;
3279      return this;
3280    };
3281
3282    $(document)
3283      .off('keydown.bs.dropdown.data-api', '.bootstrap-select [data-toggle="dropdown"], .bootstrap-select .dropdown-menu')
3284      .on('keydown' + EVENT_KEY, '.bootstrap-select [data-toggle="dropdown"], .bootstrap-select [role="listbox"], .bootstrap-select .bs-searchbox input', Selectpicker.prototype.keydown)
3285      .on('focusin.modal', '.bootstrap-select [data-toggle="dropdown"], .bootstrap-select [role="listbox"], .bootstrap-select .bs-searchbox input', function(e) {
3286        e.stopPropagation();
3287      });
3288
3289    // SELECTPICKER DATA-API
3290    // =====================
3291    $(window).on('load' + EVENT_KEY + '.data-api', function() {
3292      $('.selectpicker').each(function() {
3293        var $selectpicker = $(this);
3294        Plugin.call($selectpicker, $selectpicker.data());
3295      })
3296    });
3297  })(jQuery);
3298
3299
3300}));

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.