
/*
 * autoSubWidth v0.1 - jQuery plugin
 * Copyright (c) 2008 Joel Birch
 *
 * Dual licensed under the MIT and GPL licenses:
 * 	http://www.opensource.org/licenses/mit-license.php
 * 	http://www.gnu.org/licenses/gpl.html
 *
 *
 * This plugin automatically adjusts submenu widths of suckerfish-style menus to that of
 * their longest list item children. If you use this, please expect bugs and report them
 * to the jQuery Google Group with the word 'Superfish' in the subject line.
 *
 */

;(function($){ // $ will refer to jQuery within this closure
	
	$.fn.autoSubWidth = function(options){
		var opts = $.extend({}, $.fn.autoSubWidth.defaults, options);
		// cache this jQ object
		var $$ = this;
		// return original object to support chaining
		return this.each(function() {
			// support metadata
			var o = $.meta ? $.extend({}, opts, $$.data()) : opts;
			// cache all ul elements
			$ULs = $$.find('ul');
			
			// loop through ul elements
			$ULs.each(function(i) {
				// get all (li) children of this ul
				var $LIs = $ULs.eq(i).children();
				// get all anchor grand-children
				var $As = $LIs.children('a');
				// remove width-related CSS to prepare for measuring widest content
				$LIs.add($As).css({
					'width'			: 'auto',
					'padding-left'	: 0,
					'padding-right' : 0,
					'text-indent'	: 0
				});
				// declare and init vars used to detect and store li with longest content
				var $longest;
				var longestLength = 0;
				// loop through all (li) children of this ul to find longest
				$LIs.each(function(j) {
					// cache jQ object of this li for use more than once
					var $li = $LIs.eq(j);
					// measure length of text string
					var thisLength = $li.children('a').text().length;
					// if longest then cache reference
					if (thisLength > longestLength){
						longestLength = thisLength;
						$longest = $li;
					}
				});
				// now we know which is longest li in this ul
				// let's find out the width of it in ems:
				// cache anchor of longest li
				var $a = $longest.children('a');
				// cache text content
				var text = $a.text();
				// replace content with an em dash, the width of which should be the px size of the font
				//	 note: must use html() not text() or encoded character is not resolved to em dash,
				//   this unfortunately means that any nested spans will be removed.
				$a.html('&#8212;'); 
				// width of em rule should tell us the font-size in px. We'll use this to work out the width in ems
				var fontsize = $longest.width();
				// replace all spaces found in longest anchor with non-breaking spaces to force onto one line
				$a.html(text.replace(/ /g,'&#160;'));
				// measure width of longest li
				var w = $longest.width();
				// convert longest width from pixels to ems
				var ems = w / fontsize;
				// restrict to at least minWidth and at most maxWidth
				if (ems > o.maxWidth){
					ems = o.maxWidth;
					// set spaces back to regular spaces so text will create new line when maxWidth reached
					$a.html(text);
				} else if (ems < o.minWidth){
					ems = o.minWidth;
				}
				// final width plus desired padding, in em
				var totalWidth = ems+(o.xPadding*2);
				// set width of this ul and all its li children to (longest width + desired padding)
				$ULs.eq(i).add($LIs).css({
					'width' : totalWidth+'em'
				});
				// set width of anchor grand-children and add desired padding
				$As.css({
					'width' 		: ems+'em',
					'padding-left'	: o.xPadding+'em',
					'padding-right'	: o.xPadding+'em'
				});
				// override further nested submenu's positions to account for new width of parent li
				$LIs.each(function(){
					var $childUl = $('>ul',this);
					var offsetDirection = $childUl.css('left')!==undefined ? 'left' : 'right';
					$childUl.css(offsetDirection,totalWidth+'em');
				});
			});
		});
	};
	// expose defaults
	$.fn.autoSubWidth.defaults = {
		xPadding 		: 2,		// requires em unit. This will be applied to left and right of nav item
		minWidth		: 7,		// requires em unit. Total width will be minWidth+(xPadding*2)
		maxWidth		: 30		// requires em unit. Total width will be maxWidth+(xPadding*2)
	};

})(jQuery); // plugin code ends

