$.fn.hintText = function() {
	
	function fixIE(el) {
		var $this = $(el);
		var clone = $("<input type='text' />");
		clone.insertBefore($this).attr({
			'class': $this.attr('class') + ' faux-password',
			'style': $this.attr('style'),
			'data-hint': $this.attr('data-hint'),
			'passwordMode': '1'
		}).data('fauxPassword', $this);
		bindEvents(clone, true);
		
		$this.data('fauxPassword', clone);
		
		return clone;
	}
	
	function showHint(e) {
		var $this = $(this),
			oldVal = $this.val(),
			isBlur = e.type === 'blur',
			hint = $this.attr('data-hint'),
			that = $this.data('fauxPassword');
		
		// Exiting field with hint value
		if (isBlur && oldVal === hint) {
			return;
		}

		if (oldVal == '' || oldVal === hint) {
			if ($this.is('input') && $this.attr('type') === 'password') {
				try {
					this.type = 'text';
					$this.attr('passwordMode', '1');
				}
				catch(e) {
					if (typeof that === 'undefined') {
						that = fixIE($this);
					}
					that[0].style.display = '';
					$this[0].style.display = 'none';
					$this = that;
				}
			}

			$this.val(hint);
			$this.removeClass('cleared').addClass('hint-text');
		}
	}
	
	function hideHint(e) {
		var $this = $(this),
			oldVal = $this.val(),
			isBlur = e.type === 'blur',
			hint = $this.attr('data-hint'),
			that = $this.data('fauxPassword');
		
		if (oldVal === hint && $this.hasClass('hint-text')) {
			if ($this.is('input') && typeof $this.attr('passwordMode') !== 'undefined') {
				try {
					this.type = 'password';
				}
				catch(e) {
					that[0].style.display = '';
					that[0].value = '';
					
					$this[0].style.display = 'none';
					
					that[0].focus();
					$this = that;
				}
			}

			$this.val('');
		}
		$this.removeClass('hint-text').addClass('cleared');
	}


	function bindEvents(el, fauxMode) {
		fauxMode = fauxMode || false;
		var $this = $(el),
			form = $this.parents('form'),
			that = $this.data('fauxPassword');
		
		if(typeof $this.data('hintHandlerAdded') !== 'undefined') {
			return;
		}
		$this.data('hintHandlerAdded', true);
		
		$this.blur(showHint).focus(hideHint);	
		
		if (!fauxMode) {
			$this.bind('show-hint', showHint).bind('clear-hint', hideHint);
		}else {
			$this.bind('focusout', function (e) {
				e.stopImmediatePropagation();
			});
		}
		
/* 		$this.attr('autocomplete', 'off'); */
		
		$this.keydown(function (e) {
			if (e.which === 27) {
				e.preventDefault();
				e.stopPropagation();
			}
		});
		
		if (typeof form.data('hintHandlerAdded') === 'undefined') {
			form.bind('submit clear-hints', function (e) {
				$(this).find('input[type=text], input[type=password], textarea').trigger('clear-hint');
			}).bind('reset show-hints', function (e) {
				var $this = $(this);
				setTimeout(function () {
					$this.find('input[type=text], input[type=password], textarea').trigger('show-hint');
				}, 100);
			});
			form.data('hintHandlerAdded', true);
		}
	}

	this.each(function () {
		
		var $this = $(this).removeClass('hint-text cleared');
	
		if ($this.attr('readonly') || $this.attr('disabled')) {
			return;
		}

		// If the field has no data-hint attribute
		if (typeof $this.attr('data-hint') == 'undefined') {
			// No hint, no value, we can't do any good here.
			if ($this.val() == '') {
				return;
			}
			$this.attr('data-hint',  $this.val());
		}
		
		bindEvents($this);
        
		$this.trigger('show-hint');
	});
	
	return this;
};