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