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