/*
// 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 = '';
return html;
}
// render the html for the options/optgroups
function renderOptions(id, options, o)
{
var html = "";
for(var i = 0; i < options.length; i++) {
if(options[i].optgroup) {
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);