/* jQuery selectBox (version 1.0.7) A cosmetic, styleable replacement for SELECT elements. Homepage: http://abeautifulsite.net/blog/2011/01/jquery-selectbox-plugin/ Demo page: http://labs.abeautifulsite.net/projects/js/jquery/selectBox/ Copyright 2011 Cory LaViska for A Beautiful Site, LLC. Features: - Supports OPTGROUPS - Supports standard dropdown controls - Supports multi-select controls (i.e. multiple="multiple") - Supports inline controls (i.e. size="5") - Fully accessible via keyboard - Shift + click (or shift + enter) to select a range of options in multi-select controls - Type to search when the control has focus - Auto-height based on the size attribute (to use, omit the height property in your CSS!) - Tested in IE7-IE9, Firefox 3-4, recent webkit browsers, and Opera License: Licensed under both the MIT license and the GNU GPLv2 (same as jQuery: http://jquery.org/license) Usage: Link to the JS file: Add the CSS file (or append contents to your own stylesheet): To create: $("SELECT").selectBox([settings]); Settings: To specify settings, use this syntax: $("SELECT").selectBox('settings', { settingName: value, ... }); menuTransition: ['default', 'slide', 'fade'] - the show/hide transition for dropdown menus menuSpeed: [integer, 'slow', 'normal', 'fast'] - the show/hide transition speed Methods: To call a method use this syntax: $("SELECT").selectBox('methodName', [options]); create - Creates the control (default method) destroy - Destroys the selectBox control and reverts back to the original form control disable - Disables the control (i.e. disabled="disabled") enable - Enables the control value - if passed with a value, sets the control to that value; otherwise returns the current value options - pass in either a string of HTML or a JSON object to replace the existing options control - returns the selectBox control element (an anchor tag) for working with directly Events: Events are fired on the original select element. You can bind events like this: $("SELECT").selectBox().change( function() { alert( $(this).val() ); } ); focus - Fired when the control gains focus blur - Fired when the control loses focus change - Fired when the value of a control changes Change Log: v1.0.0 (2011-04-03) - Complete rewrite with added support for inline and multi-select controls v1.0.1 (2011-04-04) - Fixed options method so it doesn't destroy/recreate the control when called. - Added a check for iOS devices (their native controls are much better for touch-based devices; you can still use selectBox API methods for theme) - Fixed issue where IE window would lose focus on XP - Fixed premature selection issue in Webkit browsers v1.0.2 (2011-04-13) - Fixed auto-height for inline controls when control is invisible on load - Removed auto-width for dropdown and inline controls; now relies 100% on CSS for setting the width - Added 'control' method for working directly with the selectBox control v1.0.3 (2011-04-22) - Fixed bug in value method that errored if the control didn't exist v1.0.4 (2011-04-22) - Fixed bug where controls without any options would render with incorrect heights v1.0.5 (2011-04-22) - Removed 'tick' image in lieu of background colors to indicate selection - Clicking no longer toggles selected/unselected in multi-selects; use CTRL/CMD and SHIFT like in normal browser controls - Fixed bug where inline controls would not receive focus unless tabbed into v1.0.6 (2011-04-29) - Fixed bug where inline controls could be "dragged" when selecting an empty area v1.0.7 (2011-05-18) - Expanded iOS check to include Android devices as well - Added autoWidth option; set to false on init to use CSS widths for dropdown menus Known Issues: - The blur and focus callbacks are not very reliable in IE7. The change callback works fine. */ if(jQuery) (function($) { $.extend($.fn, { selectBox: function(method, data) { var typeTimer, typeSearch = ''; // // Private methods // var init = function(select, data) { // Disable for iOS devices (their native controls are more suitable for a touch device) if( navigator.userAgent.match(/iPad|iPhone|Android/i) ) return false; // Element must be a select control if( select.tagName.toLowerCase() !== 'select' ) return false; select = $(select); if( select.data('selectBox-control') ) return false; var control = $(''), inline = select.attr('multiple') || parseInt(select.attr('size')) > 1; var settings = data || {}; if( settings.autoWidth === undefined ) settings.autoWidth = true; // Inherit class names, style, and title attributes control .addClass(select.attr('class')) .attr('style', select.attr('style') || '') .attr('title', select.attr('title') || '') .attr('tabindex', parseInt(select.attr('tabindex'))) .css('display', 'inline-block') .bind('focus.selectBox', function() { if( this !== document.activeElement ) $(document.activeElement).blur(); if( control.hasClass('selectBox-active') ) return; control.addClass('selectBox-active'); select.trigger('focus'); }) .bind('blur.selectBox', function() { if( !control.hasClass('selectBox-active') ) return; control.removeClass('selectBox-active'); select.trigger('blur'); }); if( select.attr('disabled') ) control.addClass('selectBox-disabled'); // Generate control if( inline ) { // // Inline controls // var options = getOptions(select, 'inline'); control .append(options) .data('selectBox-options', options) .addClass('selectBox-inline') .addClass('selectBox-menuShowing') .bind('keydown.selectBox', function(event) { handleKeyDown(select, event); }) .bind('keypress.selectBox', function(event) { handleKeyPress(select, event); }) .bind('mousedown.selectBox', function(event) { if( $(event.target).is('A.selectBox-inline') ) event.preventDefault(); if( !control.hasClass('selectBox-focus') ) control.focus(); }) .insertAfter(select); // Auto-height based on size attribute if( !select[0].style.height ) { var size = select.attr('size') ? parseInt(select.attr('size')) : 5; // Draw a dummy control off-screen, measure, and remove it var tmp = control .clone() .removeAttr('id') .css({ position: 'absolute', top: '-9999em' }) .show() .appendTo('body'); tmp.find('.selectBox-options').html('
  • \u00A0
  • '); optionHeight = parseInt(tmp.find('.selectBox-options A:first').html(' ').outerHeight()); tmp.remove(); control.height(optionHeight * size); } disableSelection(control); } else { // // Dropdown controls // var label = $(''), arrow = $(''); label.text( $(select).find('OPTION:selected').text() || '\u00A0' ); var options = getOptions(select, 'dropdown'); options.appendTo('BODY'); control .data('selectBox-options', options) .addClass('selectBox-dropdown') .append(label) .append(arrow) .bind('mousedown.selectBox', function(event) { if( control.hasClass('selectBox-menuShowing') ) { hideMenus(); } else { event.stopPropagation(); // Webkit fix to prevent premature selection of options options.data('selectBox-down-at-x', event.screenX).data('selectBox-down-at-y', event.screenY); showMenu(select); } }) .bind('keydown.selectBox', function(event) { handleKeyDown(select, event); }) .bind('keypress.selectBox', function(event) { handleKeyPress(select, event); }) .insertAfter(select); disableSelection(control); } // Store data for later use and show the control select .addClass('selectBox') .data('selectBox-control', control) .data('selectBox-settings', settings) .hide(); }; var getOptions = function(select, type) { var options; switch( type ) { case 'inline': options = $('