
/**
 * The emptyText function will take care of 
 * specialized "Enter something here" behavior 
 * for form fields.  It will make sure the text 
 * is displaying when the field is empty and 
 * gone when the user clicks on it to enter 
 * something.  
 * 
 * Here's how to use this function:
 * 
 * <input 
 *    id="date"                  [optional]
 *    name="date"                [optional]
 *    value="{$date}"            [optional]
 *    class="normalclass"        [optional]
 *    emptyvalue="Enter date"    [required]
 *    emptyclass="grayedout"     [optional]
 *  />
 * <script>emptyText()</script>
 * 
 * Notice the two extra non-standard attributes,
 * emptyvalue and emptyclass.  These specify the 
 * text and class that will be given to the 
 * field when it is empty.  Like the class 
 * attribute, emptyclass may include more than 
 * one class.  If emptyclass is not specified, 
 * the class will not change when the field is 
 * empty.
 * 
 * You can optionally pass an argument to the 
 * emptyText function that is an id or a 
 * reference to the element you wish to effect.  
 * This can be useful for dynamically created 
 * elements or to avoid ambiguity.  If you don't 
 * pass any arguments to the emptyText function, 
 * it will search backward from the <script> 
 * element for an <input> element.  It is 
 * recommended keep the  <script> element close 
 * to the <input> element.  
 * 
 * It has the added benefit that if a field 
 * contains the empty text when the 
 * form is submitted, the empty text won't get 
 * sent to the server. This  relieves the form 
 * handling code from having to check for the 
 * empty text.
 * 
 * This should almost always "just work".  One 
 * exception is if you want to clear the input 
 * element from javascript.  Instead of setting 
 * input.value = '', use input.clear().  That 
 * will ensure the empty text is  showing after 
 * the input is cleared.
 * 
 * Requires prototype.js
 * 
 * @author Russ Black
 * 
 */

 // Use a function to create a namespace to prevent name collisions 
 // with other libraries
(function() {

// define it with bouncyCase and lowercase.
emptyText = emptytext = function(input)
{
	if (!input)
	{
		input = findLastInput()
	}
	input = $(input)
	if (input.emptytext) 
	{
		// this element has already been styled.
		return 
	}
	
	// make a new input element to hold the empty text. Leave it anonymous
	// (no "name" attribute) so it won't get submitted with the form.
	var emptytext = document.createElement('input')
	
	// give it the appropriate class
	if (input.hasAttribute('emptyclass')) 
	{
		emptytext.className = input.getAttribute('emptyclass')
	}
	else 
	{
		emptytext.className = input.className
	}
	
	if (input.hasAttribute("id"))
	{
		emptytext.id=input.id+'-emptytext'
	}
	
	// copy size attribute
	if (input.hasAttribute('size'))
	{
		emptytext.size=input.getAttribute('size')
	}
	
	// populate it an empty value
	if (input.hasAttribute('emptyvalue'))
	{
		emptytext.value=input.getAttribute('emptyvalue')
	}

	// insert emptytext before input
	input.parentNode.insertBefore(emptytext,input)
	
	// give input a reference to its emptytext
	input.emptytext = emptytext
	
	// assume it doesn't currently have focus
	input.hasFocus = false 
	
	// wrap prototype's clear function so we can catch this event and treat it like an empty blur
	input.oldclear=input.clear
	input.clear = function() {
		var r = input.oldclear();
		if (!input.hasFocus) onBlur(input);
		return r
	}
	
	// wrap focus function so we can trap the event
	input.oldfocus = input.focus
	input.focus = function() {
		onFocus(input)
		input.oldfocus()
	}
	
	// add focus listeners
	Event.observe(input,'blur',function() {onBlur(input)})
	Event.observe(input,'focus',function() {onFocus(input)})
	Event.observe(emptytext,'focus',function() {input.focus()})
	
	emptyTextFields.push(input)
	var len = emptyTextFields.length
	
	// set initial state
	onBlur(input)

	// schedule a css scan
	setTimeout(function(){
		if (len == emptyTextFields.length) 
		{
			scanAllCss()
		}
	},500)
}

Event.observe(window, 'load', scanAllCss)
var emptyTextFields = new Array()

/**
 * Called when focus leaves the input field.  Shows the empty text if the input 
 * field is empty
 */
function onBlur(input)
{
	if (input.value.length == 0)
	{
		input.emptytext.style.display=''
		input.style.display='none'
	}
	else
	{
		input.emptytext.style.display='none'
		input.style.display=''
	}
	input.hasFocus=false
}

/**
 * Called when the input field receives focus.  Hides the empty text, shows input field
 */
function onFocus(input)
{
	input.emptytext.style.display='none'
	input.style.display=''
	input.hasFocus=true
}

/**
 * This function looks for any id-specific css selectors on the emptytext 
 * fields and adds corresponding css rules for the emptytext fields.
 * This allows css designers to style at the ID level and still have the 
 * emptytext field look right.  
 */
function scanAllCss()
{	
	// see if any of our fields have an id.  If not, we can 
	// skip this step.
	var hasId = false
	for(var j=0; j<emptyTextFields.length; j++)
	{
		var field = emptyTextFields[j]
		if (field.hasAttribute("id"))
		{
			hasId = true
			break
		}
	}
	if (hasId)
	{
		for (var i=0; i<document.styleSheets.length; i++)
		{
			var ss=document.styleSheets[i]
			scanCss(ss)
		}
	}
}

function scanCss(ss)
{
	try
	{
		// scan imports
		if (ss.imports)
		{
			for(var i=0; i<ss.imports.length; i++)
			{
				scanCss(ss.imports[i])
			}
		}
		
		var rules;
		if (typeof(ss.cssRules) != "undefined") rules = ss.cssRules; // ff and safari
		else if (typeof(ss.rules) != "undefined") rules = ss.rules; // ID
		if (typeof(rules) != "undefined") 
		{
			for(var i=0; i<rules.length; i++)
			{
				var rule = rules[i]
				
				if (rule.styleSheet) // imported style sheet
				{
					scanCss(rule.styleSheet)
				}
				else
				{
					for(var j=0; j<emptyTextFields.length; j++)
					{
						var field = emptyTextFields[j]
						if (field.hasAttribute("id"))
						{
							var id=field.id
							var rex = new RegExp("#"+id+"([^a-zA-Z0-9_-]|$)")
							
							if (rule.selectorText && rule.selectorText.search(rex)>=0 && rule.selectorText.indexOf("-emptytext") == -1)
							{
								var newRule = rule.selectorText.replace(rex,"#"+id+"-emptytext") + '{' + rule.style.cssText + '}'

								addCss(newRule)
							}
						}
					}
				}
			}
		}
	}
	catch(e)
	{
		//console.log("Caught " + e)
	}
}

function addCss(cssCode) {
	var styleElement = document.createElement("style");
	styleElement.type = "text/css";
	if (styleElement.styleSheet) {
		styleElement.styleSheet.cssText = cssCode;
	} else {
		styleElement.appendChild(document.createTextNode(cssCode));
	}
	document.getElementsByTagName("head")[0].appendChild(styleElement);
}

function findLastInput()
{
	var elem = document.body.lastChild
	while (elem)
	{
		if (elem.tagName.toLowerCase() == "script")
		{
			return findPreviousEmptyTextInput(elem)
		}
		elem = elem.lastChild
	}
	return null
}

function findPreviousTerminalNode(node)
{
	if (node.previousSibling)
	{
		node = node.previousSibling
		while (node.lastChild) node = node.lastChild
		return node
	}
	else if (node.parentNode) return findPreviousTerminalNode(node.parentNode)
	else return null
}

function findPreviousEmptyTextInput(elem)
{
	var node = $(findPreviousTerminalNode(elem))
	while (node && !(node.tagName && node.tagName.toLowerCase() == "input" && node.hasAttribute("emptyvalue")))
	{
		node = $(findPreviousTerminalNode(node))
	}
	return node
}

})() // end wrap


