/* // jQuery multiSelect // // Version 1.2.2 beta // // Cory S.N. LaViska // A Beautiful Site (http://abeautifulsite.net/) // 09 September 2009 // // Visit http://abeautifulsite.net/notebook/62 for more information // // (Amended by Andy Richmond, Letters & Science Deans' Office, University of California, Davis) // // Usage: $('#control_id').multiSelect( options, callback ) // // Options: selectAll - whether or not to display the Select All option; true/false, default = true // selectAllText - text to display for selecting/unselecting all options simultaneously // noneSelected - text to display when there are no selected items in the list // oneOrMoreSelected - text to display when there are one or more selected items in the list // (note: you can use % as a placeholder for the number of items selected). // Use * to show a comma separated list of all selected; default = '% selected' // optGroupSelectable - whether or not optgroups are selectable if you use them; true/false, default = false // listHeight - the max height of the droptdown options // // Dependencies: jQuery 1.2.6 or higher (http://jquery.com/) // // Change Log: // // 1.0.1 - Updated to work with jQuery 1.2.6+ (no longer requires the dimensions plugin) // - Changed $(this).offset() to $(this).position(), per James' and Jono's suggestions // // 1.0.2 - Fixed issue where dropdown doesn't scroll up/down with keyboard shortcuts // - Changed '$' in setTimeout to use 'jQuery' to support jQuery.noConflict // - Renamed from jqueryMultiSelect.* to jquery.multiSelect.* per the standard recommended at // http://docs.jquery.com/Plugins/Authoring (does not affect API methods) // // 1.0.3 - Now uses the bgiframe plugin (if it exists) to fix the IE6 layering bug. // - Forces IE6 to use a min-height of 200px (this needs to be added to the options) // // 1.1.0 - Added the ability to update the options dynamically via javascript: multiSelectOptionsUpdate(JSON) // - Added a title that displays the whole comma delimited list when using oneOrMoreSelected = * // - Moved some of the functions to be closured to make them private // - Changed the way the keyboard navigation worked to more closely match how a standard dropdown works // - ** by Andy Richmond ** // // 1.2.0 - Added support for optgroups // - Added the ability for selectable optgroups (i.e. select all for an optgroup) // - ** by Andy Richmond ** // // 1.2.1 - Fixed bug where input text overlapped dropdown arrow in IE (i.e. when using oneOrMoreSelected = *) // - Added option "listHeight" for min-height of the dropdown // - Fixed bug where bgiframe was causing a horizontal scrollbar and on short lists extra whitespace below the options // - ** by Andy Richmond ** // // 1.2.2 - Fixed bug where the keypress stopped showing the dropdown because in jQuery 1.3.2 they changed the way ':visible' works // - Fixed some other bugs in the way the keyboard interface worked // - Changed the main textbox to an tag (with 'display: inline-block') to prevent the display text from being selected/highlighted // - Added the ability to jump to an option by typing the first character of that option (simular to a normal drop down) // - ** by Andy Richmond ** // - Added [] to make each control submit an HTML array so $.serialize() works properly // // Licensing & Terms of Use // // This plugin is dual-licensed under the GNU General Public License and the MIT License and // is copyright 2008 A Beautiful Site, LLC. // */ if(jQuery) (function($){ // render the html for a single option function renderOption(id, option) { var html = ''; html += ''; $(select).after(html); var multiSelect = $(select).next('.multiSelect'); var multiSelectOptions = multiSelect.next('.multiSelectOptions'); // if the select object had a width defined then match the new multilsect to it multiSelect.find("span").css("width", $(select).width() + 'px'); // Attach the config options to the multiselect multiSelect.data("config", o); // Attach the callback to the multiselect multiSelect.data("callback", callback); // Serialize the select options into json options var options = []; $(select).children().each( function() { if(this.tagName.toUpperCase() == 'OPTGROUP') { var suboptions = []; options.push({ optgroup: $(this).attr('label'), options: suboptions }); $(this).children('OPTION').each( function() { if( $(this).val() != '' ) { suboptions.push({ text: $(this).html(), value: $(this).val(), selected: $(this).attr('selected') }); } }); } else if(this.tagName.toUpperCase() == 'OPTION') { if( $(this).val() != '' ) { options.push({ text: $(this).html(), value: $(this).val(), selected: $(this).attr('selected') }); } } }); // Eliminate the original form element $(select).remove(); // Add the id that was on the original select element to the new input multiSelect.attr("id", $(select).attr("id")); // Build the dropdown options buildOptions.call(multiSelect, options); // Events multiSelect.hover( function() { $(this).addClass('hover'); }, function() { $(this).removeClass('hover'); }).click( function() { // Show/hide on click if( $(this).hasClass('active') ) { $(this).multiSelectOptionsHide(); } else { $(this).multiSelectOptionsShow(); } return false; }).focus( function() { // So it can be styled with CSS $(this).addClass('focus'); }).blur( function() { // So it can be styled with CSS $(this).removeClass('focus'); }); // Add an event listener to the window to close the multiselect if the user clicks off $(document).click( function(event) { // If somewhere outside of the multiselect was clicked then hide the multiselect if(!($(event.target).parents().andSelf().is('.multiSelectOptions'))){ multiSelect.multiSelectOptionsHide(); } }); }); }, // Update the dropdown options multiSelectOptionsUpdate: function(options) { buildOptions.call($(this), options); }, // Hide the dropdown multiSelectOptionsHide: function() { $(this).removeClass('active').removeClass('hover').next('.multiSelectOptions').css('visibility', 'hidden'); }, // Show the dropdown multiSelectOptionsShow: function() { var multiSelect = $(this); var multiSelectOptions = multiSelect.next('.multiSelectOptions'); var o = multiSelect.data("config"); // Hide any open option boxes $('.multiSelect').multiSelectOptionsHide(); multiSelectOptions.find('LABEL').removeClass('hover'); multiSelect.addClass('active').next('.multiSelectOptions').css('visibility', 'visible'); multiSelect.focus(); // reset the scroll to the top multiSelect.next('.multiSelectOptions').scrollTop(0); // Position it var offset = multiSelect.position(); multiSelect.next('.multiSelectOptions').css({ top: offset.top + $(this).outerHeight() + 'px' }); multiSelect.next('.multiSelectOptions').css({ left: offset.left + 'px' }); }, // get a coma-delimited list of selected values selectedValuesString: function() { var selectedValues = ""; $(this).next('.multiSelectOptions').find('INPUT:checkbox:checked').not('.optGroup, .selectAll').each(function() { selectedValues += $(this).attr('value') + ","; }); // trim any end comma and surounding whitespace return selectedValues.replace(/\s*\,\s*$/,''); } }); // add a new ":startsWith" search filter $.expr[":"].startsWith = function(el, i, m) { var search = m[3]; if (!search) return false; return eval("/^[/s]*" + search + "/i").test($(el).text()); }; })(jQuery);