/*
 *	jquery.ecombo 1.0 - 2009-09-28
 *
 *  Create an editable combo box with a given input box.
 *
 *	All the stuff written by pwwang (pwwang.com)	
 *	Feel free to do whatever you want with this file
 *
 */

(function($) {

	$.ecombo = function(input, options) {

		var $input = $(input).attr("autocomplete", "off");
		var $wrap = $(document.createElement("span"));
		var $img = $(document.createElement("img"));
		var $results = $(document.createElement("ul"));
		
		var wrapClass = $input.attr("class");
		var wrapStyle = $input.attr("style");
		
		if(wrapClass) $wrap.addClass(wrapClass);
		if(wrapStyle) $wrap.attr("style",wrapStyle);
		
		var inputCss = {  // inherit the styles about font and text
			'color' 			: $input.css('color'),
			'height' 			: $input.height() + 'px',
			'width'				: ($input.width()-20) + 'px',
			'border' 			: 'none',
			'font-family' 		: $input.css('font-family'),
			'font-size' 		: $input.css('font-size'),
			'font-weight' 		: $input.css('font-weight'),
			'font-size-adjust' 	: $input.css('font-size-adjust'),
			'font-weight' 		: $input.css('font-weight'),
			'font-stretch' 		: $input.css('font-stretch'),
			'text-decoration' 	: $input.css('text-decoration'),
			'text-underline-position' : $input.css('text-underline-position'),
			'text-shadow' 		: $input.css('text-shadow'),
			'font-variant' 		: $input.css('font-variant'),
			'text-transform' 	: $input.css('text-transform'),
			'letter-spacing' 	: $input.css('letter-spacing'),
			'word-spacing' 		: $input.css('word-spacing'),
			'text-align'	 	: $input.css('text-align'),
			'vertical-align'	: 'middle',
			'line-height'		: $input.css('line-height')
			
		};
		
		$wrap.css({
			'padding' : '1px', 
			'vertical-align' : 'middle',
			'display' : 'table-cell'  // do not support ie6?
		});		
		
		$results
			.addClass(options.listClass)
			.css('width',$input.width()+'px')
			.appendTo('body');
		
		$input
			.removeAttr("class")
			.removeAttr("style")
			.css(inputCss)
			.wrap($wrap)
			.blur(hideItems)
			.focus(function(){
				$(this).select();					  
			})
			.dblclick(ecombo);
			
		$img
			.attr({'src' : options.downImg, 'valign' : 'absmiddle'})
			.css({'cursor' : 'pointer', 'vertical-align' : 'middle', 'padding' : '1px'})
			.insertAfter($input)
			.one('click',ecombo);
			
		resetPosition();
		$(window)
			.load(resetPosition)		// just in case user is changing size of page while loading
			.resize(resetPosition);
			
		// help IE users if possible
		try {
			$results.bgiframe();
		} catch(e) { }


		if ($.browser.mozilla){
			$input.keypress(processKey);	// onkeypress repeats arrow keys in Mozilla/Opera
			$img.keypress(processKey);
		} else {
			$input.keydown(processKey);		// onkeydown repeats arrow keys in IE/Safari
			$img.keydown(processKey);
		}

		function resetPosition() {
			// requires jquery.dimension plugin
			var offset = $input.offset();
			$results.css({
				top: (offset.top + 2 + $input.height()) + 'px',
				left: (offset.left - 2) + 'px'
			});
		}
		
		function processKey(e) {
			
			// handling up/down/escape requires results to be visible
			// handling enter/tab requires that AND a result to be selected
			if ((/27$|38$|40$/.test(e.keyCode) && $results.is(':visible')) ||
				(/^13$|^9$/.test(e.keyCode) && getCurrentResult()) ||
				(e.keyCode == 40 && $results.is(':hidden'))) {
				
				if (e.preventDefault)
					e.preventDefault();
				if (e.stopPropagation)
					e.stopPropagation();

				e.cancelBubble = true;
				e.returnValue = false;
			
				switch(e.keyCode) {
					case 38: // up
						prevResult();
						break;
					case 40: // down
						if($results.is(':visible'))
							nextResult();
						else
							ecombo();
						break;
					case 9:  // tab
					case 13: // return
						selectCurrentResult();
						break;
					case 27: //	escape
						hideItems();
						break;
				}
			} 			
		}
		
		function hideItems(){
			$results.slideUp('fast');
			$img.attr("src",options.downImg);
			setTimeout(function(){$img.one('click',ecombo)},200);
		}
		
		function ecombo() {
			var items = options.source.split(options.delimiter);
			$input.focus();
			displayItems(items);
		}
		
		function displayItems(items) {			
			if (!items)	return;				
			if (!items.length) {
				$results.hide();
				return;
			}			
			var html = '';
			for (var i = 0; i < items.length; i++)
				html += '<li>' + items[i] + '</li>';
			$results.html(html).slideDown('fast');
			$img.attr("src",options.upImg);
			$results.children('li').each(function(){
					$(this).mouseover(function() {
						$results.children('li').removeClass(options.selectClass);
						$(this).addClass(options.selectClass);
					})
					.click(function(e) {
						e.preventDefault(); 
						e.stopPropagation();
						selectCurrentResult();
					});
					if($(this).html() == $input.val())
						$(this).mouseover();
				});
		}
		
		function getCurrentResult() {	
			if (!$results.is(':visible')) return false;		
			var $currentResult = $results.children('li.' + options.selectClass);			
			if (!$currentResult.length)
				$currentResult = false;				
			return $currentResult;
		}
		
		function selectCurrentResult() {		
			$currentResult = getCurrentResult();		
			if ($currentResult) {
				if(options.addMode)
					$input.val($input.val()+$currentResult.text());
				else
					$input.val($currentResult.text());
				hideItems();					
			}		
		}
		
		function nextResult() {		
			$currentResult = getCurrentResult();		
			if ($currentResult){
				$currentResult.removeClass(options.selectClass);
				if ($currentResult.is(":last-child"))
					$results.children('li:first-child').addClass(options.selectClass);
				else
					$currentResult.next().addClass(options.selectClass);	
			} else
				$results.children('li:first-child').addClass(options.selectClass);	
		}
		
		function prevResult() {
			$currentResult = getCurrentResult();	
			if ($currentResult) {
				$currentResult.removeClass(options.selectClass);
				if($currentResult.is(":first-child"))
					hideItems();
				else
					$currentResult.prev().addClass(options.selectClass);
			} else
				hideItems();
		}
	}
	$.fn.ecombo = function(source, options) {
		if (!source) return;
		options = options || {};
		options.source = source;
		options.listClass = options.listClass || 'pwwang_com_list';
		options.selectClass = options.selectClass || 'pwwang_com_over';
		options.delimiter = options.delimiter || ';';
		options.downImg = options.downImg || "images/down.gif";
		options.upImg = options.upImg || "images/up.gif";
		options.addMode = options.addMode || false;
		this.each(function() {
			new $.ecombo(this, options);
		});
		return this;	
	};
})(jQuery);

