﻿/*
jquery.fixSelect

Fixes an whereby IE chops long options in a select box with fixed width. It does this by
surrounding the element within a span of the same width with overflow-x set to hidden,
and setting the select width to auto on a mousedown or keyup event then back to its
previous value on blur.

Syntax:

	$jQueryCollection.fixSelect([minWidth]);

The minWidth parameter is optional, but can be used to hard set a width for the elements.
If the result doesn't look quite right, you can use CSS to fix the result: the added span
wrapping the select element has the class "selectFix" to make this possible.

Two custom events are exposed:

	- "initfix" will recompute the natural width of the element; and
	- "applyfix" will resize the select element (e.g. after assigning focus programmatically).

(Merciful heavens, IE should just be taken outside and *shot*. This apparently simple code
involved more obscure bug workarounds than I have time or space to document.)
*/

(function($) {
$.fn.fixSelect = function(minWidth) {
	/* Fix only applies to IE 8 and below. */
	return (!($.browser.msie && $.browser.version < 9)) ? this : this.each(function() {
		if (this.tagName.toLowerCase() == 'select') { // Also only applies to select elements.
			var el = this,
			$this = $(this),
			minWidth = minWidth ? minWidth : el.offsetWidth, // Current width used as minimum.
			elementWidth = $this.outerWidth(),
			$wrapper = $('<span class="selectFix"></span>').css({ // Wraps the select element.
				display: ($this.css('display') == 'block') ? 'block' : 'inline-block',
				cssFloat: $this.css('float'),
				overflowX: 'hidden',
				overflowY: 'visible',
				width: minWidth
			}),
			naturalWidth;

			/* Set up element margins on wrapper instead. (For more complex styles, use CSS.) */
			$.each('marginTop marginRight marginBottom marginLeft'.split(' '), function(i, prop) {
				$wrapper.css(prop, $this.css(prop));
				$this.css(prop, 0);
			});

			if ($this.is(':visible')) { // Doesn't work for invisible elements, they have zero width!
				/* Determine what the "natural" (i.e. automatic) width would be. */
				$this.width('auto');
				naturalWidth = $this.outerWidth();
				$this.width(minWidth);
				$this
					.wrap($wrapper)
					.bind('mousedown keyup applyfix', function() {
					/* Use "auto" or fixed width, whichever is biggest. */
					$this.width((naturalWidth < elementWidth) ? minWidth : 'auto');
					/* Horribly, IE 6 will ignore the overflow anyway unless some part of the
					select element is already hidden before the options list is displayed. */
					if ($.browser.version == 6) $this.css('marginLeft', 1);
				})
				.blur(function() {
					/* Reset the element to fixed width. */
					$this.width(minWidth);
					if ($.browser.version == 6) $this.css('marginLeft', 0);
				})
				.bind('initfix', function() {
					/* Recalculate "natural" width. */
					$this.width('auto');
					naturalWidth = $this.outerWidth();
					$this.width(minWidth);
				});
			}
		}
	});
}
})(jQuery);
