PageSourceSearch

https://uch.edu.ar/web/js/bootstrap-selectpicker.js

js uch.edu.ar collected 2026-10-02 07:35:17 UTC 69,993 bytes, 1,906 lines download raw bytes

vendor: 4,244 bytes, lines 1-129
1/*!
2 * Bootstrap-select v1.12.2 (http://silviomoreto.github.io/bootstrap-select)
3 *
4 * Copyright 2013-2017 bootstrap-select
5 * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 */
7
8 /*
9
10
11      Creative Tim Modifications
12
13      Line: 379-380 - we changed glyphicons with material-icons.
14      Line: 593 - we put tickIcon inside of span tag.
15
16
17 */
18
19(function (root, factory) {
20  if (typeof define === 'function' && define.amd) {
21    // AMD. Register as an anonymous module unless amdModuleId is set
22    define(["jquery"], function (a0) {
23      return (factory(a0));
24    });
25  } else if (typeof module === 'object' && module.exports) {
26    // Node. Does not work with strict CommonJS, but
27    // only CommonJS-like environments that support module.exports,
28    // like Node.
29    module.exports = factory(require("jquery"));
30  } else {
31    factory(root["jQuery"]);
32  }
33}(this, function (jQuery) {
34
35(function ($) {
36  'use strict';
37
38  //<editor-fold desc="Shims">
39  if (!String.prototype.includes) {
40    (function () {
41      'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
42      var toString = {}.toString;
43      var defineProperty = (function () {
44        // IE 8 only supports `Object.defineProperty` on DOM elements
45        try {
46          var object = {};
47          var $defineProperty = Object.defineProperty;
48          var result = $defineProperty(object, object, object) && $defineProperty;
49        } catch (error) {
50        }
51        return result;
52      }());
53      var indexOf = ''.indexOf;
54      var includes = function (search) {
55        if (this == null) {
56          throw new TypeError();
57        }
58        var string = String(this);
59        if (search && toString.call(search) == '[object RegExp]') {
60          throw new TypeError();
61        }
62        var stringLength = string.length;
63        var searchString = String(search);
64        var searchLength = searchString.length;
65        var position = arguments.length > 1 ? arguments[1] : undefined;
66        // `ToInteger`
67        var pos = position ? Number(position) : 0;
68        if (pos != pos) { // better `isNaN`
69          pos = 0;
70        }
71        var start = Math.min(Math.max(pos, 0), stringLength);
72        // Avoid the `indexOf` call if no match is possible
73        if (searchLength + start > stringLength) {
74          return false;
75        }
76        return indexOf.call(string, searchString, pos) != -1;
77      };
78      if (defineProperty) {
79        defineProperty(String.prototype, 'includes', {
80          'value': includes,
81          'configurable': true,
82          'writable': true
83        });
84      } else {
85        String.prototype.includes = includes;
86      }
87    }());
88  }
89
90  if (!String.prototype.startsWith) {
91    (function () {
92      'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
93      var defineProperty = (function () {
94        // IE 8 only supports `Object.defineProperty` on DOM elements
95        try {
96          var object = {};
97          var $defineProperty = Object.defineProperty;
98          var result = $defineProperty(object, object, object) && $defineProperty;
99        } catch (error) {
100        }
101        return result;
102      }());
103      var toString = {}.toString;
104      var startsWith = function (search) {
105        if (this == null) {
106          throw new TypeError();
107        }
108        var string = String(this);
109        if (search && toString.call(search) == '[object RegExp]') {
110          throw new TypeError();
111        }
112        var stringLength = string.length;
113        var searchString = String(search);
114        var searchLength = searchString.length;
115        var position = arguments.length > 1 ? arguments[1] : undefined;
116        // `ToInteger`
117        var pos = position ? Number(position) : 0;
118        if (pos != pos) { // better `isNaN`
119          pos = 0;
120        }
121        var start = Math.min(Math.max(pos, 0), stringLength);
122        // Avoid the `indexOf` call if no match is possible
123        if (searchLength + start > stringLength) {
124          return false;
125        }
126        var index = -1;
127        while (++index < searchLength) {
128          if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {
129            return false;
130          }
131        }
132        return true;
133      };
134      if (defineProperty) {
135        defineProperty(String.prototype, 'startsWith', {
136          'value': startsWith,
137          'configurable': true,
138          'writable': true
139        });
140      } else {
141        String.prototype.startsWith = startsWith;
142      }
143    }());
144  }
145
146  if (!Object.keys) {
147    Object.keys = function (
148      o, // object
149      k, // key
150      r  // result array
151      ){
152      // initialize object and result
153      r=[];
154      // iterate over object keys
155      for (k in o)
156          // fill result array with non-prototypical keys
157        r.hasOwnProperty.call(o, k) && r.push(k);
158      // return result
159      return r;
160    };
161  }
162
163  // set data-selected on select element if the value has been programmatically selected
164  // prior to initialization of bootstrap-select
165  // * consider removing or replacing an alternative method *
166  var valHooks = {
167    useDefault: false,
168    _set: $.valHooks.select.set
169  };
170
171  $.valHooks.select.set = function(elem, value) {
172    if (value && !valHooks.useDefault) $(elem).data('selected', true);
173
174    return valHooks._set.apply(this, arguments);
175  };
176
177  var changed_arguments = null;
178  $.fn.triggerNative = function (eventName) {
179    var el = this[0],
180        event;
181
182    if (el.dispatchEvent) { // for modern browsers & IE9+
183      if (typeof Event === 'function') {
184        // For modern browsers
185        event = new Event(eventName, {
186          bubbles: true
187        });
188      } else {
189        // For IE since it doesn't support Event constructor
190        event = document.createEvent('Event');
191        event.initEvent(eventName, true, false);
192      }
193
194      el.dispatchEvent(event);
195    } else if (el.fireEvent) { // for IE8
196      event = document.createEventObject();
197      event.eventType = eventName;
198      el.fireEvent('on' + eventName, event);
199    } else {
200      // fall back to jQuery.trigger
201      this.trigger(eventName);
202    }
203  };
204  //</editor-fold>
205
206  // Case insensitive contains search
207  $.expr.pseudos.icontains = function (obj, index, meta) {
208    var $obj = $(obj);
209    var haystack = ($obj.data('tokens') || $obj.text()).toString().toUpperCase();
210    return haystack.includes(meta[3].toUpperCase());
211  };
212
213  // Case insensitive begins search
214  $.expr.pseudos.ibegins = function (obj, index, meta) {
215    var $obj = $(obj);
216    var haystack = ($obj.data('tokens') || $obj.text()).toString().toUpperCase();
217    return haystack.startsWith(meta[3].toUpperCase());
218  };
219
220  // Case and accent insensitive contains search
221  $.expr.pseudos.aicontains = function (obj, index, meta) {
222    var $obj = $(obj);
223    var haystack = ($obj.data('tokens') || $obj.data('normalizedText') || $obj.text()).toString().toUpperCase();
224    return haystack.includes(meta[3].toUpperCase());
225  };
226
227  // Case and accent insensitive begins search
228  $.expr.pseudos.aibegins = function (obj, index, meta) {
229    var $obj = $(obj);
230    var haystack = ($obj.data('tokens') || $obj.data('normalizedText') || $obj.text()).toString().toUpperCase();
231    return haystack.startsWith(meta[3].toUpperCase());
232  };
233
234  /**
235   * Remove all diatrics from the given text.
236   * @access private
237   * @param {String} text
238   * @returns {String}
239   */
240  function normalizeToBase(text) {
241    var rExps = [
242      {re: /[\xC0-\xC6]/g, ch: "A"},
243      {re: /[\xE0-\xE6]/g, ch: "a"},
244      {re: /[\xC8-\xCB]/g, ch: "E"},
245      {re: /[\xE8-\xEB]/g, ch: "e"},
246      {re: /[\xCC-\xCF]/g, ch: "I"},
247      {re: /[\xEC-\xEF]/g, ch: "i"},
248      {re: /[\xD2-\xD6]/g, ch: "O"},
249      {re: /[\xF2-\xF6]/g, ch: "o"},
250      {re: /[\xD9-\xDC]/g, ch: "U"},
251      {re: /[\xF9-\xFC]/g, ch: "u"},
252      {re: /[\xC7-\xE7]/g, ch: "c"},
253      {re: /[\xD1]/g, ch: "N"},
254      {re: /[\xF1]/g, ch: "n"}
255    ];
256    $.each(rExps, function () {
257      text = text ? text.replace(this.re, this.ch) : '';
258    });
259    return text;
260  }
261
262
263  // List of HTML entities for escaping.
264  var escapeMap = {
265    '&': '&amp;',
266    '<': '&lt;',
267    '>': '&gt;',
268    '"': '&quot;',
269    "'": '&#x27;',
270    '`': '&#x60;'
271  };
272
273  var unescapeMap = {
274    '&amp;': '&',
275    '&lt;': '<',
276    '&gt;': '>',
277    '&quot;': '"',
278    '&#x27;': "'",
279    '&#x60;': '`'
280  };
281
282  // Functions for escaping and unescaping strings to/from HTML interpolation.
283  var createEscaper = function(map) {
284    var escaper = function(match) {
285      return map[match];
286    };
287    // Regexes for identifying a key that needs to be escaped.
288    var source = '(?:' + Object.keys(map).join('|') + ')';
289    var testRegexp = RegExp(source);
290    var replaceRegexp = RegExp(source, 'g');
291    return function(string) {
292      string = string == null ? '' : '' + string;
293      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
294    };
295  };
296
297  var htmlEscape = createEscaper(escapeMap);
298  var htmlUnescape = createEscaper(unescapeMap);
299
300  var Selectpicker = function (element, options) {
301    // bootstrap-select has been initialized - revert valHooks.select.set back to its original function
302    if (!valHooks.useDefault) {
303      $.valHooks.select.set = valHooks._set;
304      valHooks.useDefault = true;
305    }
306
307    this.$element = $(element);
308    this.$newElement = null;
309    this.$button = null;
310    this.$menu = null;
311    this.$lis = null;
312    this.options = options;
313
314    // 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
315    // data-attribute)
316    if (this.options.title === null) {
317      this.options.title = this.$element.attr('title');
318    }
319
320    // Format window padding
321    var winPad = this.options.windowPadding;
322    if (typeof winPad === 'number') {
323      this.options.windowPadding = [winPad, winPad, winPad, winPad];
324    }
325
326    //Expose public methods
327    this.val = Selectpicker.prototype.val;
328    this.render = Selectpicker.prototype.render;
329    this.refresh = Selectpicker.prototype.refresh;
330    this.setStyle = Selectpicker.prototype.setStyle;
331    this.selectAll = Selectpicker.prototype.selectAll;
332    this.deselectAll = Selectpicker.prototype.deselectAll;
333    this.destroy = Selectpicker.prototype.destroy;
334    this.remove = Selectpicker.prototype.remove;
335    this.show = Selectpicker.prototype.show;
336    this.hide = Selectpicker.prototype.hide;
337
338    this.init();
339  };
340
341  Selectpicker.VERSION = '1.12.2';
342
343  // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.
344  Selectpicker.DEFAULTS = {
345    noneSelectedText: 'Nothing selected',
346    noneResultsText: 'No results matched {0}',
347    countSelectedText: function (numSelected, numTotal) {
348      return (numSelected == 1) ? "{0} item selected" : "{0} items selected";
349    },
350    maxOptionsText: function (numAll, numGroup) {
351      return [
352        (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',
353        (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'
354      ];
355    },
356    selectAllText: 'Select All',
357    deselectAllText: 'Deselect All',
358    doneButton: false,
359    doneButtonText: 'Close',
360    multipleSeparator: ', ',
361    styleBase: 'btn',
362    style: 'btn-default',
363    size: 'auto',
364    title: null,
365    selectedTextFormat: 'values',
366    width: false,
367    container: false,
368    hideDisabled: false,
369    showSubtext: false,
370    showIcon: true,
371    showContent: true,
372    dropupAuto: true,
373    header: false,
374    liveSearch: false,
375    liveSearchPlaceholder: null,
376    liveSearchNormalize: false,
377    liveSearchStyle: 'contains',
378    actionsBox: false,
379    iconBase: 'material-icons',
380    tickIcon: 'done',
381    showTick: false,
382    template: {
383      caret: '<span class="caret"></span>'
384    },
385    maxOptions: false,
386    mobile: false,
387    selectOnTab: false,
388    dropdownAlignRight: false,
389    windowPadding: 0
390  };
391
392  Selectpicker.prototype = {
393
394    constructor: Selectpicker,
395
396    init: function () {
397      var that = this,
398          id = this.$element.attr('id');
399
400      this.$element.addClass('bs-select-hidden');
401
402      // store originalIndex (key) and newIndex (value) in this.liObj for fast accessibility
403      // allows us to do this.$lis.eq(that.liObj[index]) instead of this.$lis.filter('[data-original-index="' + index + '"]')
404      this.liObj = {};
405      this.multiple = this.$element.prop('multiple');
406      this.autofocus = this.$element.prop('autofocus');
407      this.$newElement = this.createView();
408      this.$element
409        .after(this.$newElement)
410        .appendTo(this.$newElement);
411      this.$button = this.$newElement.children('button');
412      this.$menu = this.$newElement.children('.dropdown-menu');
413      this.$menuInner = this.$menu.children('.inner');
414      this.$searchbox = this.$menu.find('input');
415
416      this.$element.removeClass('bs-select-hidden');
417
418      if (this.options.dropdownAlignRight === true) this.$menu.addClass('dropdown-menu-right');
419
420      if (typeof id !== 'undefined') {
421        this.$button.attr('data-id', id);
422        $('label[for="' + id + '"]').click(function (e) {
423          e.preventDefault();
424          that.$button.focus();
425        });
426      }
427
428      this.checkDisabled();
429      this.clickListener();
430      if (this.options.liveSearch) this.liveSearchListener();
431      this.render();
432      this.setStyle();
433      this.setWidth();
434      if (this.options.container) this.selectPosition();
435      this.$menu.data('this', this);
436      this.$newElement.data('this', this);
437      if (this.options.mobile) this.mobile();
438
439      this.$newElement.on({
440        'hide.bs.dropdown': function (e) {
441          that.$menuInner.attr('aria-expanded', false);
442          that.$element.trigger('hide.bs.select', e);
443        },
444        'hidden.bs.dropdown': function (e) {
445          that.$element.trigger('hidden.bs.select', e);
446        },
447        'show.bs.dropdown': function (e) {
448          that.$menuInner.attr('aria-expanded', true);
449          that.$element.trigger('show.bs.select', e);
450        },
451        'shown.bs.dropdown': function (e) {
452          that.$element.trigger('shown.bs.select', e);
453        }
454      });
455
456      if (that.$element[0].hasAttribute('required')) {
457        this.$element.on('invalid', function () {
458          that.$button
459            .addClass('bs-invalid')
460            .focus();
461
462          that.$element.on({
463            'focus.bs.select': function () {
464              that.$button.focus();
465              that.$element.off('focus.bs.select');
466            },
467            'shown.bs.select': function () {
468              that.$element
469                .val(that.$element.val()) // set the value to hide the validation message in Chrome when menu is opened
470                .off('shown.bs.select');
471            },
472            'rendered.bs.select': function () {
473              // if select is no longer invalid, remove the bs-invalid class
474              if (this.validity.valid) that.$button.removeClass('bs-invalid');
475              that.$element.off('rendered.bs.select');
476            }
477          });
478        });
479      }
480
481      setTimeout(function () {
482        that.$element.trigger('loaded.bs.select');
483      });
484    },
485
486    createDropdown: function () {
487      // Options
488      // If we are multiple or showTick option is set, then add the show-tick class
489      var showTick = (this.multiple || this.options.showTick) ? ' show-tick' : '',
490          inputGroup = this.$element.parent().hasClass('input-group') ? ' input-group-btn' : '',
491          autofocus = this.autofocus ? ' autofocus' : '';
492      // Elements
493      var header = this.options.header ? '<div class="popover-title"><button type="button" class="close" aria-hidden="true">&times;</button>' + this.options.header + '</div>' : '';
494      var searchbox = this.options.liveSearch ?
495      '<div class="bs-searchbox">' +
496      '<input type="text" class="form-control" autocomplete="off"' +
497      (null === this.options.liveSearchPlaceholder ? '' : ' placeholder="' + htmlEscape(this.options.liveSearchPlaceholder) + '"') + ' role="textbox" aria-label="Search">' +
498      '</div>'
499          : '';
500      var actionsbox = this.multiple && this.options.actionsBox ?
501      '<div class="bs-actionsbox">' +
502      '<div class="btn-group btn-group-sm btn-block">' +
503      '<button type="button" class="actions-btn bs-select-all btn btn-default">' +
504      this.options.selectAllText +
505      '</button>' +
506      '<button type="button" class="actions-btn bs-deselect-all btn btn-default">' +
507      this.options.deselectAllText +
508      '</button>' +
509      '</div>' +
510      '</div>'
511          : '';
512      var donebutton = this.multiple && this.options.doneButton ?
513      '<div class="bs-donebutton">' +
514      '<div class="btn-group btn-block">' +
515      '<button type="button" class="btn btn-sm btn-default">' +
516      this.options.doneButtonText +
517      '</button>' +
518      '</div>' +
519      '</div>'
520          : '';
521      var drop =
522          '<div class="btn-group bootstrap-select' + showTick + inputGroup + '">' +
523          '<button type="button" class="' + this.options.styleBase + ' dropdown-toggle" data-toggle="dropdown"' + autofocus + ' role="button">' +
524          '<span class="filter-option pull-left"></span>&nbsp;' +
525          '<span class="bs-caret">' +
526          this.options.template.caret +
527          '</span>' +
528          '</button>' +
529          '<div class="dropdown-menu open" role="combobox">' +
530          header +
531          searchbox +
532          actionsbox +
533          '<ul class="dropdown-menu inner" role="listbox" aria-expanded="false">' +
534          '</ul>' +
535          donebutton +
536          '</div>' +
537          '</div>';
538
539      return $(drop);
540    },
541
542    createView: function () {
543      var $drop = this.createDropdown(),
544          li = this.createLi();
545
546      $drop.find('ul')[0].innerHTML = li;
547      return $drop;
548    },
549
550    reloadLi: function () {
551      // rebuild
552      var li = this.createLi();
553      this.$menuInner[0].innerHTML = li;
554    },
555
556    createLi: function () {
557      var that = this,
558          _li = [],
559          optID = 0,
560          titleOption = document.createElement('option'),
561          liIndex = -1; // increment liIndex whenever a new <li> element is created to ensure liObj is correct
562
563      // Helper functions
564      /**
565       * @param content
566       * @param [index]
567       * @param [classes]
568       * @param [optgroup]
569       * @returns {string}
570       */
571      var generateLI = function (content, index, classes, optgroup) {
572        return '<li' +
573            ((typeof classes !== 'undefined' & '' !== classes) ? ' class="' + classes + '"' : '') +
574            ((typeof index !== 'undefined' & null !== index) ? ' data-original-index="' + index + '"' : '') +
575            ((typeof optgroup !== 'undefined' & null !== optgroup) ? 'data-optgroup="' + optgroup + '"' : '') +
576            '>' + content + '</li>';
577      };
578
579      /**
580       * @param text
581       * @param [classes]
582       * @param [inline]
583       * @param [tokens]
584       * @returns {string}
585       */
586      var generateA = function (text, classes, inline, tokens) {
587        return '<a tabindex="0"' +
588            (typeof classes !== 'undefined' ? ' class="' + classes + '"' : '') +
589            (inline ? ' style="' + inline + '"' : '') +
590            (that.options.liveSearchNormalize ? ' data-normalized-text="' + normalizeToBase(htmlEscape($(text).html())) + '"' : '') +
591            (typeof tokens !== 'undefined' || tokens !== null ? ' data-tokens="' + tokens + '"' : '') +
592            ' role="option">
592' + text +
593            '<span class="' + that.options.iconBase + '  check-mark"> ' + that.options.tickIcon + ' </span>' +
594            '</a>';
595      };
596
597      if (this.options.title && !this.multiple) {
598        // this option doesn't create a new <li> element, but does add a new option, so liIndex is decreased
599        // since liObj is recalculated on every refresh, liIndex needs to be decreased even if the titleOption is already appended
600        liIndex--;
601
602        if (!this.$element.find('.bs-title-option').length) {
603          // Use native JS to prepend option (faster)
604          var element = this.$element[0];
605          titleOption.className = 'bs-title-option';
606          titleOption.innerHTML = this.options.title;
607          titleOption.value = '';
608          element.insertBefore(titleOption, element.firstChild);
609          // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.
610          // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,
611          // if so, the select will have the data-selected attribute
612          var $opt = $(element.options[element.selectedIndex]);
613          if ($opt.attr('selected') === undefined && this.$element.data('selected') === undefined) {
614            titleOption.selected = true;
615          }
616        }
617      }
618
619      this.$element.find('option').each(function (index) {
620        var $this = $(this);
621
622        liIndex++;
623
624        if ($this.hasClass('bs-title-option')) return;
625
626        // Get the class and text for the option
627        var optionClass = this.className || '',
628            inline = this.style.cssText,
629            text = $this.data('content') ? $this.data('content') : $this.html(),
630            tokens = $this.data('tokens') ? $this.data('tokens') : null,
631            subtext = typeof $this.data('subtext') !== 'undefined' ? '<small class="text-muted">' + $this.data('subtext') + '</small>' : '',
632            icon = typeof $this.data('icon') !== 'undefined' ? '<span class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></span> ' : '',
633            $parent = $this.parent(),
634            isOptgroup = $parent[0].tagName === 'OPTGROUP',
635            isOptgroupDisabled = isOptgroup && $parent[0].disabled,
636            isDisabled = this.disabled || isOptgroupDisabled;
637
638        if (icon !== '' && isDisabled) {
639          icon = '<span>' + icon + '</span>';
640        }
641
642        if (that.options.hideDisabled && (isDisabled && !isOptgroup || isOptgroupDisabled)) {
643          liIndex--;
644          return;
645        }
646
647        if (!$this.data('content')) {
648          // Prepend any icon and append any subtext to the main text.
649          text = icon + '<span class="text">' + text + subtext + '</span>';
650        }
651
652        if (isOptgroup && $this.data('divider') !== true) {
653          if (that.options.hideDisabled && isDisabled) {
654            if ($parent.data('allOptionsDisabled') === undefined) {
655              var $options = $parent.children();
656              $parent.data('allOptionsDisabled', $options.filter(':disabled').length === $options.length);
657            }
658
659            if ($parent.data('allOptionsDisabled')) {
660              liIndex--;
661              return;
662            }
663          }
664
665          var optGroupClass = ' ' + $parent[0].className || '';
666
667          if ($this.index() === 0) { // Is it the first option of the optgroup?
668            optID += 1;
669
670            // Get the opt group label
671            var label = $parent[0].label,
672                labelSubtext = typeof $parent.data('subtext') !== 'undefined' ? '<small class="text-muted">' + $parent.data('subtext') + '</small>' : '',
673                labelIcon = $parent.data('icon') ? '<span class="' + that.options.iconBase + ' ' + $parent.data('icon') + '"></span> ' : '';
674
675            label = labelIcon + '<span class="text">' + htmlEscape(label) + labelSubtext + '</span>';
676
677            if (index !== 0 && _li.length > 0) { // Is it NOT the first option of the select && are there elements in the dropdown?
678              liIndex++;
679              _li.push(generateLI('', null, 'divider', optID + 'div'));
680            }
681            liIndex++;
682            _li.push(generateLI(label, null, 'dropdown-header' + optGroupClass, optID));
683          }
684
685          if (that.options.hideDisabled && isDisabled) {
686            liIndex--;
687            return;
688          }
689
690          _li.push(generateLI(generateA(text, 'opt ' + optionClass + optGroupClass, inline, tokens), index, '', optID));
691        } else if ($this.data('divider') === true) {
692          _li.push(generateLI('', index, 'divider'));
693        } else if ($this.data('hidden') === true) {
694          _li.push(generateLI(generateA(text, optionClass, inline, tokens), index, 'hidden is-hidden'));
695        } else {
696          var showDivider = this.previousElementSibling && this.previousElementSibling.tagName === 'OPTGROUP';
697
698          // if previous element is not an optgroup and hideDisabled is true
699          if (!showDivider && that.options.hideDisabled) {
700            // get previous elements
701            var $prev = $(this).prevAll();
702
703            for (var i = 0; i < $prev.length; i++) {
704              // find the first element in the previous elements that is an optgroup
705              if ($prev[i].tagName === 'OPTGROUP') {
706                var optGroupDistance = 0;
707
708                // loop through the options in between the current option and the optgroup
709                // and check if they are hidden or disabled
710                for (var d = 0; d < i; d++) {
711                  var prevOption = $prev[d];
712                  if (prevOption.disabled || $(prevOption).data('hidden') === true) optGroupDistance++;
713                }
714
715                // if all of the options between the current option and the optgroup are hidden or disabled, show the divider
716                if (optGroupDistance === i) showDivider = true;
717
718                break;
719              }
720            }
721          }
722
723          if (showDivider) {
724            liIndex++;
725            _li.push(generateLI('', null, 'divider', optID + 'div'));
726          }
727          _li.push(generateLI(generateA(text, optionClass, inline, tokens), index));
728        }
729
730        that.liObj[index] = liIndex;
731      });
732
733      //If we are not multiple, we don't have a selected item, and we don't have a title, select the first element so something is set in the button
734      if (!this.multiple && this.$element.find('option:selected').length === 0 && !this.options.title) {
735        this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected');
736      }
737
738      return _li.join('');
739    },
740
741    findLis: function () {
742      if (this.$lis == null) this.$lis = this.$menu.find('li');
743      return this.$lis;
744    },
745
746    /**
747     * @param [updateLi] defaults to true
748     */
749    render: function (updateLi) {
750      var that = this,
751          notDisabled;
752
753      //Update the LI to match the SELECT
754      if (updateLi !== false) {
755        this.$element.find('option').each(function (index) {
756          var $lis = that.findLis().eq(that.liObj[index]);
757
758          that.setDisabled(index, this.disabled || this.parentNode.tagName === 'OPTGROUP' && this.parentNode.disabled, $lis);
759          that.setSelected(index, this.selected, $lis);
760        });
761      }
762
763      this.togglePlaceholder();
764
765      this.tabIndex();
766
767      var selectedItems = this.$element.find('option').map(function () {
768        if (this.selected) {
769          if (that.options.hideDisabled && (this.disabled || this.parentNode.tagName === 'OPTGROUP' && this.parentNode.disabled)) return;
770
771          var $this = $(this),
772              icon = $this.data('icon') && that.options.showIcon ? '<i class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></i> ' : '',
773              subtext;
774
775          if (that.options.showSubtext && $this.data('subtext') && !that.multiple) {
776            subtext = ' <small class="text-muted">' + $this.data('subtext') + '</small>';
777          } else {
778            subtext = '';
779          }
780          if (typeof $this.attr('title') !== 'undefined') {
781            return $this.attr('title');
782          } else if ($this.data('content') && that.options.showContent) {
783            return $this.data('content').toString();
784          } else {
785            return icon + $this.html() + subtext;
786          }
787        }
788      }).toArray();
789
790      //Fixes issue in IE10 occurring when no default option is selected and at least one option is disabled
791      //Convert all the values into a comma delimited string
792      var title = !this.multiple ? selectedItems[0] : selectedItems.join(this.options.multipleSeparator);
793
794      //If this is multi select, and the selectText type is count, the show 1 of 2 selected etc..
795      if (this.multiple && this.options.selectedTextFormat.indexOf('count') > -1) {
796        var max = this.options.selectedTextFormat.split('>');
797        if ((max.length > 1 && selectedItems.length > max[1]) || (max.length == 1 && selectedItems.length >= 2)) {
798          notDisabled = this.options.hideDisabled ? ', [disabled]' : '';
799          var totalCount = this.$element.find('option').not('[data-divider="true"], [data-hidden="true"]' + notDisabled).length,
800              tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedItems.length, totalCount) : this.options.countSelectedText;
801          title = tr8nText.replace('{0}', selectedItems.length.toString()).replace('{1}', totalCount.toString());
802        }
803      }
804
805      if (this.options.title == undefined) {
806        this.options.title = this.$element.attr('title');
807      }
808
809      if (this.options.selectedTextFormat == 'static') {
810        title = this.options.title;
811      }
812
813      //If we dont have a title, then use the default, or if nothing is set at all, use the not selected text
814      if (!title) {
815        title = typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText;
816      }
817
818      //strip all HTML tags and trim the result, then unescape any escaped tags
819      this.$button.attr('title', htmlUnescape($.trim(title.replace(/<[^>]*>?/g, ''))));
820      this.$button.children('.filter-option').html(title);
821
822      this.$element.trigger('rendered.bs.select');
823    },
824
825    /**
826     * @param [style]
827     * @param [status]
828     */
829    setStyle: function (style, status) {
830      if (this.$element.attr('class')) {
831        this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi, ''));
832      }
833
834      var buttonClass = style ? style : this.options.style;
835
836      if (status == 'add') {
837        this.$button.addClass(buttonClass);
838      } else if (status == 'remove') {
839        this.$button.removeClass(buttonClass);
840      } else {
841        this.$button.removeClass(this.options.style);
842        this.$button.addClass(buttonClass);
843      }
844    },
845
846    liHeight: function (refresh) {
847      if (!refresh && (this.options.size === false || this.sizeInfo)) return;
848
849      var newElement = document.createElement('div'),
850          menu = document.createElement('div'),
851          menuInner = document.createElement('ul'),
852          divider = document.createElement('li'),
853          li = document.createElement('li'),
854          a = document.createElement('a'),
855          text = document.createElement('span'),
856          header = this.options.header && this.$menu.find('.popover-title').length > 0 ? this.$menu.find('.popover-title')[0].cloneNode(true) : null,
857          search = this.options.liveSearch ? document.createElement('div') : null,
858          actions = this.options.actionsBox && this.multiple && this.$menu.find('.bs-actionsbox').length > 0 ? this.$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,
859          doneButton = this.options.doneButton && this.multiple && this.$menu.find('.bs-donebutton').length > 0 ? this.$menu.find('.bs-donebutton')[0].cloneNode(true) : null;
860
861      text.className = 'text';
862      newElement.className = this.$menu[0].parentNode.className + ' open';
863      menu.className = 'dropdown-menu open';
864      menuInner.className = 'dropdown-menu inner';
865      divider.className = 'divider';
866
867      text.appendChild(document.createTextNode('Inner text'));
868      a.appendChild(text);
869      li.appendChild(a);
870      menuInner.appendChild(li);
871      menuInner.appendChild(divider);
872      if (header) menu.appendChild(header);
873      if (search) {
874        var input = document.createElement('input');
875        search.className = 'bs-searchbox';
876        input.className = 'form-control';
877        search.appendChild(input);
878        menu.appendChild(search);
879      }
880      if (actions) menu.appendChild(actions);
881      menu.appendChild(menuInner);
882      if (doneButton) menu.appendChild(doneButton);
883      newElement.appendChild(menu);
884
885      document.body.appendChild(newElement);
886
887      var liHeight = a.offsetHeight,
888          headerHeight = header ? header.offsetHeight : 0,
889          searchHeight = search ? search.offsetHeight : 0,
890          actionsHeight = actions ? actions.offsetHeight : 0,
891          doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,
892          dividerHeight = $(divider).outerHeight(true),
893          // fall back to jQuery if getComputedStyle is not supported
894          menuStyle = typeof getComputedStyle === 'function' ? getComputedStyle(menu) : false,
895          $menu = menuStyle ? null : $(menu),
896          menuPadding = {
897            vert: parseInt(menuStyle ? menuStyle.paddingTop : $menu.css('paddingTop')) +
898                  parseInt(menuStyle ? menuStyle.paddingBottom : $menu.css('paddingBottom')) +
899                  parseInt(menuStyle ? menuStyle.borderTopWidth : $menu.css('borderTopWidth')) +
900                  parseInt(menuStyle ? menuStyle.borderBottomWidth : $menu.css('borderBottomWidth')),
901            horiz: parseInt(menuStyle ? menuStyle.paddingLeft : $menu.css('paddingLeft')) +
902                  parseInt(menuStyle ? menuStyle.paddingRight : $menu.css('paddingRight')) +
903                  parseInt(menuStyle ? menuStyle.borderLeftWidth : $menu.css('borderLeftWidth')) +
904                  parseInt(menuStyle ? menuStyle.borderRightWidth : $menu.css('borderRightWidth'))
905          },
906          menuExtras =  {
907            vert: menuPadding.vert +
908                  parseInt(menuStyle ? menuStyle.marginTop : $menu.css('marginTop')) +
909                  parseInt(menuStyle ? menuStyle.marginBottom : $menu.css('marginBottom')) + 2,
910            horiz: menuPadding.horiz +
911                  parseInt(menuStyle ? menuStyle.marginLeft : $menu.css('marginLeft')) +
912                  parseInt(menuStyle ? menuStyle.marginRight : $menu.css('marginRight')) + 2
913          }
914
915      document.body.removeChild(newElement);
916
917      this.sizeInfo = {
918        liHeight: liHeight,
919        headerHeight: headerHeight,
920        searchHeight: searchHeight,
921        actionsHeight: actionsHeight,
922        doneButtonHeight: doneButtonHeight,
923        dividerHeight: dividerHeight,
924        menuPadding: menuPadding,
925        menuExtras: menuExtras
926      };
927    },
928
929    setSize: function () {
930      this.findLis();
931      this.liHeight();
932
933      if (this.options.header) this.$menu.css('padding-top', 0);
934      if (this.options.size === false) return;
935
936      var that = this,
937          $menu = this.$menu,
938          $menuInner = this.$menuInner,
939          $window = $(window),
940          selectHeight = this.$newElement[0].offsetHeight,
941          selectWidth = this.$newElement[0].offsetWidth,
942          liHeight = this.sizeInfo['liHeight'],
943          headerHeight = this.sizeInfo['headerHeight'],
944          searchHeight = this.sizeInfo['searchHeight'],
945          actionsHeight = this.sizeInfo['actionsHeight'],
946          doneButtonHeight = this.sizeInfo['doneButtonHeight'],
947          divHeight = this.sizeInfo['dividerHeight'],
948          menuPadding = this.sizeInfo['menuPadding'],
949          menuExtras = this.sizeInfo['menuExtras'],
950          notDisabled = this.options.hideDisabled ? '.disabled' : '',
951          menuHeight,
952          menuWidth,
953          getHeight,
954          getWidth,
955          selectOffsetTop,
956          selectOffsetBot,
957          selectOffsetLeft,
958          selectOffsetRight,
959          getPos = function() {
960            var pos = that.$newElement.offset(),
961                $container = $(that.options.container),
962                containerPos;
963
964            if (that.options.container && !$container.is('body')) {
965              containerPos = $container.offset();
966              containerPos.top += parseInt($container.css('borderTopWidth'));
967              containerPos.left += parseInt($container.css('borderLeftWidth'));
968            } else {
969              containerPos = { top: 0, left: 0 };
970            }
971
972            var winPad = that.options.windowPadding;
973            selectOffsetTop = pos.top - containerPos.top - $window.scrollTop();
974            selectOffsetBot = $window.height() - selectOffsetTop - selectHeight - containerPos.top - winPad[2];
975            selectOffsetLeft = pos.left - containerPos.left - $window.scrollLeft();
976            selectOffsetRight = $window.width() - selectOffsetLeft - selectWidth - containerPos.left - winPad[1];
977            selectOffsetTop -= winPad[0];
978            selectOffsetLeft -= winPad[3];
979          };
980
981      getPos();
982
983      if (this.options.size === 'auto') {
984        var getSize = function () {
985          var minHeight,
986              hasClass = function (className, include) {
987                return function (element) {
988                    if (include) {
989                        return (element.classList ? element.classList.contains(className) : $(element).hasClass(className));
990                    } else {
991                        return !(element.classList ? element.classList.contains(className) : $(element).hasClass(className));
992                    }
993                };
994              },
995              lis = that.$menuInner[0].getElementsByTagName('li'),
996              lisVisible = Array.prototype.filter ? Array.prototype.filter.call(lis, hasClass('hidden', false)) : that.$lis.not('.hidden'),
997              optGroup = Array.prototype.filter ? Array.prototype.filter.call(lisVisible, hasClass('dropdown-header', true)) : lisVisible.filter('.dropdown-header');
998
999          getPos();
1000          menuHeight = selectOffsetBot - menuExtras.vert;
1001          menuWidth = selectOffsetRight - menuExtras.horiz;
1002
1003          if (that.options.container) {
1004            if (!$menu.data('height')) $menu.data('height', $menu.height());
1005            getHeight = $menu.data('height');
1006
1007            if (!$menu.data('width')) $menu.data('width', $menu.width());
1008            getWidth = $menu.data('width');
1009          } else {
1010            getHeight = $menu.height();
1011            getWidth = $menu.width();
1012          }
1013
1014          if (that.options.dropupAuto) {
1015            that.$newElement.toggleClass('dropup', selectOffsetTop > selectOffsetBot && (menuHeight - menuExtras.vert) < getHeight);
1016          }
1017
1018          if (that.$newElement.hasClass('dropup')) {
1019            menuHeight = selectOffsetTop - menuExtras.vert;
1020          }
1021
1022          if (that.options.dropdownAlignRight === 'auto') {
1023            $menu.toggleClass('dropdown-menu-right', selectOffsetLeft > selectOffsetRight && (menuWidth - menuExtras.horiz) < (getWidth - selectWidth));
1024          }
1025
1026          if ((lisVisible.length + optGroup.length) > 3) {
1027            minHeight = liHeight * 3 + menuExtras.vert - 2;
1028          } else {
1029            minHeight = 0;
1030          }
1031
1032          $menu.css({
1033            'max-height': menuHeight + 'px',
1034            'overflow': 'hidden',
1035            'min-height': minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight + 'px'
1036          });
1037          $menuInner.css({
1038            'max-height': menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert + 'px',
1039            'overflow-y': 'auto',
1040            'min-height': Math.max(minHeight - menuPadding.vert, 0) + 'px'
1041          });
1042        };
1043        getSize();
1044        this.$searchbox.off('input.getSize propertychange.getSize').on('input.getSize propertychange.getSize', getSize);
1045        $window.off('resize.getSize scroll.getSize').on('resize.getSize scroll.getSize', getSize);
1046      } else if (this.options.size && this.options.size != 'auto' && this.$lis.not(notDisabled).length > this.options.size) {
1047        var optIndex = this.$lis.not('.divider').not(notDisabled).children().slice(0, this.options.size).last().parent().index(),
1048            divLength = this.$lis.slice(0, optIndex + 1).filter('.divider').length;
1049        menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert;
1050
1051        if (that.options.container) {
1052          if (!$menu.data('height')) $menu.data('height', $menu.height());
1053          getHeight = $menu.data('height');
1054        } else {
1055          getHeight = $menu.height();
1056        }
1057
1058        if (that.options.dropupAuto) {
1059          //noinspection JSUnusedAssignment
1060          this.$newElement.toggleClass('dropup', selectOffsetTop > selectOffsetBot && (menuHeight - menuExtras.vert) < getHeight);
1061        }
1062        $menu.css({
1063          'max-height': menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight + 'px',
1064          'overflow': 'hidden',
1065          'min-height': ''
1066        });
1067        $menuInner.css({
1068          'max-height': menuHeight - menuPadding.vert + 'px',
1069          'overflow-y': 'auto',
1070          'min-height': ''
1071        });
1072      }
1073    },
1074
1075    setWidth: function () {
1076      if (this.options.width === 'auto') {
1077        this.$menu.css('min-width', '0');
1078
1079        // Get correct width if element is hidden
1080        var $selectClone = this.$menu.parent().clone().appendTo('body'),
1081            $selectClone2 = this.options.container ? this.$newElement.clone().appendTo('body') : $selectClone,
1082            ulWidth = $selectClone.children('.dropdown-menu').outerWidth(),
1083            btnWidth = $selectClone2.css('width', 'auto').children('button').outerWidth();
1084
1085        $selectClone.remove();
1086        $selectClone2.remove();
1087
1088        // Set width to whatever's larger, button title or longest option
1089        this.$newElement.css('width', Math.max(ulWidth, btnWidth) + 'px');
1090      } else if (this.options.width === 'fit') {
1091        // Remove inline min-width so width can be changed from 'auto'
1092        this.$menu.css('min-width', '');
1093        this.$newElement.css('width', '').addClass('fit-width');
1094      } else if (this.options.width) {
1095        // Remove inline min-width so width can be changed from 'auto'
1096        this.$menu.css('min-width', '');
1097        this.$newElement.css('width', this.options.width);
1098      } else {
1099        // Remove inline min-width/width so width can be changed
1100        this.$menu.css('min-width', '');
1101        this.$newElement.css('width', '');
1102      }
1103      // Remove fit-width class if width is changed programmatically
1104      if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {
1105        this.$newElement.removeClass('fit-width');
1106      }
1107    },
1108
1109    selectPosition: function () {
1110      this.$bsContainer = $('<div class="bs-container" />');
1111
1112      var that = this,
1113          $container = $(this.options.container),
1114          pos,
1115          containerPos,
1116          actualHeight,
1117          getPlacement = function ($element) {
1118            that.$bsContainer.addClass($element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass('dropup', $element.hasClass('dropup'));
1119            pos = $element.offset();
1120
1121            if (!$container.is('body')) {
1122              containerPos = $container.offset();
1123              containerPos.top += parseInt($container.css('borderTopWidth')) - $container.scrollTop();
1124              containerPos.left += parseInt($container.css('borderLeftWidth')) - $container.scrollLeft();
1125            } else {
1126              containerPos = { top: 0, left: 0 };
1127            }
1128
1129            actualHeight = $element.hasClass('dropup') ? 0 : $element[0].offsetHeight;
1130
1131            that.$bsContainer.css({
1132              'top': pos.top - containerPos.top + actualHeight,
1133              'left': pos.left - containerPos.left,
1134              'width': $element[0].offsetWidth
1135            });
1136          };
1137
1138      this.$button.on('click', function () {
1139        var $this = $(this);
1140
1141        if (that.isDisabled()) {
1142          return;
1143        }
1144
1145        getPlacement(that.$newElement);
1146
1147        that.$bsContainer
1148          .appendTo(that.options.container)
1149          .toggleClass('open', !$this.hasClass('open'))
1150          .append(that.$menu);
1151      });
1152
1153      $(window).on('resize scroll', function () {
1154        getPlacement(that.$newElement);
1155      });
1156
1157      this.$element.on('hide.bs.select', function () {
1158        that.$menu.data('height', that.$menu.height());
1159        that.$bsContainer.detach();
1160      });
1161    },
1162
1163    /**
1164     * @param {number} index - the index of the option that is being changed
1165     * @param {boolean} selected - true if the option is being selected, false if being deselected
1166     * @param {JQuery} $lis - the 'li' element that is being modified
1167     */
1168    setSelected: function (index, selected, $lis) {
1169      if (!$lis) {
1170        this.togglePlaceholder(); // check if setSelected is being called by changing the value of the select
1171        $lis = this.findLis().eq(this.liObj[index]);
1172      }
1173
1174      $lis.toggleClass('selected', selected).find('a').attr('aria-selected', selected);
1175    },
1176
1177    /**
1178     * @param {number} index - the index of the option that is being disabled
1179     * @param {boolean} disabled - true if the option is being disabled, false if being enabled
1180     * @param {JQuery} $lis - the 'li' element that is being modified
1181     */
1182    setDisabled: function (index, disabled, $lis) {
1183      if (!$lis) {
1184        $lis = this.findLis().eq(this.liObj[index]);
1185      }
1186
1187      if (disabled) {
1188        $lis.addClass('disabled').children('a').attr('href', '#').attr('tabindex', -1).attr('aria-disabled', true);
1189      } else {
1190        $lis.removeClass('disabled').children('a').removeAttr('href').attr('tabindex', 0).attr('aria-disabled', false);
1191      }
1192    },
1193
1194    isDisabled: function () {
1195      return this.$element[0].disabled;
1196    },
1197
1198    checkDisabled: function () {
1199      var that = this;
1200
1201      if (this.isDisabled()) {
1202        this.$newElement.addClass('disabled');
1203        this.$button.addClass('disabled').attr('tabindex', -1).attr('aria-disabled', true);
1204      } else {
1205        if (this.$button.hasClass('disabled')) {
1206          this.$newElement.removeClass('disabled');
1207          this.$button.removeClass('disabled').attr('aria-disabled', false);
1208        }
1209
1210        if (this.$button.attr('tabindex') == -1 && !this.$element.data('tabindex')) {
1211          this.$button.removeAttr('tabindex');
1212        }
1213      }
1214
1215      this.$button.click(function () {
1216        return !that.isDisabled();
1217      });
1218    },
1219
1220    togglePlaceholder: function () {
1221      var value = this.$element.val();
1222      this.$button.toggleClass('bs-placeholder', value === null || value === '' || (value.constructor === Array && value.length === 0));
1223    },
1224
1225    tabIndex: function () {
1226      if (this.$element.data('tabindex') !== this.$element.attr('tabindex') &&
1227        (this.$element.attr('tabindex') !== -98 && this.$element.attr('tabindex') !== '-98')) {
1228        this.$element.data('tabindex', this.$element.attr('tabindex'));
1229        this.$button.attr('tabindex', this.$element.data('tabindex'));
1230      }
1231
1232      this.$element.attr('tabindex', -98);
1233    },
1234
1235    clickListener: function () {
1236      var that = this,
1237          $document = $(document);
1238
1239      $document.data('spaceSelect', false);
1240
1241      this.$button.on('keyup', function (e) {
1242        if (/(32)/.test(e.keyCode.toString(10)) && $document.data('spaceSelect')) {
1243            e.preventDefault();
1244            $document.data('spaceSelect', false);
1245        }
1246      });
1247
1248      this.$button.on('click', function () {
1249        that.setSize();
1250      });
1251
1252      this.$element.on('shown.bs.select', function () {
1253        if (!that.options.liveSearch && !that.multiple) {
1254          that.$menuInner.find('.selected a').focus();
1255        } else if (!that.multiple) {
1256          var selectedIndex = that.liObj[that.$element[0].selectedIndex];
1257
1258          if (typeof selectedIndex !== 'number' || that.options.size === false) return;
1259
1260          // scroll to selected option
1261          var offset = that.$lis.eq(selectedIndex)[0].offsetTop - that.$menuInner[0].offsetTop;
1262          offset = offset - that.$menuInner[0].offsetHeight/2 + that.sizeInfo.liHeight/2;
1263          that.$menuInner[0].scrollTop = offset;
1264        }
1265      });
1266
1267      this.$menuInner.on('click', 'li a', function (e) {
1268        var $this = $(this),
1269            clickedIndex = $this.parent().data('originalIndex'),
1270            prevValue = that.$element.val(),
1271            prevIndex = that.$element.prop('selectedIndex'),
1272            triggerChange = true;
1273
1274        // Don't close on multi choice menu
1275        if (that.multiple && that.options.maxOptions !== 1) {
1276          e.stopPropagation();
1277        }
1278
1279        e.preventDefault();
1280
1281        //Don't run if we have been disabled
1282        if (!that.isDisabled() && !$this.parent().hasClass('disabled')) {
1283          var $options = that.$element.find('option'),
1284              $option = $options.eq(clickedIndex),
1285              state = $option.prop('selected'),
1286              $optgroup = $option.parent('optgroup'),
1287              maxOptions = that.options.maxOptions,
1288              maxOptionsGrp = $optgroup.data('maxOptions') || false;
1289
1290          if (!that.multiple) { // Deselect all others if not multi select box
1291            $options.prop('selected', false);
1292            $option.prop('selected', true);
1293            that.$menuInner.find('.selected').removeClass('selected').find('a').attr('aria-selected', false);
1294            that.setSelected(clickedIndex, true);
1295          } else { // Toggle the one we have chosen if we are multi select.
1296            $option.prop('selected', !state);
1297            that.setSelected(clickedIndex, !state);
1298            $this.blur();
1299
1300            if (maxOptions !== false || maxOptionsGrp !== false) {
1301              var maxReached = maxOptions < $options.filter(':selected').length,
1302                  maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length;
1303
1304              if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {
1305                if (maxOptions && maxOptions == 1) {
1306                  $options.prop('selected', false);
1307                  $option.prop('selected', true);
1308                  that.$menuInner.find('.selected').removeClass('selected');
1309                  that.setSelected(clickedIndex, true);
1310                } else if (maxOptionsGrp && maxOptionsGrp == 1) {
1311                  $optgroup.find('option:selected').prop('selected', false);
1312                  $option.prop('selected', true);
1313                  var optgroupID = $this.parent().data('optgroup');
1314                  that.$menuInner.find('[data-optgroup="' + optgroupID + '"]').removeClass('selected');
1315                  that.setSelected(clickedIndex, true);
1316                } else {
1317                  var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText,
1318                      maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText,
1319                      maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),
1320                      maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),
1321                      $notify = $('<div class="notify"></div>');
1322                  // If {var} is set in array, replace it
1323                  /** @deprecated */
1324                  if (maxOptionsArr[2]) {
1325                    maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);
1326                    maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);
1327                  }
1328
1329                  $option.prop('selected', false);
1330
1331                  that.$menu.append($notify);
1332
1333                  if (maxOptions && maxReached) {
1334                    $notify.append($('<div>' + maxTxt + '</div>'));
1335                    triggerChange = false;
1336                    that.$element.trigger('maxReached.bs.select');
1337                  }
1338
1339                  if (maxOptionsGrp && maxReachedGrp) {
1340                    $notify.append($('<div>' + maxTxtGrp + '</div>'));
1341                    triggerChange = false;
1342                    that.$element.trigger('maxReachedGrp.bs.select');
1343                  }
1344
1345                  setTimeout(function () {
1346                    that.setSelected(clickedIndex, false);
1347                  }, 10);
1348
1349                  $notify.delay(750).fadeOut(300, function () {
1350                    $(this).remove();
1351                  });
1352                }
1353              }
1354            }
1355          }
1356
1357          if (!that.multiple || (that.multiple && that.options.maxOptions === 1)) {
1358            that.$button.focus();
1359          } else if (that.options.liveSearch) {
1360            that.$searchbox.focus();
1361          }
1362
1363          // Trigger select 'change'
1364          if (triggerChange) {
1365            if ((prevValue != that.$element.val() && that.multiple) || (prevIndex != that.$element.prop('selectedIndex') && !that.multiple)) {
1366              // $option.prop('selected') is current option state (selected/unselected). state is previous option state.
1367              changed_arguments = [clickedIndex, $option.prop('selected'), state];
1368              that.$element
1369                .triggerNative('change');
1370            }
1371          }
1372        }
1373      });
1374
1375      this.$menu.on('click', 'li.disabled a, .popover-title, .popover-title :not(.close)', function (e) {
1376        if (e.currentTarget == this) {
1377          e.preventDefault();
1378          e.stopPropagation();
1379          if (that.options.liveSearch && !$(e.target).hasClass('close')) {
1380            that.$searchbox.focus();
1381          } else {
1382            that.$button.focus();
1383          }
1384        }
1385      });
1386
1387      this.$menuInner.on('click', '.divider, .dropdown-header', function (e) {
1388        e.preventDefault();
1389        e.stopPropagation();
1390        if (that.options.liveSearch) {
1391          that.$searchbox.focus();
1392        } else {
1393          that.$button.focus();
1394        }
1395      });
1396
1397      this.$menu.on('click', '.popover-title .close', function () {
1398        that.$button.click();
1399      });
1400
1401      this.$searchbox.on('click', function (e) {
1402        e.stopPropagation();
1403      });
1404
1405      this.$menu.on('click', '.actions-btn', function (e) {
1406        if (that.options.liveSearch) {
1407          that.$searchbox.focus();
1408        } else {
1409          that.$button.focus();
1410        }
1411
1412        e.preventDefault();
1413        e.stopPropagation();
1414
1415        if ($(this).hasClass('bs-select-all')) {
1416          that.selectAll();
1417        } else {
1418          that.deselectAll();
1419        }
1420      });
1421
1422      this.$element.change(function () {
1423        that.render(false);
1424        that.$element.trigger('changed.bs.select', changed_arguments);
1425        changed_arguments = null;
1426      });
1427    },
1428
1429    liveSearchListener: function () {
1430      var that = this,
1431          $no_results = $('<li class="no-results"></li>');
1432
1433      this.$button.on('click.dropdown.data-api', function () {
1434        that.$menuInner.find('.active').removeClass('active');
1435        if (!!that.$searchbox.val()) {
1436          that.$searchbox.val('');
1437          that.$lis.not('.is-hidden').removeClass('hidden');
1438          if (!!$no_results.parent().length) $no_results.remove();
1439        }
1440        if (!that.multiple) that.$menuInner.find('.selected').addClass('active');
1441        setTimeout(function () {
1442          that.$searchbox.focus();
1443        }, 10);
1444      });
1445
1446      this.$searchbox.on('click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api', function (e) {
1447        e.stopPropagation();
1448      });
1449
1450      this.$searchbox.on('input propertychange', function () {
1451        that.$lis.not('.is-hidden').removeClass('hidden');
1452        that.$lis.filter('.active').removeClass('active');
1453        $no_results.remove();
1454
1455        if (that.$searchbox.val()) {
1456          var $searchBase = that.$lis.not('.is-hidden, .divider, .dropdown-header'),
1457              $hideItems;
1458          if (that.options.liveSearchNormalize) {
1459            $hideItems = $searchBase.find('a').not(':a' + that._searchStyle() + '("' + normalizeToBase(that.$searchbox.val()) + '")');
1460          } else {
1461            $hideItems = $searchBase.find('a').not(':' + that._searchStyle() + '("' + that.$searchbox.val() + '")');
1462          }
1463
1464          if ($hideItems.length === $searchBase.length) {
1465            $no_results.html(that.options.noneResultsText.replace('{0}', '"' + htmlEscape(that.$searchbox.val()) + '"'));
1466            that.$menuInner.append($no_results);
1467            that.$lis.addClass('hidden');
1468          } else {
1469            $hideItems.parent().addClass('hidden');
1470
1471            var $lisVisible = that.$lis.not('.hidden'),
1472                $foundDiv;
1473
1474            // hide divider if first or last visible, or if followed by another divider
1475            $lisVisible.each(function (index) {
1476              var $this = $(this);
1477
1478              if ($this.hasClass('divider')) {
1479                if ($foundDiv === undefined) {
1480                  $this.addClass('hidden');
1481                } else {
1482                  if ($foundDiv) $foundDiv.addClass('hidden');
1483                  $foundDiv = $this;
1484                }
1485              } else if ($this.hasClass('dropdown-header') && $lisVisible.eq(index + 1).data('optgroup') !== $this.data('optgroup')) {
1486                $this.addClass('hidden');
1487              } else {
1488                $foundDiv = null;
1489              }
1490            });
1491            if ($foundDiv) $foundDiv.addClass('hidden');
1492
1493            $searchBase.not('.hidden').first().addClass('active');
1494          }
1495        }
1496      });
1497    },
1498
1499    _searchStyle: function () {
1500      var styles = {
1501        begins: 'ibegins',
1502        startsWith: 'ibegins'
1503      };
1504
1505      return styles[this.options.liveSearchStyle] || 'icontains';
1506    },
1507
1508    val: function (value) {
1509      if (typeof value !== 'undefined') {
1510        this.$element.val(value);
1511        this.render();
1512
1513        return this.$element;
1514      } else {
1515        return this.$element.val();
1516      }
1517    },
1518
1519    changeAll: function (status) {
1520      if (!this.multiple) return;
1521      if (typeof status === 'undefined') status = true;
1522
1523      this.findLis();
1524
1525      var $options = this.$element.find('option'),
1526          $lisVisible = this.$lis.not('.divider, .dropdown-header, .disabled, .hidden'),
1527          lisVisLen = $lisVisible.length,
1528          selectedOptions = [];
1529
1530      if (status) {
1531        if ($lisVisible.filter('.selected').length === $lisVisible.length) return;
1532      } else {
1533        if ($lisVisible.filter('.selected').length === 0) return;
1534      }
1535
1536      $lisVisible.toggleClass('selected', status);
1537
1538      for (var i = 0; i < lisVisLen; i++) {
1539        var origIndex = $lisVisible[i].getAttribute('data-original-index');
1540        selectedOptions[selectedOptions.length] = $options.eq(origIndex)[0];
1541      }
1542
1543      $(selectedOptions).prop('selected', status);
1544
1545      this.render(false);
1546
1547      this.togglePlaceholder();
1548
1549      this.$element
1550        .triggerNative('change');
1551    },
1552
1553    selectAll: function () {
1554      return this.changeAll(true);
1555    },
1556
1557    deselectAll: function () {
1558      return this.changeAll(false);
1559    },
1560
1561    toggle: function (e) {
1562      e = e || window.event;
1563
1564      if (e) e.stopPropagation();
1565
1566      this.$button.trigger('click');
1567    },
1568
1569    keydown: function (e) {
1570      var $this = $(this),
1571          $parent = $this.is('input') ? $this.parent().parent() : $this.parent(),
1572          $items,
1573          that = $parent.data('this'),
1574          index,
1575          next,
1576          first,
1577          last,
1578          prev,
1579          nextPrev,
1580          prevIndex,
1581          isActive,
1582          selector = ':not(.disabled, .hidden, .dropdown-header, .divider)',
1583          keyCodeMap = {
1584            32: ' ',
1585            48: '0',
1586            49: '1',
1587            50: '2',
1588            51: '3',
1589            52: '4',
1590            53: '5',
1591            54: '6',
1592            55: '7',
1593            56: '8',
1594            57: '9',
1595            59: ';',
1596            65: 'a',
1597            66: 'b',
1598            67: 'c',
1599            68: 'd',
1600            69: 'e',
1601            70: 'f',
1602            71: 'g',
1603            72: 'h',
1604            73: 'i',
1605            74: 'j',
1606            75: 'k',
1607            76: 'l',
1608            77: 'm',
1609            78: 'n',
1610            79: 'o',
1611            80: 'p',
1612            81: 'q',
1613            82: 'r',
1614            83: 's',
1615            84: 't',
1616            85: 'u',
1617            86: 'v',
1618            87: 'w',
1619            88: 'x',
1620            89: 'y',
1621            90: 'z',
1622            96: '0',
1623            97: '1',
1624            98: '2',
1625            99: '3',
1626            100: '4',
1627            101: '5',
1628            102: '6',
1629            103: '7',
1630            104: '8',
1631            105: '9'
1632          };
1633
1634      if (that.options.liveSearch) $parent = $this.parent().parent();
1635
1636      if (that.options.container) $parent = that.$menu;
1637
1638      $items = $('[role="listbox"] li', $parent);
1639
1640      isActive = that.$newElement.hasClass('open');
1641
1642      if (!isActive && (e.keyCode >= 48 && e.keyCode <= 57 || e.keyCode >= 96 && e.keyCode <= 105 || e.keyCode >= 65 && e.keyCode <= 90)) {
1643        if (!that.options.container) {
1644          that.setSize();
1645          that.$menu.parent().addClass('open');
1646          isActive = true;
1647        } else {
1648          that.$button.trigger('click');
1649        }
1650        that.$searchbox.focus();
1651        return;
1652      }
1653
1654      if (that.options.liveSearch) {
1655        if (/(^9$|27)/.test(e.keyCode.toString(10)) && isActive) {
1656          e.preventDefault();
1657          e.stopPropagation();
1658          that.$menuInner.click();
1659          that.$button.focus();
1660        }
1661        // $items contains li elements when liveSearch is enabled
1662        $items = $('[role="listbox"] li' + selector, $parent);
1663        if (!$this.val() && !/(38|40)/.test(e.keyCode.toString(10))) {
1664          if ($items.filter('.active').length === 0) {
1665            $items = that.$menuInner.find('li');
1666            if (that.options.liveSearchNormalize) {
1667              $items = $items.filter(':a' + that._searchStyle() + '(' + normalizeToBase(keyCodeMap[e.keyCode]) + ')');
1668            } else {
1669              $items = $items.filter(':' + that._searchStyle() + '(' + keyCodeMap[e.keyCode] + ')');
1670            }
1671          }
1672        }
1673      }
1674
1675      if (!$items.length) return;
1676
1677      if (/(38|40)/.test(e.keyCode.toString(10))) {
1678        index = $items.index($items.find('a').filter(':focus').parent());
1679        first = $items.filter(selector).first().index();
1680        last = $items.filter(selector).last().index();
1681        next = $items.eq(index).nextAll(selector).eq(0).index();
1682        prev = $items.eq(index).prevAll(selector).eq(0).index();
1683        nextPrev = $items.eq(next).prevAll(selector).eq(0).index();
1684
1685        if (that.options.liveSearch) {
1686          $items.each(function (i) {
1687            if (!$(this).hasClass('disabled')) {
1688              $(this).data('index', i);
1689            }
1690          });
1691          index = $items.index($items.filter('.active'));
1692          first = $items.first().data('index');
1693          last = $items.last().data('index');
1694          next = $items.eq(index).nextAll().eq(0).data('index');
1695          prev = $items.eq(index).prevAll().eq(0).data('index');
1696          nextPrev = $items.eq(next).prevAll().eq(0).data('index');
1697        }
1698
1699        prevIndex = $this.data('prevIndex');
1700
1701        if (e.keyCode == 38) {
1702          if (that.options.liveSearch) index--;
1703          if (index != nextPrev && index > prev) index = prev;
1704          if (index < first) index = first;
1705          if (index == prevIndex) index = last;
1706        } else if (e.keyCode == 40) {
1707          if (that.options.liveSearch) index++;
1708          if (index == -1) index = 0;
1709          if (index != nextPrev && index < next) index = next;
1710          if (index > last) index = last;
1711          if (index == prevIndex) index = first;
1712        }
1713
1714        $this.data('prevIndex', index);
1715
1716        if (!that.options.liveSearch) {
1717          $items.eq(index).children('a').focus();
1718        } else {
1719          e.preventDefault();
1720          if (!$this.hasClass('dropdown-toggle')) {
1721            $items.removeClass('active').eq(index).addClass('active').children('a').focus();
1722            $this.focus();
1723          }
1724        }
1725
1726      } else if (!$this.is('input')) {
1727        var keyIndex = [],
1728            count,
1729            prevKey;
1730
1731        $items.each(function () {
1732          if (!$(this).hasClass('disabled')) {
1733            if ($.trim($(this).children('a').text().toLowerCase()).substring(0, 1) == keyCodeMap[e.keyCode]) {
1734              keyIndex.push($(this).index());
1735            }
1736          }
1737        });
1738
1739        count = $(document).data('keycount');
1740        count++;
1741        $(document).data('keycount', count);
1742
1743        prevKey = $.trim($(':focus').text().toLowerCase()).substring(0, 1);
1744
1745        if (prevKey != keyCodeMap[e.keyCode]) {
1746          count = 1;
1747          $(document).data('keycount', count);
1748        } else if (count >= keyIndex.length) {
1749          $(document).data('keycount', 0);
1750          if (count > keyIndex.length) count = 1;
1751        }
1752
1753        $items.eq(keyIndex[count - 1]).children('a').focus();
1754      }
1755
1756      // Select focused option if "Enter", "Spacebar" or "Tab" (when selectOnTab is true) are pressed inside the menu.
1757      if ((/(13|32)/.test(e.keyCode.toString(10)) || (/(^9$)/.test(e.keyCode.toString(10)) && that.options.selectOnTab)) && isActive) {
1758        if (!/(32)/.test(e.keyCode.toString(10))) e.preventDefault();
1759        if (!that.options.liveSearch) {
1760          var elem = $(':focus');
1761          elem.click();
1762          // Bring back focus for multiselects
1763          elem.focus();
1764          // Prevent screen from scrolling if the user hit the spacebar
1765          e.preventDefault();
1766          // Fixes spacebar selection of dropdown items in FF & IE
1767          $(document).data('spaceSelect', true);
1768        } else if (!/(32)/.test(e.keyCode.toString(10))) {
1769          that.$menuInner.find('.active a').click();
1770          $this.focus();
1771        }
1772        $(document).data('keycount', 0);
1773      }
1774
1775      if ((/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && (that.multiple || that.options.liveSearch)) || (/(27)/.test(e.keyCode.toString(10)) && !isActive)) {
1776        that.$menu.parent().removeClass('open');
1777        if (that.options.container) that.$newElement.removeClass('open');
1778        that.$button.focus();
1779      }
1780    },
1781
1782    mobile: function () {
1783      this.$element.addClass('mobile-device');
1784    },
1785
1786    refresh: function () {
1787      this.$lis = null;
1788      this.liObj = {};
1789      this.reloadLi();
1790      this.render();
1791      this.checkDisabled();
1792      this.liHeight(true);
1793      this.setStyle();
1794      this.setWidth();
1795      if (this.$lis) this.$searchbox.trigger('propertychange');
1796
1797      this.$element.trigger('refreshed.bs.select');
1798    },
1799
1800    hide: function () {
1801      this.$newElement.hide();
1802    },
1803
1804    show: function () {
1805      this.$newElement.show();
1806    },
1807
1808    remove: function () {
1809      this.$newElement.remove();
1810      this.$element.remove();
1811    },
1812
1813    destroy: function () {
1814      this.$newElement.before(this.$element).remove();
1815
1816      if (this.$bsContainer) {
1817        this.$bsContainer.remove();
1818      } else {
1819        this.$menu.remove();
1820      }
1821
1822      this.$element
1823        .off('.bs.select')
1824        .removeData('selectpicker')
1825        .removeClass('bs-select-hidden selectpicker');
1826    }
1827  };
1828
1829  // SELECTPICKER PLUGIN DEFINITION
1830  // ==============================
1831  function Plugin(option) {
1832    // get the args of the outer function..
1833    var args = arguments;
1834    // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them
1835    // to get lost/corrupted in android 2.3 and IE9 #715 #775
1836    var _option = option;
1837
1838    [].shift.apply(args);
1839
1840    var value;
1841    var chain = this.each(function () {
1842      var $this = $(this);
1843      if ($this.is('select')) {
1844        var data = $this.data('selectpicker'),
1845            options = typeof _option == 'object' && _option;
1846
1847        if (!data) {
1848          var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, $this.data(), options);
1849          config.template = $.extend({}, Selectpicker.DEFAULTS.template, ($.fn.selectpicker.defaults ? $.fn.selectpicker.defaults.template : {}), $this.data().template, options.template);
1850          $this.data('selectpicker', (data = new Selectpicker(this, config)));
1851        } else if (options) {
1852          for (var i in options) {
1853            if (options.hasOwnProperty(i)) {
1854              data.options[i] = options[i];
1855            }
1856          }
1857        }
1858
1859        if (typeof _option == 'string') {
1860          if (data[_option] instanceof Function) {
1861            value = data[_option].apply(data, args);
1862          } else {
1863            value = data.options[_option];
1864          }
1865        }
1866      }
1867    });
1868
1869    if (typeof value !== 'undefined') {
1870      //noinspection JSUnusedAssignment
1871      return value;
1872    } else {
1873      return chain;
1874    }
1875  }
1876
1877  var old = $.fn.selectpicker;
1878  $.fn.selectpicker = Plugin;
1879  $.fn.selectpicker.Constructor = Selectpicker;
1880
1881  // SELECTPICKER NO CONFLICT
1882  // ========================
1883  $.fn.selectpicker.noConflict = function () {
1884    $.fn.selectpicker = old;
1885    return this;
1886  };
1887
1888  $(document)
1889      .data('keycount', 0)
1890      .on('keydown.bs.select', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input', Selectpicker.prototype.keydown)
1891      .on('focusin.modal', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input', function (e) {
1892        e.stopPropagation();
1893      });
1894
1895  // SELECTPICKER DATA-API
1896  // =====================
1897  $(window).on('load.bs.select.data-api', function () {
1898    $('.selectpicker').each(function () {
1899      var $selectpicker = $(this);
1900      Plugin.call($selectpicker, $selectpicker.data());
1901    })
1902  });
1903})(jQuery);
1904
1905
1906}));

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.