vendor: 38,064 bytes, lines 1-884
1/** 2 * Display a nice easy to use multiselect list 3 * @Version: 2.4.17 4 * @Author: Patrick Springstubbe 5 * @Contact: @JediNobleclem 6 * @Website: springstubbe.us 7 * @Source: https://github.com/nobleclem/jQuery-MultiSelect 8 * 9 * Usage: 10 * $('select[multiple]').multiselect(); 11 * $('select[multiple]').multiselect({ texts: { placeholder: 'Select options' } }); 12 * $('select[multiple]').multiselect('reload'); 13 * $('select[multiple]').multiselect( 'loadOptions', [{ 14 * name : 'Option Name 1', 15 * value : 'option-value-1', 16 * checked: false, 17 * attributes : { 18 * custom1: 'value1', 19 * custom2: 'value2' 20 * } 21 * },{ 22 * name : 'Option Name 2', 23 * value : 'option-value-2', 24 * checked: false, 25 * attributes : { 26 * custom1: 'value1', 27 * custom2: 'value2' 28 * } 29 * }]); 30 * 31 **/ 32(function($){ 33 34 var __ = tclist__; 35 36 var defaults = { 37 columns: 1, // how many columns should be use to show options 38 search : false, // include option search box 39 40 // search filter options 41 searchOptions : { 42 delay : 250, // time (in ms) between keystrokes until search happens 43 showOptGroups: false, // show option group titles if no options remaining 44 searchText : true, // search within the text 45 searchValue : false, // search within the value 46 onSearch : function( element ){} // fires on keyup before search on options happens 47 }, 48 49 // plugin texts 50 texts: { 51 placeholder : __.tclist_select_options, // text to use in dummy input 52 search : __.tclist_search, // search input placeholder text 53 selectedOptions: __.tclist_selected, // selected suffix text 54 selectAll : __.tclist_select_all, // select all text 55 unselectAll : __.tclist_unselect_all, // unselect all text 56 noneSelected : __.tclist_none_selected // None selected text 57 }, 58 59 // general options 60 selectAll : false, // add select all option 61 selectGroup : false, // select entire optgroup 62 minHeight : 200, // minimum height of option overlay 63 maxHeight : null, // maximum height of option overlay 64 maxWidth : null, // maximum width of option overlay (or selector) 65 maxPlaceholderWidth: null, // maximum width of placeholder button 66 maxPlaceholderOpts : 10, // maximum number of placeholder options to show until "# selected" shown instead 67 showCheckbox : true, // display the checkbox to the user 68 checkboxAutoFit : false, // auto calc checkbox padding 69 optionAttributes : [], // attributes to copy to the checkbox from the option element 70 71 // Callbacks 72 onLoad : function( element ){}, // fires at end of list initialization 73 onOptionClick : function( element, option ){}, // fires when an option is clicked 74 onControlClose: function( element ){}, // fires when the options list is closed 75 onSelectAll : function( element, selected ){}, // fires when (un)select all is clicked 76 onPlaceholder : function( element, placeholder, selectedOpts ){}, // fires when the placeholder txt is updated 77 }; 78 79 var msCounter = 1; // counter for each select list 80 var msOptCounter = 1; // counter for each option on page 81 82 // FOR LEGACY BROWSERS (talking to you IE8) 83 if( typeof Array.prototype.map !== 'function' ) { 84 Array.prototype.map = function( callback, thisArg ) { 85 if( typeof thisArg === 'undefined' ) { 86 thisArg = this; 87 } 88 89 return $.isArray( thisArg ) ? $.map( thisArg, callback ) : []; 90 }; 91 } 92 if( typeof String.prototype.trim !== 'function' ) { 93 String.prototype.trim = function() { 94 return this.replace(/^\s+|\s+$/g, ''); 95 }; 96 } 97 98 function MultiSelect( element, options ) 99 { 100 this.element = element; 101 this.options = $.extend( true, {}, defaults, options ); 102 this.updateSelectAll = true; 103 this.updatePlaceholder = true; 104 this.listNumber = msCounter; 105 106 msCounter = msCounter + 1; // increment counter 107 108 /* Make sure its a multiselect list */ 109 if( !$(this.element).attr('multiple') ) { 110 throw new Error( '[jQuery-MultiSelect] Select list must be a multiselect list in order to use this plugin' ); 111 } 112 113 /* Options validation checks */ 114 if( this.options.search ){ 115 if( !this.options.searchOptions.searchText && !this.options.searchOptions.searchValue ){ 116 throw new Error( '[jQuery-MultiSelect] Either searchText or searchValue should be true.' ); 117 } 118 } 119 120 /** BACKWARDS COMPATIBILITY **/ 121 if( 'placeholder' in this.options ) { 122 this.options.texts.placeholder = this.options.placeholder; 123 delete this.options.placeholder; 124 } 125 if( 'default' in this.options.searchOptions ) { 126 this.options.texts.search = this.options.searchOptions['default']; 127 delete this.options.searchOptions['default']; 128 } 129 /** END BACKWARDS COMPATIBILITY **/ 130 131 // load this instance 132 this.load(); 133 } 134 135 MultiSelect.prototype = { 136 /* LOAD CUSTOM MULTISELECT DOM/ACTIONS */ 137 load: function() { 138 var instance = this; 139 140 // make sure this is a select list and not loaded 141 if( (instance.element.nodeName != 'SELECT') || $(instance.element).hasClass('jqmsLoaded') ) { 142 return true; 143 } 144 145 // sanity check so we don't double load on a select element 146 $(instance.element).addClass('jqmsLoaded ms-list-'+ instance.listNumber ).data( 'plugin_multiselect-instance', instance ); 147 148 // add option container 149 $(instance.element).after('<div id="ms-list-'+ instance.listNumber +'" class="ms-options-wrap"><button type="button"><span>None Selected</span></button><div class="ms-options"><ul></ul></div></div>'); 150 151 var placeholder = $(instance.element).siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> button:first-child'); 152 var optionsWrap = $(instance.element).siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> .ms-options'); 153 var optionsList = optionsWrap.find('> ul'); 154 155 // don't show checkbox (add class for css to hide checkboxes) 156 if( !instance.options.showCheckbox ) { 157 optionsWrap.addClass('hide-checkbox'); 158 } 159 else if( instance.options.checkboxAutoFit ) { 160 optionsWrap.addClass('checkbox-autofit'); 161 } 162 163 // check if list is disabled 164 if( $(instance.element).prop( 'disabled' ) ) { 165 placeholder.prop( 'disabled', true ); 166 } 167 168 // set placeholder maxWidth 169 if( instance.options.maxPlaceholderWidth ) { 170 placeholder.css( 'maxWidth', instance.options.maxPlaceholderWidth ); 171 } 172 173 // override with user defined maxHeight 174 if( instance.options.maxHeight ) { 175 var maxHeight = instance.options.maxHeight; 176 } 177 else { 178 // cacl default maxHeight 179 var maxHeight = ($(window).height() - optionsWrap.offset().top + $(window).scrollTop() - 20); 180 } 181 182 // maxHeight cannot be less than options.minHeight 183 maxHeight = maxHeight < instance.options.minHeight ? instance.options.minHeight : maxHeight; 184 185 optionsWrap.css({ 186 maxWidth : instance.options.maxWidth, 187 minHeight: instance.options.minHeight, 188 maxHeight: maxHeight, 189 }); 190 191 // isolate options scroll 192 // @source: https://github.com/nobleclem/jQuery-IsolatedScroll 193 optionsWrap.on( 'touchmove mousewheel DOMMouseScroll', function ( e ) { 194 if( ($(this).outerHeight() < $(this)[0].scrollHeight) ) { 195 var e0 = e.originalEvent, 196 delta = e0.wheelDelta || -e0.detail; 197 198 if( ($(this).outerHeight() + $(this)[0].scrollTop) > $(this)[0].scrollHeight ) { 199 e.preventDefault(); 200 this.scrollTop += ( delta < 0 ? 1 : -1 ); 201 } 202 } 203 }); 204 205 // hide options menus if click happens off of the list placeholder button 206 $(document).off('click.ms-hideopts').on('click.ms-hideopts', function( event ){ 207 if( !$(event.target).closest('.ms-options-wrap').length ) { 208 $('.ms-options-wrap.ms-active > .ms-options').each(function(){ 209 $(this).closest('.ms-options-wrap').removeClass('ms-active'); 210 211 var listID = $(this).closest('.ms-options-wrap').attr('id'); 212 213 var thisInst = $(this).parent().siblings('.'+ listID +'.jqmsLoaded').data('plugin_multiselect-instance'); 214 215 // USER CALLBACK 216 if( typeof thisInst.options.onControlClose == 'function' ) { 217 thisInst.options.onControlClose( thisInst.element ); 218 } 219 }); 220 } 221 // hide open option lists if escape key pressed 222 }).on('keydown', function( event ){ 223 if( (event.keyCode || event.which) == 27 ) { // esc key 224 $(this).trigger('click.ms-hideopts'); 225 } 226 }); 227 228 // handle pressing enter|space while tabbing through 229 placeholder.on('keydown', function( event ){ 230 var code = (event.keyCode || event.which); 231 if( (code == 13) || (code == 32) ) { // enter OR space 232 placeholder.trigger( 'mousedown' ); 233 } 234 }); 235 236 // disable button action 237 placeholder.on( 'mousedown', function( event ){ 238 // ignore if its not a left click 239 if( event.which && (event.which != 1) ) { 240 return true; 241 } 242 243 // hide other menus before showing this one 244 $('.ms-options-wrap.ms-active').each(function(){ 245 if( $(this).siblings( '.'+ $(this).attr('id') +'.jqmsLoaded')[0] != optionsWrap.parent().siblings('.ms-list-'+ instance.listNumber +'.jqmsLoaded')[0] ) { 246 $(this).removeClass('ms-active'); 247 248 var thisInst = $(this).siblings( '.'+ $(this).attr('id') +'.jqmsLoaded').data('plugin_multiselect-instance'); 249 250 // USER CALLBACK 251 if( typeof thisInst.options.onControlClose == 'function' ) { 252 thisInst.options.onControlClose( thisInst.element ); 253 } 254 } 255 }); 256 257 // show/hide options 258 optionsWrap.closest('.ms-options-wrap').toggleClass('ms-active'); 259 260 // recalculate height 261 if( optionsWrap.closest('.ms-options-wrap').hasClass('ms-active') ) { 262 optionsWrap.css( 'maxHeight', '' ); 263 264 // override with user defined maxHeight 265 if( instance.options.maxHeight ) { 266 var maxHeight = instance.options.maxHeight; 267 } 268 else { 269 // cacl default maxHeight 270 var maxHeight = ($(window).height() - optionsWrap.offset().top + $(window).scrollTop() - 20); 271 } 272 273 if( maxHeight ) { 274 // maxHeight cannot be less than options.minHeight 275 maxHeight = maxHeight < instance.options.minHeight ? instance.options.minHeight : maxHeight; 276 277 optionsWrap.css( 'maxHeight', maxHeight ); 278 } 279 } 280 else if( typeof instance.options.onControlClose == 'function' ) { 281 instance.options.onControlClose( instance.element ); 282 } 283 }).click(function( event ){ event.preventDefault(); }); 284 285 // add placeholder copy 286 if( instance.options.texts.placeholder ) { 287 placeholder.find('span').text( instance.options.texts.placeholder ); 288 } 289 290 // add search box 291 if( instance.options.search ) { 292 optionsList.before('<div class="ms-search"><input type="text" value="" placeholder="'+ instance.options.texts.search +'" /></div>'); 293 294 var search = optionsWrap.find('.ms-search input'); 295 search.on('keyup', function(){ 296 // ignore keystrokes that don't make a difference 297 if( $(this).data('lastsearch') == $(this).val() ) { 298 return true; 299 } 300 301 // pause timeout 302 if( $(this).data('searchTimeout') ) { 303 clearTimeout( $(this).data('searchTimeout') ); 304 } 305 306 var thisSearchElem = $(this); 307 308 $(this).data('searchTimeout', setTimeout(function(){ 309 thisSearchElem.data('lastsearch', thisSearchElem.val() ); 310 311 // USER CALLBACK 312 if( typeof instance.options.searchOptions.onSearch == 'function' ) { 313 instance.options.searchOptions.onSearch( instance.element ); 314 } 315 316 // search non optgroup li's 317 var searchString = $.trim( search.val().toLowerCase() ); 318 if( searchString ) { 319 optionsList.find('li[data-search-term*="'+ searchString +'"]:not(.optgroup)').removeClass('ms-hidden'); 320 optionsList.find('li:not([data-search-term*="'+ searchString +'"], .optgroup)').addClass('ms-hidden'); 321 } 322 else { 323 optionsList.find('.ms-hidden').removeClass('ms-hidden'); 324 } 325 326 // show/hide optgroups based on if there are items visible within 327 if( !instance.options.searchOptions.showOptGroups ) { 328 optionsList.find('.optgroup').each(function(){ 329 if( $(this).find('li:not(.ms-hidden)').length ) { 330 $(this).show(); 331 } 332 else { 333 $(this).hide(); 334 } 335 }); 336 } 337 338 instance._updateSelectAllText(); 339 }, instance.options.searchOptions.delay )); 340 }); 341 } 342 343 // add global select all options 344 if( instance.options.selectAll ) { 345 optionsList.before('<a href="#" class="ms-selectall global">' + instance.options.texts.selectAll + '</a>'); 346 } 347 348 // handle select all option 349 optionsWrap.on('click', '.ms-selectall', function( event ){ 350 event.preventDefault(); 351 352 instance.updateSelectAll = false; 353 instance.updatePlaceholder = false; 354 355 var select = optionsWrap.parent().siblings('.ms-list-'+ instance.listNumber +'.jqmsLoaded'); 356 357 if( $(this).hasClass('global') ) { 358 // check if any options are not selected if so then select them 359 if( optionsList.find('li:not(.optgroup, .selected, .ms-hidden)').length ) { 360 // get unselected vals, mark as selected, return val list 361 optionsList.find('li:not(.optgroup, .selected, .ms-hidden)').addClass('selected'); 362 optionsList.find('li.selected input[type="checkbox"]:not(:disabled)').prop( 'checked', true ); 363 } 364 // deselect everything 365 else { 366 optionsList.find('li:not(.optgroup, .ms-hidden).selected').removeClass('selected'); 367 optionsList.find('li:not(.optgroup, .ms-hidden, .selected) input[type="checkbox"]:not(:disabled)').prop( 'checked', false ); 368 } 369 } 370 else if( $(this).closest('li').hasClass('optgroup') ) { 371 var optgroup = $(this).closest('li.optgroup'); 372 373 // check if any selected if so then select them 374 if( optgroup.find('li:not(.selected, .ms-hidden)').length ) { 375 optgroup.find('li:not(.selected, .ms-hidden)').addClass('selected'); 376 optgroup.find('li.selected input[type="checkbox"]:not(:disabled)').prop( 'checked', true ); 377 } 378 // deselect everything 379 else { 380 optgroup.find('li:not(.ms-hidden).selected').removeClass('selected'); 381 optgroup.find('li:not(.ms-hidden, .selected) input[type="checkbox"]:not(:disabled)').prop( 'checked', false ); 382 } 383 } 384 385 var vals = []; 386 optionsList.find('li.selected input[type="checkbox"]').each(function(){ 387 vals.push( $(this).val() ); 388 }); 389 select.val( vals ).trigger('change'); 390 391 instance.updateSelectAll = true; 392 instance.updatePlaceholder = true; 393 394 // USER CALLBACK 395 if( typeof instance.options.onSelectAll == 'function' ) { 396 instance.options.onSelectAll( instance.element, vals.length ); 397 } 398 399 instance._updateSelectAllText(); 400 instance._updatePlaceholderText(); 401 }); 402 403 // add options to wrapper 404 var options = []; 405 $(instance.element).children().each(function(){ 406 if( this.nodeName == 'OPTGROUP' ) { 407 var groupOptions = []; 408 409 $(this).children('option').each(function(){ 410 var thisOptionAtts = {}; 411 for( var i = 0; i < instance.options.optionAttributes.length; i++ ) { 412 var thisOptAttr = instance.options.optionAttributes[ i ]; 413 414 if( $(this).attr( thisOptAttr ) !== undefined ) { 415 thisOptionAtts[ thisOptAttr ] = $(this).attr( thisOptAttr ); 416 } 417 } 418 419 groupOptions.push({ 420 name : $(this).text(), 421 value : $(this).val(), 422 checked: $(this).prop( 'selected' ), 423 attributes: thisOptionAtts 424 }); 425 }); 426 427 options.push({ 428 label : $(this).attr('label'), 429 options: groupOptions 430 }); 431 } 432 else if( this.nodeName == 'OPTION' ) { 433 var thisOptionAtts = {}; 434 for( var i = 0; i < instance.options.optionAttributes.length; i++ ) { 435 var thisOptAttr = instance.options.optionAttributes[ i ]; 436 437 if( $(this).attr( thisOptAttr ) !== undefined ) { 438 thisOptionAtts[ thisOptAttr ] = $(this).attr( thisOptAttr ); 439 } 440 } 441 442 options.push({ 443 name : $(this).text(), 444 value : $(this).val(), 445 checked : $(this).prop( 'selected' ), 446 attributes: thisOptionAtts 447 }); 448 } 449 else { 450 // bad option 451 return true; 452 } 453 }); 454 instance.loadOptions( options, true, false ); 455 456 // BIND SELECT ACTION 457 optionsWrap.on( 'click', 'input[type="checkbox"]', function(){ 458 $(this).closest( 'li' ).toggleClass( 'selected' ); 459 460 var select = optionsWrap.parent().siblings('.ms-list-'+ instance.listNumber +'.jqmsLoaded'); 461 462 // toggle clicked option 463 select.find('option[value="'+ instance._escapeSelector( $(this).val() ) +'"]').prop( 464 'selected', $(this).is(':checked') 465 ).closest('select').trigger('change'); 466 467 // USER CALLBACK 468 if( typeof instance.options.onOptionClick == 'function' ) { 469 instance.options.onOptionClick(instance.element, this); 470 } 471 472 instance._updateSelectAllText(); 473 instance._updatePlaceholderText(); 474 }); 475 476 // BIND FOCUS EVENT 477 optionsWrap.on('focusin', 'input[type="checkbox"]', function(){ 478 $(this).closest('label').addClass('focused'); 479 }).on('focusout', 'input[type="checkbox"]', function(){ 480 $(this).closest('label').removeClass('focused'); 481 }); 482 483 // USER CALLBACK 484 if( typeof instance.options.onLoad === 'function' ) { 485 instance.options.onLoad( instance.element ); 486 } 487 488 // hide native select list 489 $(instance.element).hide(); 490 }, 491 492 /* LOAD SELECT OPTIONS */ 493 loadOptions: function( options, overwrite, updateSelect ) { 494 overwrite = (typeof overwrite == 'boolean') ? overwrite : true; 495 updateSelect = (typeof updateSelect == 'boolean') ? updateSelect : true; 496 497 var instance = this; 498 var select = $(instance.element); 499 var optionsList = select.siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> .ms-options > ul'); 500 var optionsWrap = select.siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> .ms-options'); 501 502 if( overwrite ) { 503 optionsList.find('> li').remove(); 504 505 if( updateSelect ) { 506 select.find('> *').remove(); 507 } 508 } 509 510 var containers = []; 511 for( var key in options ) { 512 // Prevent prototype methods injected into options from being iterated over. 513 if( !options.hasOwnProperty( key ) ) { 514 continue; 515 } 516 517 var thisOption = options[ key ]; 518 var container = $('<li/>'); 519 var appendContainer = true; 520 521 // OPTION 522 if( thisOption.hasOwnProperty('value') ) { 523 if( instance.options.showCheckbox && instance.options.checkboxAutoFit ) { 524 container.addClass('ms-reflow'); 525 } 526 527 // add option to ms dropdown 528 instance._addOption( container, thisOption ); 529 530 if( updateSelect ) { 531 var selOption = $('<option value="'+ thisOption.value +'">'+ thisOption.name +'</option>'); 532 533 // add custom user attributes 534 if( thisOption.hasOwnProperty('attributes') && Object.keys( thisOption.attributes ).length ) { 535 selOption.attr( thisOption.attributes ); 536 } 537 538 // mark option as selected 539 if( thisOption.checked ) { 540 selOption.prop( 'selected', true ); 541 } 542 543 select.append( selOption ); 544 } 545 } 546 // OPTGROUP 547 else if( thisOption.hasOwnProperty('options') ) { 548 var optGroup = $('<optgroup label="'+ thisOption.label +'"></optgroup>'); 549 550 optionsList.find('> li.optgroup > span.label').each(function(){ 551 if( $(this).text() == thisOption.label ) { 552 container = $(this).closest('.optgroup'); 553 appendContainer = false; 554 } 555 }); 556 557 // prepare to append optgroup to select element 558 if( updateSelect ) { 559 if( select.find('optgroup[label="'+ thisOption.label +'"]').length ) { 560 optGroup = select.find('optgroup[label="'+ thisOption.label +'"]'); 561 } 562 else { 563 select.append( optGroup ); 564 } 565 } 566 567 // setup container 568 if( appendContainer ) { 569 container.addClass('optgroup'); 570 container.append('<span class="label">'+ thisOption.label +'</span>'); 571 container.find('> .label').css({ 572 clear: 'both' 573 }); 574 575 // add select all link 576 if( instance.options.selectGroup ) { 577 container.append('<a href="#" class="ms-selectall">' + instance.options.texts.selectAll + '</a>'); 578 } 579 580 container.append('<ul/>'); 581 } 582 583 for( var gKey in thisOption.options ) { 584 // Prevent prototype methods injected into options from 585 // being iterated over. 586 if( !thisOption.options.hasOwnProperty( gKey ) ) { 587 continue; 588 } 589 590 var thisGOption = thisOption.options[ gKey ]; 591 var gContainer = $('<li/>'); 592 if( instance.options.showCheckbox && instance.options.checkboxAutoFit ) { 593 gContainer.addClass('ms-reflow'); 594 } 595 596 // no clue what this is we hit (skip) 597 if( !thisGOption.hasOwnProperty('value') ) { 598 continue; 599 } 600 601 instance._addOption( gContainer, thisGOption ); 602 603 container.find('> ul').append( gContainer ); 604 605 // add option to optgroup in select element 606 if( updateSelect ) { 607 var selOption = $('<option value="'+ thisGOption.value +'">'+ thisGOption.name +'</option>'); 608 609 // add custom user attributes 610 if( thisGOption.hasOwnProperty('attributes') && Object.keys( thisGOption.attributes ).length ) { 611 selOption.attr( thisGOption.attributes ); 612 } 613 614 // mark option as selected 615 if( thisGOption.checked ) { 616 selOption.prop( 'selected', true ); 617 } 618 619 optGroup.append( selOption ); 620 } 621 } 622 } 623 else { 624 // no clue what this is we hit (skip) 625 continue; 626 } 627 628 if( appendContainer ) { 629 containers.push( container ); 630 } 631 } 632 optionsList.append( containers ); 633 634 // pad out label for room for the checkbox 635 if( instance.options.checkboxAutoFit && instance.options.showCheckbox && !optionsWrap.hasClass('hide-checkbox') ) { 636 var chkbx = optionsList.find('.ms-reflow:eq(0) input[type="checkbox"]'); 637 if( chkbx.length ) { 638 var checkboxWidth = chkbx.outerWidth(); 639 checkboxWidth = checkboxWidth ? checkboxWidth : 15; 640 641 optionsList.find('.ms-reflow label').css( 642 'padding-left', 643 (parseInt( chkbx.closest('label').css('padding-left') ) * 2) + checkboxWidth 644 ); 645 646 optionsList.find('.ms-reflow').removeClass('ms-reflow'); 647 } 648 } 649 650 // update placeholder text 651 instance._updatePlaceholderText(); 652 653 // RESET COLUMN STYLES 654 optionsWrap.find('ul').css({ 655 'column-count' : '', 656 'column-gap' : '', 657 '-webkit-column-count': '', 658 '-webkit-column-gap' : '', 659 '-moz-column-count' : '', 660 '-moz-column-gap' : '' 661 }); 662 663 // COLUMNIZE 664 if( select.find('optgroup').length ) { 665 // float non grouped options 666 optionsList.find('> li:not(.optgroup)').css({ 667 'float': 'left', 668 width: (100 / instance.options.columns) +'%' 669 }); 670 671 // add CSS3 column styles 672 optionsList.find('li.optgroup').css({ 673 clear: 'both' 674 }).find('> ul').css({ 675 'column-count' : instance.options.columns, 676 'column-gap' : 0, 677 '-webkit-column-count': instance.options.columns, 678 '-webkit-column-gap' : 0, 679 '-moz-column-count' : instance.options.columns, 680 '-moz-column-gap' : 0 681 }); 682 683 // for crappy IE versions float grouped options 684 if( this._ieVersion() && (this._ieVersion() < 10) ) { 685 optionsList.find('li.optgroup > ul > li').css({ 686 'float': 'left', 687 width: (100 / instance.options.columns) +'%' 688 }); 689 } 690 } 691 else { 692 // add CSS3 column styles 693 optionsList.css({ 694 'column-count' : instance.options.columns, 695 'column-gap' : 0, 696 '-webkit-column-count': instance.options.columns, 697 '-webkit-column-gap' : 0, 698 '-moz-column-count' : instance.options.columns, 699 '-moz-column-gap' : 0 700 }); 701 702 // for crappy IE versions float grouped options 703 if( this._ieVersion() && (this._ieVersion() < 10) ) { 704 optionsList.find('> li').css({ 705 'float': 'left', 706 width: (100 / instance.options.columns) +'%' 707 }); 708 } 709 } 710 711 // update un/select all logic 712 instance._updateSelectAllText(); 713 }, 714 715 /* UPDATE MULTISELECT CONFIG OPTIONS */ 716 settings: function( options ) { 717 this.options = $.extend( true, {}, this.options, options ); 718 this.reload(); 719 }, 720 721 /* RESET THE DOM */ 722 unload: function() { 723 $(this.element).siblings('#ms-list-'+ this.listNumber +'.ms-options-wrap').remove(); 724 $(this.element).show(function(){ 725 $(this).css('display','').removeClass('jqmsLoaded'); 726 }); 727 }, 728 729 /* RELOAD JQ MULTISELECT LIST */ 730 reload: function() { 731 // remove existing options 732 $(this.element).siblings('#ms-list-'+ this.listNumber +'.ms-options-wrap').remove(); 733 $(this.element).removeClass('jqmsLoaded'); 734 735 // load element 736 this.load(); 737 }, 738 739 // RESET BACK TO DEFAULT VALUES & RELOAD 740 reset: function() { 741 var defaultVals = []; 742 $(this.element).find('option').each(function(){ 743 if( $(this).prop('defaultSelected') ) { 744 defaultVals.push( $(this).val() ); 745 } 746 }); 747 748 $(this.element).val( defaultVals ); 749 750 this.reload(); 751 }, 752 753 disable: function( status ) { 754 status = (typeof status === 'boolean') ? status : true; 755 $(this.element).prop( 'disabled', status ); 756 $(this.element).siblings('#ms-list-'+ this.listNumber +'.ms-options-wrap').find('button:first-child') 757 .prop( 'disabled', status ); 758 }, 759 760 /** PRIVATE FUNCTIONS **/ 761 // update the un/select all texts based on selected options and visibility 762 _updateSelectAllText: function(){ 763 if( !this.updateSelectAll ) { 764 return; 765 } 766 767 var instance = this; 768 769 // select all not used at all so just do nothing 770 if( !instance.options.selectAll && !instance.options.selectGroup ) { 771 return; 772 } 773 774 var optionsWrap = $(instance.element).siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> .ms-options'); 775 776 // update un/select all text 777 optionsWrap.find('.ms-selectall').each(function(){ 778 var unselected = $(this).parent().find('li:not(.optgroup,.selected,.ms-hidden)'); 779 780 $(this).text( 781 unselected.length ? instance.options.texts.selectAll : instance.options.texts.unselectAll 782 ); 783 }); 784 }, 785 786 // update selected placeholder text 787 _updatePlaceholderText: function(){ 788 if( !this.updatePlaceholder ) { 789 return; 790 } 791 792 var instance = this; 793 var select = $(instance.element); 794 var selectVals = select.val() ? select.val() : []; 795 var placeholder = select.siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> button:first-child'); 796 var placeholderTxt = placeholder.find('span'); 797 var optionsWrap = select.siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> .ms-options'); 798 799 // if there are disabled options get those values as well 800 if( select.find('option:selected:disabled').length ) { 801 selectVals = []; 802 select.find('option:selected').each(function(){ 803 selectVals.push( $(this).val() ); 804 }); 805 } 806 807 // get selected options 808 var selOpts = []; 809 for( var key in selectVals ) { 810 // Prevent prototype methods injected into options from being iterated over. 811 if( !selectVals.hasOwnProperty( key ) ) { 812 continue; 813 } 814 815 selOpts.push( 816 $.trim( select.find('option[value="'+ instance._escapeSelector( selectVals[ key ] ) +'"]').text() ) 817 ); 818 819 if( selOpts.length >= instance.options.maxPlaceholderOpts ) { 820 break; 821 } 822 } 823 824 // UPDATE PLACEHOLDER TEXT WITH OPTIONS SELECTED 825 placeholderTxt.text( selOpts.join( ', ' ) ); 826 827 if( selOpts.length ) { 828 optionsWrap.closest('.ms-options-wrap').addClass('ms-has-selections'); 829 830 // USER CALLBACK 831 if( typeof instance.options.onPlaceholder == 'function' ) { 832 instance.options.onPlaceholder( instance.element, placeholderTxt, selOpts ); 833 } 834 } 835 else { 836 optionsWrap.closest('.ms-options-wrap').removeClass('ms-has-selections'); 837 } 838 839 // replace placeholder text 840 if( !selOpts.length ) { 841 placeholderTxt.text( instance.options.texts.placeholder ); 842 } 843 // if copy is larger than button width use "# selected" 844 else if( (placeholderTxt.width() > placeholder.width()) || (selOpts.length != selectVals.length) ) { 845 placeholderTxt.text( selectVals.length + instance.options.texts.selectedOptions ); 846 } 847 }, 848 849 // Add option to the custom dom list 850 _addOption: function( container, option ) { 851 var instance = this; 852 var thisOption = $('<label/>', { 853 for : 'ms-opt-'+ msOptCounter, 854 text: option.name 855 }); 856 857 var thisCheckbox = $('<input>', { 858 type : 'checkbox', 859 title: option.name, 860 id : 'ms-opt-'+ msOptCounter, 861 value: option.value 862 }); 863 864 // add user defined attributes 865 if( option.hasOwnProperty('attributes') && Object.keys( option.attributes ).length ) { 866 thisCheckbox.attr( option.attributes ); 867 } 868 869 if( option.checked ) { 870 container.addClass('default selected'); 871 thisCheckbox.prop( 'checked', true ); 872 } 873 874 thisOption.prepend( thisCheckbox ); 875 876 var searchTerm = ''; 877 if( instance.options.searchOptions.searchText ) { 878 searchTerm += ' ' + option.name.toLowerCase(); 879 } 880 if( instance.options.searchOptions.searchValue ) { 881 searchTerm += ' ' + option.value.toLowerCase(); 882 } 883 884 container.attr( 'data-search-term', $.trim( searchTerm
vendor: 1,834 bytes, lines 884-939
884) ).prepend( thisOption ); 885 886 msOptCounter = msOptCounter + 1; 887 }, 888 889 // check ie version 890 _ieVersion: function() { 891 var myNav = navigator.userAgent.toLowerCase(); 892 return (myNav.indexOf('msie') != -1) ? parseInt(myNav.split('msie')[1]) : false; 893 }, 894 895 // escape selector 896 _escapeSelector: function( string ) { 897 if( typeof $.escapeSelector == 'function' ) { 898 return $.escapeSelector( string ); 899 } 900 else { 901 return string.replace(/[!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, "\\$&"); 902 } 903 } 904 }; 905 906 // ENABLE JQUERY PLUGIN FUNCTION 907 $.fn.multiselect = function( options ){ 908 if( !this.length ) { 909 return; 910 } 911 912 var args = arguments; 913 var ret; 914 915 // menuize each list 916 if( (options === undefined) || (typeof options === 'object') ) { 917 return this.each(function(){ 918 if( !$.data( this, 'plugin_multiselect' ) ) { 919 $.data( this, 'plugin_multiselect', new MultiSelect( this, options ) ); 920 } 921 }); 922 } else if( (typeof options === 'string') && (options[0] !== '_') && (options !== 'init') ) { 923 this.each(function(){ 924 var instance = $.data( this, 'plugin_multiselect' ); 925 926 if( instance instanceof MultiSelect && typeof instance[ options ] === 'function' ) { 927 ret = instance[ options ].apply( instance, Array.prototype.slice.call( args, 1 ) ); 928 } 929 930 // special destruct handler 931 if( options === 'unload' ) { 932 $.data( this, 'plugin_multiselect', null ); 933 } 934 }); 935 936 return ret; 937 } 938 }; 939}(jQuery));
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.