Teacher html
Jump to navigation
Jump to search
Line 392: | Line 392: | ||
<script> | <script> | ||
− | + | </style> | |
.ms-options-wrap, | .ms-options-wrap, | ||
.ms-options-wrap * { | .ms-options-wrap * { | ||
Line 541: | Line 541: | ||
clip: rect(1px, 1px, 1px, 1px); | clip: rect(1px, 1px, 1px, 1px); | ||
} | } | ||
+ | </style> | ||
+ | <script> | ||
+ | |||
+ | /** | ||
+ | * Display a nice easy to use multiselect list | ||
+ | * @Version: 2.4.18 | ||
+ | * @Author: Patrick Springstubbe | ||
+ | * @Contact: @JediNobleclem | ||
+ | * @Website: springstubbe.us | ||
+ | * @Source: https://github.com/nobleclem/jQuery-MultiSelect | ||
+ | * | ||
+ | * Usage: | ||
+ | * $('select[multiple]').multiselect(); | ||
+ | * $('select[multiple]').multiselect({ texts: { placeholder: 'Select options' } }); | ||
+ | * $('select[multiple]').multiselect('reload'); | ||
+ | * $('select[multiple]').multiselect( 'loadOptions', [{ | ||
+ | * name : 'Option Name 1', | ||
+ | * value : 'option-value-1', | ||
+ | * checked: false, | ||
+ | * attributes : { | ||
+ | * custom1: 'value1', | ||
+ | * custom2: 'value2' | ||
+ | * } | ||
+ | * },{ | ||
+ | * name : 'Option Name 2', | ||
+ | * value : 'option-value-2', | ||
+ | * checked: false, | ||
+ | * attributes : { | ||
+ | * custom1: 'value1', | ||
+ | * custom2: 'value2' | ||
+ | * } | ||
+ | * }]); | ||
+ | * | ||
+ | **/ | ||
+ | (function($){ | ||
+ | var defaults = { | ||
+ | columns: 1, // how many columns should be use to show options | ||
+ | search : false, // include option search box | ||
+ | |||
+ | // search filter options | ||
+ | searchOptions : { | ||
+ | delay : 250, // time (in ms) between keystrokes until search happens | ||
+ | showOptGroups: false, // show option group titles if no options remaining | ||
+ | searchText : true, // search within the text | ||
+ | searchValue : false, // search within the value | ||
+ | onSearch : function( element ){} // fires on keyup before search on options happens | ||
+ | }, | ||
+ | |||
+ | // plugin texts | ||
+ | texts: { | ||
+ | placeholder : 'Select options', // text to use in dummy input | ||
+ | search : 'Search', // search input placeholder text | ||
+ | selectedOptions: ' selected', // selected suffix text | ||
+ | selectAll : 'Select all', // select all text | ||
+ | unselectAll : 'Unselect all', // unselect all text | ||
+ | noneSelected : 'None Selected' // None selected text | ||
+ | }, | ||
+ | |||
+ | // general options | ||
+ | selectAll : false, // add select all option | ||
+ | selectGroup : false, // select entire optgroup | ||
+ | minHeight : 200, // minimum height of option overlay | ||
+ | maxHeight : null, // maximum height of option overlay | ||
+ | maxWidth : null, // maximum width of option overlay (or selector) | ||
+ | maxPlaceholderWidth: null, // maximum width of placeholder button | ||
+ | maxPlaceholderOpts : 10, // maximum number of placeholder options to show until "# selected" shown instead | ||
+ | showCheckbox : true, // display the checkbox to the user | ||
+ | checkboxAutoFit : false, // auto calc checkbox padding | ||
+ | optionAttributes : [], // attributes to copy to the checkbox from the option element | ||
+ | |||
+ | // Callbacks | ||
+ | onLoad : function( element ){}, // fires at end of list initialization | ||
+ | onOptionClick : function( element, option ){}, // fires when an option is clicked | ||
+ | onControlClose: function( element ){}, // fires when the options list is closed | ||
+ | onSelectAll : function( element, selected ){}, // fires when (un)select all is clicked | ||
+ | onPlaceholder : function( element, placeholder, selectedOpts ){}, // fires when the placeholder txt is updated | ||
+ | }; | ||
+ | |||
+ | var msCounter = 1; // counter for each select list | ||
+ | var msOptCounter = 1; // counter for each option on page | ||
+ | |||
+ | // FOR LEGACY BROWSERS (talking to you IE8) | ||
+ | if( typeof Array.prototype.map !== 'function' ) { | ||
+ | Array.prototype.map = function( callback, thisArg ) { | ||
+ | if( typeof thisArg === 'undefined' ) { | ||
+ | thisArg = this; | ||
+ | } | ||
+ | |||
+ | return $.isArray( thisArg ) ? $.map( thisArg, callback ) : []; | ||
+ | }; | ||
+ | } | ||
+ | if( typeof String.prototype.trim !== 'function' ) { | ||
+ | String.prototype.trim = function() { | ||
+ | return this.replace(/^\s+|\s+$/g, ''); | ||
+ | }; | ||
+ | } | ||
+ | |||
+ | function MultiSelect( element, options ) | ||
+ | { | ||
+ | this.element = element; | ||
+ | this.options = $.extend( true, {}, defaults, options ); | ||
+ | this.updateSelectAll = true; | ||
+ | this.updatePlaceholder = true; | ||
+ | this.listNumber = msCounter; | ||
+ | |||
+ | msCounter = msCounter + 1; // increment counter | ||
+ | |||
+ | /* Make sure its a multiselect list */ | ||
+ | if( !$(this.element).attr('multiple') ) { | ||
+ | throw new Error( '[jQuery-MultiSelect] Select list must be a multiselect list in order to use this plugin' ); | ||
+ | } | ||
+ | |||
+ | /* Options validation checks */ | ||
+ | if( this.options.search ){ | ||
+ | if( !this.options.searchOptions.searchText && !this.options.searchOptions.searchValue ){ | ||
+ | throw new Error( '[jQuery-MultiSelect] Either searchText or searchValue should be true.' ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** BACKWARDS COMPATIBILITY **/ | ||
+ | if( 'placeholder' in this.options ) { | ||
+ | this.options.texts.placeholder = this.options.placeholder; | ||
+ | delete this.options.placeholder; | ||
+ | } | ||
+ | if( 'default' in this.options.searchOptions ) { | ||
+ | this.options.texts.search = this.options.searchOptions['default']; | ||
+ | delete this.options.searchOptions['default']; | ||
+ | } | ||
+ | /** END BACKWARDS COMPATIBILITY **/ | ||
+ | |||
+ | // load this instance | ||
+ | this.load(); | ||
+ | } | ||
+ | |||
+ | MultiSelect.prototype = { | ||
+ | /* LOAD CUSTOM MULTISELECT DOM/ACTIONS */ | ||
+ | load: function() { | ||
+ | var instance = this; | ||
+ | |||
+ | // make sure this is a select list and not loaded | ||
+ | if( (instance.element.nodeName != 'SELECT') || $(instance.element).hasClass('jqmsLoaded') ) { | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | // sanity check so we don't double load on a select element | ||
+ | $(instance.element).addClass('jqmsLoaded ms-list-'+ instance.listNumber ).data( 'plugin_multiselect-instance', instance ); | ||
+ | |||
+ | // add option container | ||
+ | $(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>'); | ||
+ | |||
+ | var placeholder = $(instance.element).siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> button:first-child'); | ||
+ | var optionsWrap = $(instance.element).siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> .ms-options'); | ||
+ | var optionsList = optionsWrap.find('> ul'); | ||
+ | |||
+ | // don't show checkbox (add class for css to hide checkboxes) | ||
+ | if( !instance.options.showCheckbox ) { | ||
+ | optionsWrap.addClass('hide-checkbox'); | ||
+ | } | ||
+ | else if( instance.options.checkboxAutoFit ) { | ||
+ | optionsWrap.addClass('checkbox-autofit'); | ||
+ | } | ||
+ | |||
+ | // check if list is disabled | ||
+ | if( $(instance.element).prop( 'disabled' ) ) { | ||
+ | placeholder.prop( 'disabled', true ); | ||
+ | } | ||
+ | |||
+ | // set placeholder maxWidth | ||
+ | if( instance.options.maxPlaceholderWidth ) { | ||
+ | placeholder.css( 'maxWidth', instance.options.maxPlaceholderWidth ); | ||
+ | } | ||
+ | |||
+ | // override with user defined maxHeight | ||
+ | if( instance.options.maxHeight ) { | ||
+ | var maxHeight = instance.options.maxHeight; | ||
+ | } | ||
+ | else { | ||
+ | // cacl default maxHeight | ||
+ | var maxHeight = ($(window).height() - optionsWrap.offset().top + $(window).scrollTop() - 20); | ||
+ | } | ||
+ | |||
+ | // maxHeight cannot be less than options.minHeight | ||
+ | maxHeight = maxHeight < instance.options.minHeight ? instance.options.minHeight : maxHeight; | ||
+ | |||
+ | optionsWrap.css({ | ||
+ | maxWidth : instance.options.maxWidth, | ||
+ | minHeight: instance.options.minHeight, | ||
+ | maxHeight: maxHeight, | ||
+ | }); | ||
+ | |||
+ | // isolate options scroll | ||
+ | // @source: https://github.com/nobleclem/jQuery-IsolatedScroll | ||
+ | optionsWrap.on( 'touchmove mousewheel DOMMouseScroll', function ( e ) { | ||
+ | if( ($(this).outerHeight() < $(this)[0].scrollHeight) ) { | ||
+ | var e0 = e.originalEvent, | ||
+ | delta = e0.wheelDelta || -e0.detail; | ||
+ | |||
+ | if( ($(this).outerHeight() + $(this)[0].scrollTop) > $(this)[0].scrollHeight ) { | ||
+ | e.preventDefault(); | ||
+ | this.scrollTop += ( delta < 0 ? 1 : -1 ); | ||
+ | } | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | // hide options menus if click happens off of the list placeholder button | ||
+ | $(document).off('click.ms-hideopts').on('click.ms-hideopts', function( event ){ | ||
+ | if( !$(event.target).closest('.ms-options-wrap').length ) { | ||
+ | $('.ms-options-wrap.ms-active > .ms-options').each(function(){ | ||
+ | $(this).closest('.ms-options-wrap').removeClass('ms-active'); | ||
+ | |||
+ | var listID = $(this).closest('.ms-options-wrap').attr('id'); | ||
+ | |||
+ | var thisInst = $(this).parent().siblings('.'+ listID +'.jqmsLoaded').data('plugin_multiselect-instance'); | ||
+ | |||
+ | // USER CALLBACK | ||
+ | if( typeof thisInst.options.onControlClose == 'function' ) { | ||
+ | thisInst.options.onControlClose( thisInst.element ); | ||
+ | } | ||
+ | }); | ||
+ | } | ||
+ | // hide open option lists if escape key pressed | ||
+ | }).on('keydown', function( event ){ | ||
+ | if( (event.keyCode || event.which) == 27 ) { // esc key | ||
+ | $(this).trigger('click.ms-hideopts'); | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | // handle pressing enter|space while tabbing through | ||
+ | placeholder.on('keydown', function( event ){ | ||
+ | var code = (event.keyCode || event.which); | ||
+ | if( (code == 13) || (code == 32) ) { // enter OR space | ||
+ | placeholder.trigger( 'mousedown' ); | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | // disable button action | ||
+ | placeholder.on( 'mousedown', function( event ){ | ||
+ | // ignore if its not a left click | ||
+ | if( event.which && (event.which != 1) ) { | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | // hide other menus before showing this one | ||
+ | $('.ms-options-wrap.ms-active').each(function(){ | ||
+ | if( $(this).siblings( '.'+ $(this).attr('id') +'.jqmsLoaded')[0] != optionsWrap.parent().siblings('.ms-list-'+ instance.listNumber +'.jqmsLoaded')[0] ) { | ||
+ | $(this).removeClass('ms-active'); | ||
+ | |||
+ | var thisInst = $(this).siblings( '.'+ $(this).attr('id') +'.jqmsLoaded').data('plugin_multiselect-instance'); | ||
+ | |||
+ | // USER CALLBACK | ||
+ | if( typeof thisInst.options.onControlClose == 'function' ) { | ||
+ | thisInst.options.onControlClose( thisInst.element ); | ||
+ | } | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | // show/hide options | ||
+ | optionsWrap.closest('.ms-options-wrap').toggleClass('ms-active'); | ||
+ | |||
+ | // recalculate height | ||
+ | if( optionsWrap.closest('.ms-options-wrap').hasClass('ms-active') ) { | ||
+ | optionsWrap.css( 'maxHeight', '' ); | ||
+ | |||
+ | // override with user defined maxHeight | ||
+ | if( instance.options.maxHeight ) { | ||
+ | var maxHeight = instance.options.maxHeight; | ||
+ | } | ||
+ | else { | ||
+ | // cacl default maxHeight | ||
+ | var maxHeight = ($(window).height() - optionsWrap.offset().top + $(window).scrollTop() - 20); | ||
+ | } | ||
+ | |||
+ | if( maxHeight ) { | ||
+ | // maxHeight cannot be less than options.minHeight | ||
+ | maxHeight = maxHeight < instance.options.minHeight ? instance.options.minHeight : maxHeight; | ||
+ | |||
+ | optionsWrap.css( 'maxHeight', maxHeight ); | ||
+ | } | ||
+ | } | ||
+ | else if( typeof instance.options.onControlClose == 'function' ) { | ||
+ | instance.options.onControlClose( instance.element ); | ||
+ | } | ||
+ | }).click(function( event ){ event.preventDefault(); }); | ||
+ | |||
+ | // add placeholder copy | ||
+ | if( instance.options.texts.placeholder ) { | ||
+ | placeholder.find('span').text( instance.options.texts.placeholder ); | ||
+ | } | ||
+ | |||
+ | // add search box | ||
+ | if( instance.options.search ) { | ||
+ | optionsList.before('<div class="ms-search"><input type="text" value="" placeholder="'+ instance.options.texts.search +'" /></div>'); | ||
+ | |||
+ | var search = optionsWrap.find('.ms-search input'); | ||
+ | search.on('keyup', function(){ | ||
+ | // ignore keystrokes that don't make a difference | ||
+ | if( $(this).data('lastsearch') == $(this).val() ) { | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | // pause timeout | ||
+ | if( $(this).data('searchTimeout') ) { | ||
+ | clearTimeout( $(this).data('searchTimeout') ); | ||
+ | } | ||
+ | |||
+ | var thisSearchElem = $(this); | ||
+ | |||
+ | $(this).data('searchTimeout', setTimeout(function(){ | ||
+ | thisSearchElem.data('lastsearch', thisSearchElem.val() ); | ||
+ | |||
+ | // USER CALLBACK | ||
+ | if( typeof instance.options.searchOptions.onSearch == 'function' ) { | ||
+ | instance.options.searchOptions.onSearch( instance.element ); | ||
+ | } | ||
+ | |||
+ | // search non optgroup li's | ||
+ | var searchString = $.trim( search.val().toLowerCase() ); | ||
+ | if( searchString ) { | ||
+ | optionsList.find('li[data-search-term*="'+ searchString +'"]:not(.optgroup)').removeClass('ms-hidden'); | ||
+ | optionsList.find('li:not([data-search-term*="'+ searchString +'"], .optgroup)').addClass('ms-hidden'); | ||
+ | } | ||
+ | else { | ||
+ | optionsList.find('.ms-hidden').removeClass('ms-hidden'); | ||
+ | } | ||
+ | |||
+ | // show/hide optgroups based on if there are items visible within | ||
+ | if( !instance.options.searchOptions.showOptGroups ) { | ||
+ | optionsList.find('.optgroup').each(function(){ | ||
+ | if( $(this).find('li:not(.ms-hidden)').length ) { | ||
+ | $(this).show(); | ||
+ | } | ||
+ | else { | ||
+ | $(this).hide(); | ||
+ | } | ||
+ | }); | ||
+ | } | ||
+ | |||
+ | instance._updateSelectAllText(); | ||
+ | }, instance.options.searchOptions.delay )); | ||
+ | }); | ||
+ | } | ||
+ | |||
+ | // add global select all options | ||
+ | if( instance.options.selectAll ) { | ||
+ | optionsList.before('<a href="#" class="ms-selectall global">' + instance.options.texts.selectAll + '</a>'); | ||
+ | } | ||
+ | |||
+ | // handle select all option | ||
+ | optionsWrap.on('click', '.ms-selectall', function( event ){ | ||
+ | event.preventDefault(); | ||
+ | |||
+ | instance.updateSelectAll = false; | ||
+ | instance.updatePlaceholder = false; | ||
+ | |||
+ | var select = optionsWrap.parent().siblings('.ms-list-'+ instance.listNumber +'.jqmsLoaded'); | ||
+ | |||
+ | if( $(this).hasClass('global') ) { | ||
+ | // check if any options are not selected if so then select them | ||
+ | if( optionsList.find('li:not(.optgroup, .selected, .ms-hidden)').length ) { | ||
+ | // get unselected vals, mark as selected, return val list | ||
+ | optionsList.find('li:not(.optgroup, .selected, .ms-hidden)').addClass('selected'); | ||
+ | optionsList.find('li.selected input[type="checkbox"]:not(:disabled)').prop( 'checked', true ); | ||
+ | } | ||
+ | // deselect everything | ||
+ | else { | ||
+ | optionsList.find('li:not(.optgroup, .ms-hidden).selected').removeClass('selected'); | ||
+ | optionsList.find('li:not(.optgroup, .ms-hidden, .selected) input[type="checkbox"]:not(:disabled)').prop( 'checked', false ); | ||
+ | } | ||
+ | } | ||
+ | else if( $(this).closest('li').hasClass('optgroup') ) { | ||
+ | var optgroup = $(this).closest('li.optgroup'); | ||
+ | |||
+ | // check if any selected if so then select them | ||
+ | if( optgroup.find('li:not(.selected, .ms-hidden)').length ) { | ||
+ | optgroup.find('li:not(.selected, .ms-hidden)').addClass('selected'); | ||
+ | optgroup.find('li.selected input[type="checkbox"]:not(:disabled)').prop( 'checked', true ); | ||
+ | } | ||
+ | // deselect everything | ||
+ | else { | ||
+ | optgroup.find('li:not(.ms-hidden).selected').removeClass('selected'); | ||
+ | optgroup.find('li:not(.ms-hidden, .selected) input[type="checkbox"]:not(:disabled)').prop( 'checked', false ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var vals = []; | ||
+ | optionsList.find('li.selected input[type="checkbox"]').each(function(){ | ||
+ | vals.push( $(this).val() ); | ||
+ | }); | ||
+ | select.val( vals ).trigger('change'); | ||
+ | |||
+ | instance.updateSelectAll = true; | ||
+ | instance.updatePlaceholder = true; | ||
+ | |||
+ | // USER CALLBACK | ||
+ | if( typeof instance.options.onSelectAll == 'function' ) { | ||
+ | instance.options.onSelectAll( instance.element, vals.length ); | ||
+ | } | ||
+ | |||
+ | instance._updateSelectAllText(); | ||
+ | instance._updatePlaceholderText(); | ||
+ | }); | ||
+ | |||
+ | // add options to wrapper | ||
+ | var options = []; | ||
+ | $(instance.element).children().each(function(){ | ||
+ | if( this.nodeName == 'OPTGROUP' ) { | ||
+ | var groupOptions = []; | ||
+ | |||
+ | $(this).children('option').each(function(){ | ||
+ | var thisOptionAtts = {}; | ||
+ | for( var i = 0; i < instance.options.optionAttributes.length; i++ ) { | ||
+ | var thisOptAttr = instance.options.optionAttributes[ i ]; | ||
+ | |||
+ | if( $(this).attr( thisOptAttr ) !== undefined ) { | ||
+ | thisOptionAtts[ thisOptAttr ] = $(this).attr( thisOptAttr ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | groupOptions.push({ | ||
+ | name : $(this).text(), | ||
+ | value : $(this).val(), | ||
+ | checked: $(this).prop( 'selected' ), | ||
+ | attributes: thisOptionAtts | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | options.push({ | ||
+ | label : $(this).attr('label'), | ||
+ | options: groupOptions | ||
+ | }); | ||
+ | } | ||
+ | else if( this.nodeName == 'OPTION' ) { | ||
+ | var thisOptionAtts = {}; | ||
+ | for( var i = 0; i < instance.options.optionAttributes.length; i++ ) { | ||
+ | var thisOptAttr = instance.options.optionAttributes[ i ]; | ||
+ | |||
+ | if( $(this).attr( thisOptAttr ) !== undefined ) { | ||
+ | thisOptionAtts[ thisOptAttr ] = $(this).attr( thisOptAttr ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | options.push({ | ||
+ | name : $(this).text(), | ||
+ | value : $(this).val(), | ||
+ | checked : $(this).prop( 'selected' ), | ||
+ | attributes: thisOptionAtts | ||
+ | }); | ||
+ | } | ||
+ | else { | ||
+ | // bad option | ||
+ | return true; | ||
+ | } | ||
+ | }); | ||
+ | instance.loadOptions( options, true, false ); | ||
+ | |||
+ | // BIND SELECT ACTION | ||
+ | optionsWrap.on( 'click', 'input[type="checkbox"]', function(){ | ||
+ | $(this).closest( 'li' ).toggleClass( 'selected' ); | ||
+ | |||
+ | var select = optionsWrap.parent().siblings('.ms-list-'+ instance.listNumber +'.jqmsLoaded'); | ||
+ | |||
+ | // toggle clicked option | ||
+ | select.find('option[value="'+ instance._escapeSelector( $(this).val() ) +'"]').prop( | ||
+ | 'selected', $(this).is(':checked') | ||
+ | ).closest('select').trigger('change'); | ||
+ | |||
+ | // USER CALLBACK | ||
+ | if( typeof instance.options.onOptionClick == 'function' ) { | ||
+ | instance.options.onOptionClick(instance.element, this); | ||
+ | } | ||
+ | |||
+ | instance._updateSelectAllText(); | ||
+ | instance._updatePlaceholderText(); | ||
+ | }); | ||
+ | |||
+ | // BIND FOCUS EVENT | ||
+ | optionsWrap.on('focusin', 'input[type="checkbox"]', function(){ | ||
+ | $(this).closest('label').addClass('focused'); | ||
+ | }).on('focusout', 'input[type="checkbox"]', function(){ | ||
+ | $(this).closest('label').removeClass('focused'); | ||
+ | }); | ||
+ | |||
+ | // USER CALLBACK | ||
+ | if( typeof instance.options.onLoad === 'function' ) { | ||
+ | instance.options.onLoad( instance.element ); | ||
+ | } | ||
+ | |||
+ | // hide native select list | ||
+ | $(instance.element).hide(); | ||
+ | }, | ||
+ | |||
+ | /* LOAD SELECT OPTIONS */ | ||
+ | loadOptions: function( options, overwrite, updateSelect ) { | ||
+ | overwrite = (typeof overwrite == 'boolean') ? overwrite : true; | ||
+ | updateSelect = (typeof updateSelect == 'boolean') ? updateSelect : true; | ||
+ | |||
+ | var instance = this; | ||
+ | var select = $(instance.element); | ||
+ | var optionsList = select.siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> .ms-options > ul'); | ||
+ | var optionsWrap = select.siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> .ms-options'); | ||
+ | |||
+ | if( overwrite ) { | ||
+ | optionsList.find('> li').remove(); | ||
+ | |||
+ | if( updateSelect ) { | ||
+ | select.find('> *').remove(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var containers = []; | ||
+ | for( var key in options ) { | ||
+ | // Prevent prototype methods injected into options from being iterated over. | ||
+ | if( !options.hasOwnProperty( key ) ) { | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | var thisOption = options[ key ]; | ||
+ | var container = $('<li/>'); | ||
+ | var appendContainer = true; | ||
+ | |||
+ | // OPTION | ||
+ | if( thisOption.hasOwnProperty('value') ) { | ||
+ | if( instance.options.showCheckbox && instance.options.checkboxAutoFit ) { | ||
+ | container.addClass('ms-reflow'); | ||
+ | } | ||
+ | |||
+ | // add option to ms dropdown | ||
+ | instance._addOption( container, thisOption ); | ||
+ | |||
+ | if( updateSelect ) { | ||
+ | var selOption = $('<option/>', { | ||
+ | value: thisOption.value, | ||
+ | text : thisOption.name | ||
+ | }); | ||
+ | |||
+ | // add custom user attributes | ||
+ | if( thisOption.hasOwnProperty('attributes') && Object.keys( thisOption.attributes ).length ) { | ||
+ | selOption.attr( thisOption.attributes ); | ||
+ | } | ||
+ | |||
+ | // mark option as selected | ||
+ | if( thisOption.checked ) { | ||
+ | selOption.prop( 'selected', true ); | ||
+ | } | ||
+ | |||
+ | select.append( selOption ); | ||
+ | } | ||
+ | } | ||
+ | // OPTGROUP | ||
+ | else if( thisOption.hasOwnProperty('options') ) { | ||
+ | var optGroup = $('<optgroup/>', { | ||
+ | label: thisOption.label | ||
+ | }); | ||
+ | |||
+ | optionsList.find('> li.optgroup > span.label').each(function(){ | ||
+ | if( $(this).text() == thisOption.label ) { | ||
+ | container = $(this).closest('.optgroup'); | ||
+ | appendContainer = false; | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | // prepare to append optgroup to select element | ||
+ | if( updateSelect ) { | ||
+ | if( select.find('optgroup[label="'+ thisOption.label +'"]').length ) { | ||
+ | optGroup = select.find('optgroup[label="'+ thisOption.label +'"]'); | ||
+ | } | ||
+ | else { | ||
+ | select.append( optGroup ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // setup container | ||
+ | if( appendContainer ) { | ||
+ | container.addClass('optgroup'); | ||
+ | container.append('<span class="label">'+ thisOption.label +'</span>'); | ||
+ | container.find('> .label').css({ | ||
+ | clear: 'both' | ||
+ | }); | ||
+ | |||
+ | // add select all link | ||
+ | if( instance.options.selectGroup ) { | ||
+ | container.append('<a href="#" class="ms-selectall">' + instance.options.texts.selectAll + '</a>'); | ||
+ | } | ||
+ | |||
+ | container.append('<ul/>'); | ||
+ | } | ||
+ | |||
+ | for( var gKey in thisOption.options ) { | ||
+ | // Prevent prototype methods injected into options from | ||
+ | // being iterated over. | ||
+ | if( !thisOption.options.hasOwnProperty( gKey ) ) { | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | var thisGOption = thisOption.options[ gKey ]; | ||
+ | var gContainer = $('<li/>'); | ||
+ | if( instance.options.showCheckbox && instance.options.checkboxAutoFit ) { | ||
+ | gContainer.addClass('ms-reflow'); | ||
+ | } | ||
+ | |||
+ | // no clue what this is we hit (skip) | ||
+ | if( !thisGOption.hasOwnProperty('value') ) { | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | instance._addOption( gContainer, thisGOption ); | ||
+ | |||
+ | container.find('> ul').append( gContainer ); | ||
+ | |||
+ | // add option to optgroup in select element | ||
+ | if( updateSelect ) { | ||
+ | var selOption = $('<option/>', { | ||
+ | value: thisGOption.value, | ||
+ | text : thisGOption.name | ||
+ | }); | ||
+ | |||
+ | // add custom user attributes | ||
+ | if( thisGOption.hasOwnProperty('attributes') && Object.keys( thisGOption.attributes ).length ) { | ||
+ | selOption.attr( thisGOption.attributes ); | ||
+ | } | ||
+ | |||
+ | // mark option as selected | ||
+ | if( thisGOption.checked ) { | ||
+ | selOption.prop( 'selected', true ); | ||
+ | } | ||
+ | |||
+ | optGroup.append( selOption ); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | else { | ||
+ | // no clue what this is we hit (skip) | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | if( appendContainer ) { | ||
+ | containers.push( container ); | ||
+ | } | ||
+ | } | ||
+ | optionsList.append( containers ); | ||
+ | |||
+ | // pad out label for room for the checkbox | ||
+ | if( instance.options.checkboxAutoFit && instance.options.showCheckbox && !optionsWrap.hasClass('hide-checkbox') ) { | ||
+ | var chkbx = optionsList.find('.ms-reflow:eq(0) input[type="checkbox"]'); | ||
+ | if( chkbx.length ) { | ||
+ | var checkboxWidth = chkbx.outerWidth(); | ||
+ | checkboxWidth = checkboxWidth ? checkboxWidth : 15; | ||
+ | |||
+ | optionsList.find('.ms-reflow label').css( | ||
+ | 'padding-left', | ||
+ | (parseInt( chkbx.closest('label').css('padding-left') ) * 2) + checkboxWidth | ||
+ | ); | ||
+ | |||
+ | optionsList.find('.ms-reflow').removeClass('ms-reflow'); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // update placeholder text | ||
+ | instance._updatePlaceholderText(); | ||
+ | |||
+ | // RESET COLUMN STYLES | ||
+ | optionsWrap.find('ul').css({ | ||
+ | 'column-count' : '', | ||
+ | 'column-gap' : '', | ||
+ | '-webkit-column-count': '', | ||
+ | '-webkit-column-gap' : '', | ||
+ | '-moz-column-count' : '', | ||
+ | '-moz-column-gap' : '' | ||
+ | }); | ||
+ | |||
+ | // COLUMNIZE | ||
+ | if( select.find('optgroup').length ) { | ||
+ | // float non grouped options | ||
+ | optionsList.find('> li:not(.optgroup)').css({ | ||
+ | 'float': 'left', | ||
+ | width: (100 / instance.options.columns) +'%' | ||
+ | }); | ||
+ | |||
+ | // add CSS3 column styles | ||
+ | optionsList.find('li.optgroup').css({ | ||
+ | clear: 'both' | ||
+ | }).find('> ul').css({ | ||
+ | 'column-count' : instance.options.columns, | ||
+ | 'column-gap' : 0, | ||
+ | '-webkit-column-count': instance.options.columns, | ||
+ | '-webkit-column-gap' : 0, | ||
+ | '-moz-column-count' : instance.options.columns, | ||
+ | '-moz-column-gap' : 0 | ||
+ | }); | ||
+ | |||
+ | // for crappy IE versions float grouped options | ||
+ | if( this._ieVersion() && (this._ieVersion() < 10) ) { | ||
+ | optionsList.find('li.optgroup > ul > li').css({ | ||
+ | 'float': 'left', | ||
+ | width: (100 / instance.options.columns) +'%' | ||
+ | }); | ||
+ | } | ||
+ | } | ||
+ | else { | ||
+ | // add CSS3 column styles | ||
+ | optionsList.css({ | ||
+ | 'column-count' : instance.options.columns, | ||
+ | 'column-gap' : 0, | ||
+ | '-webkit-column-count': instance.options.columns, | ||
+ | '-webkit-column-gap' : 0, | ||
+ | '-moz-column-count' : instance.options.columns, | ||
+ | '-moz-column-gap' : 0 | ||
+ | }); | ||
+ | |||
+ | // for crappy IE versions float grouped options | ||
+ | if( this._ieVersion() && (this._ieVersion() < 10) ) { | ||
+ | optionsList.find('> li').css({ | ||
+ | 'float': 'left', | ||
+ | width: (100 / instance.options.columns) +'%' | ||
+ | }); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // update un/select all logic | ||
+ | instance._updateSelectAllText(); | ||
+ | }, | ||
+ | |||
+ | /* UPDATE MULTISELECT CONFIG OPTIONS */ | ||
+ | settings: function( options ) { | ||
+ | this.options = $.extend( true, {}, this.options, options ); | ||
+ | this.reload(); | ||
+ | }, | ||
+ | |||
+ | /* RESET THE DOM */ | ||
+ | unload: function() { | ||
+ | $(this.element).siblings('#ms-list-'+ this.listNumber +'.ms-options-wrap').remove(); | ||
+ | $(this.element).show(function(){ | ||
+ | $(this).css('display','').removeClass('jqmsLoaded'); | ||
+ | }); | ||
+ | }, | ||
+ | |||
+ | /* RELOAD JQ MULTISELECT LIST */ | ||
+ | reload: function() { | ||
+ | // remove existing options | ||
+ | $(this.element).siblings('#ms-list-'+ this.listNumber +'.ms-options-wrap').remove(); | ||
+ | $(this.element).removeClass('jqmsLoaded'); | ||
+ | |||
+ | // load element | ||
+ | this.load(); | ||
+ | }, | ||
+ | |||
+ | // RESET BACK TO DEFAULT VALUES & RELOAD | ||
+ | reset: function() { | ||
+ | var defaultVals = []; | ||
+ | $(this.element).find('option').each(function(){ | ||
+ | if( $(this).prop('defaultSelected') ) { | ||
+ | defaultVals.push( $(this).val() ); | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | $(this.element).val( defaultVals ); | ||
+ | |||
+ | this.reload(); | ||
+ | }, | ||
+ | |||
+ | disable: function( status ) { | ||
+ | status = (typeof status === 'boolean') ? status : true; | ||
+ | $(this.element).prop( 'disabled', status ); | ||
+ | $(this.element).siblings('#ms-list-'+ this.listNumber +'.ms-options-wrap').find('button:first-child') | ||
+ | .prop( 'disabled', status ); | ||
+ | }, | ||
+ | |||
+ | /** PRIVATE FUNCTIONS **/ | ||
+ | // update the un/select all texts based on selected options and visibility | ||
+ | _updateSelectAllText: function(){ | ||
+ | if( !this.updateSelectAll ) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | var instance = this; | ||
+ | |||
+ | // select all not used at all so just do nothing | ||
+ | if( !instance.options.selectAll && !instance.options.selectGroup ) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | var optionsWrap = $(instance.element).siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> .ms-options'); | ||
+ | |||
+ | // update un/select all text | ||
+ | optionsWrap.find('.ms-selectall').each(function(){ | ||
+ | var unselected = $(this).parent().find('li:not(.optgroup,.selected,.ms-hidden)'); | ||
+ | |||
+ | $(this).text( | ||
+ | unselected.length ? instance.options.texts.selectAll : instance.options.texts.unselectAll | ||
+ | ); | ||
+ | }); | ||
+ | }, | ||
+ | |||
+ | // update selected placeholder text | ||
+ | _updatePlaceholderText: function(){ | ||
+ | if( !this.updatePlaceholder ) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | var instance = this; | ||
+ | var select = $(instance.element); | ||
+ | var selectVals = select.val() ? select.val() : []; | ||
+ | var placeholder = select.siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> button:first-child'); | ||
+ | var placeholderTxt = placeholder.find('span'); | ||
+ | var optionsWrap = select.siblings('#ms-list-'+ instance.listNumber +'.ms-options-wrap').find('> .ms-options'); | ||
+ | |||
+ | // if there are disabled options get those values as well | ||
+ | if( select.find('option:selected:disabled').length ) { | ||
+ | selectVals = []; | ||
+ | select.find('option:selected').each(function(){ | ||
+ | selectVals.push( $(this).val() ); | ||
+ | }); | ||
+ | } | ||
+ | |||
+ | // get selected options | ||
+ | var selOpts = []; | ||
+ | for( var key in selectVals ) { | ||
+ | // Prevent prototype methods injected into options from being iterated over. | ||
+ | if( !selectVals.hasOwnProperty( key ) ) { | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | selOpts.push( | ||
+ | $.trim( select.find('option[value="'+ instance._escapeSelector( selectVals[ key ] ) +'"]').text() ) | ||
+ | ); | ||
+ | |||
+ | if( selOpts.length >= instance.options.maxPlaceholderOpts ) { | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // UPDATE PLACEHOLDER TEXT WITH OPTIONS SELECTED | ||
+ | placeholderTxt.text( selOpts.join( ', ' ) ); | ||
+ | |||
+ | if( selOpts.length ) { | ||
+ | optionsWrap.closest('.ms-options-wrap').addClass('ms-has-selections'); | ||
+ | |||
+ | // USER CALLBACK | ||
+ | if( typeof instance.options.onPlaceholder == 'function' ) { | ||
+ | instance.options.onPlaceholder( instance.element, placeholderTxt, selOpts ); | ||
+ | } | ||
+ | } | ||
+ | else { | ||
+ | optionsWrap.closest('.ms-options-wrap').removeClass('ms-has-selections'); | ||
+ | } | ||
+ | |||
+ | // replace placeholder text | ||
+ | if( !selOpts.length ) { | ||
+ | placeholderTxt.text( instance.options.texts.placeholder ); | ||
+ | } | ||
+ | // if copy is larger than button width use "# selected" | ||
+ | else if( (placeholderTxt.width() > placeholder.width()) || (selOpts.length != selectVals.length) ) { | ||
+ | placeholderTxt.text( selectVals.length + instance.options.texts.selectedOptions ); | ||
+ | } | ||
+ | }, | ||
+ | |||
+ | // Add option to the custom dom list | ||
+ | _addOption: function( container, option ) { | ||
+ | var instance = this; | ||
+ | var optionNameText = $('<div/>').html( option.name ).text(); | ||
+ | |||
+ | var thisOption = $('<label/>', { | ||
+ | for : 'ms-opt-'+ msOptCounter | ||
+ | }).html( option.name ); | ||
+ | |||
+ | var thisCheckbox = $('<input>', { | ||
+ | type : 'checkbox', | ||
+ | title: optionNameText, | ||
+ | id : 'ms-opt-'+ msOptCounter, | ||
+ | value: option.value | ||
+ | }); | ||
+ | |||
+ | // add user defined attributes | ||
+ | if( option.hasOwnProperty('attributes') && Object.keys( option.attributes ).length ) { | ||
+ | thisCheckbox.attr( option.attributes ); | ||
+ | } | ||
+ | |||
+ | if( option.checked ) { | ||
+ | container.addClass('default selected'); | ||
+ | thisCheckbox.prop( 'checked', true ); | ||
+ | } | ||
+ | |||
+ | thisOption.prepend( thisCheckbox ); | ||
+ | |||
+ | var searchTerm = ''; | ||
+ | if( instance.options.searchOptions.searchText ) { | ||
+ | searchTerm += ' ' + optionNameText.toLowerCase(); | ||
+ | } | ||
+ | if( instance.options.searchOptions.searchValue ) { | ||
+ | searchTerm += ' ' + option.value.toLowerCase(); | ||
+ | } | ||
+ | |||
+ | container.attr( 'data-search-term', $.trim( searchTerm ) ).prepend( thisOption ); | ||
+ | |||
+ | msOptCounter = msOptCounter + 1; | ||
+ | }, | ||
+ | |||
+ | // check ie version | ||
+ | _ieVersion: function() { | ||
+ | var myNav = navigator.userAgent.toLowerCase(); | ||
+ | return (myNav.indexOf('msie') != -1) ? parseInt(myNav.split('msie')[1]) : false; | ||
+ | }, | ||
+ | |||
+ | // escape selector | ||
+ | _escapeSelector: function( string ) { | ||
+ | if( typeof $.escapeSelector == 'function' ) { | ||
+ | return $.escapeSelector( string ); | ||
+ | } | ||
+ | else { | ||
+ | return string.replace(/[!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, "\\$&"); | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // ENABLE JQUERY PLUGIN FUNCTION | ||
+ | $.fn.multiselect = function( options ){ | ||
+ | if( !this.length ) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | var args = arguments; | ||
+ | var ret; | ||
+ | |||
+ | // menuize each list | ||
+ | if( (options === undefined) || (typeof options === 'object') ) { | ||
+ | return this.each(function(){ | ||
+ | if( !$.data( this, 'plugin_multiselect' ) ) { | ||
+ | $.data( this, 'plugin_multiselect', new MultiSelect( this, options ) ); | ||
+ | } | ||
+ | }); | ||
+ | } else if( (typeof options === 'string') && (options[0] !== '_') && (options !== 'init') ) { | ||
+ | this.each(function(){ | ||
+ | var instance = $.data( this, 'plugin_multiselect' ); | ||
+ | |||
+ | if( instance instanceof MultiSelect && typeof instance[ options ] === 'function' ) { | ||
+ | ret = instance[ options ].apply( instance, Array.prototype.slice.call( args, 1 ) ); | ||
+ | } | ||
+ | |||
+ | // special destruct handler | ||
+ | if( options === 'unload' ) { | ||
+ | $.data( this, 'plugin_multiselect', null ); | ||
+ | } | ||
+ | }); | ||
+ | return ret; | ||
+ | } | ||
+ | }; | ||
+ | }(jQuery)); | ||
$(function(){ | $(function(){ | ||
$('select[multiple]').multiselect(); | $('select[multiple]').multiselect(); |
Revision as of 14:49, 2 March 2020
First Name
Last Name
Curriculum
Phone
Email
Role
Spoken Languages
Spoken Languages
Mother Languages
Phone
Free Text