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