/* =================================================================================================

* NiceTitles

* 20th September 2004

* http://neo.dzygn.com/code/nicetitles

*

* NiceTitles turns your boring (X)HTML tags into a dynamic experience

* Modified by Kevin Hale for unfoldedorigami.com use. 

* Nicetitles now works with images, form fields and follows the mouse.

*

* Copyright (c) 2003 - 2004 Stuart Langridge, Paul McLanahan, Peter Janes, 

* Brad Choate, Dunstan Orchard, Ethan Marcotte, Mark Wubben, Kevin Hale

* 

*

* Licensed under MIT - http://www.opensource.org/licenses/mit-license.php

==================================================================================================*/



function NiceTitles(sTemplate, nDelay, nStringMaxLength, nMarginX, nMarginY, sContainerID, sClassName){

	var oTimer;

	var isActive = false;

	var showingAlready = false; //added var to start cursor tracking only AFTER delay occurs in show();

	var sNameSpaceURI = "http://www.w3.org/1999/xhtml";

	

	if(!sTemplate){ sTemplate = "attr(nicetitle)";}

	if(!nDelay || nDelay <= 0){ nDelay = false;}

	if(!nStringMaxLength){ nStringMaxLength = 80; }

	if(!nMarginX){ nMarginX = 15; }

	if(!nMarginY){ nMarginY = 35; }

	if(!sContainerID){ sContainerID = "nicetitlecontainer";}

	if(!sClassName){ sClassName = "nicetitle";}



	var oContainer = document.getElementById(sContainerID);

	if(!oContainer){

		oContainer = document.createElementNS ? document.createElementNS(sNameSpaceURI, "div") : document.createElement("div");

		oContainer.setAttribute("id", sContainerID);

		oContainer.className = sClassName;

		oContainer.style.display = "none";

		document.getElementsByTagName("body").item(0).appendChild(oContainer);

	}

	

	//=====================================================================

	// Method addElements (Public)

	//=====================================================================

	this.addElements = function addElements(collNodes, sAttribute){

		var currentNode, sTitle;

		

		for(var i = 0; i < collNodes.length; i++){

			currentNode = collNodes[i];

		

			sTitle = currentNode.getAttribute(sAttribute);

			if(sTitle){

				currentNode.setAttribute("nicetitle", sTitle);

				currentNode.removeAttribute(sAttribute);

				addEvent(currentNode, 'mouseover', show);

				addEvent(currentNode, 'mouseout', hide);

				addEvent(currentNode, 'mousemove', reposition); //added to allow cursor tracking

				addEvent(currentNode, 'focus', show);

				addEvent(currentNode, 'blur', hide);

				addEvent(currentNode, 'keypress', hide);

				addEvent(currentNode, 'mousedown', hide);

			}

		}



	}

	

	//=====================================================================

	// Other Methods (All Private)

	//=====================================================================

	function show(e){

		if (isActive){ hide(); }

		

		var oNode = window.event ? window.event.srcElement : e.currentTarget;

		if(!oNode.getAttribute("nicetitle")){ 

			while(oNode.parentNode){

				oNode = oNode.parentNode; // immediately goes to the parent, thus we can only have element nodes

				if(oNode.getAttribute("nicetitle")){ break;	}

			}

		}



		var sOutput = parseTemplate(oNode);

		setContainerContent(sOutput);

		var oPosition = getPosition(e, oNode);

		oContainer.style.left = oPosition.x;

		oContainer.style.top = oPosition.y;



		//added showingAlready. cursor tracks only after delay occurs

		if(nDelay){	

			oTimer = setTimeout(function(){oContainer.style.display = "block"; showingAlready = true;}, nDelay);

		} else {

			oContainer.style.display = "block";

		}



		isActive = true;		

		// Let's put this event to a halt before it starts messing things up

		window.event ? window.event.cancelBubble = true : e.stopPropagation();

	}

	

	function hide(){

		clearTimeout(oTimer);

		oContainer.style.display = "none";

		removeContainerContent();

		isActive = false;

		showingAlready = false;

	}

	

	//function added to allow cursor tracking by Kevin Hale

	function reposition(e){

		var oNode = window.event ? window.event.srcElement : e.currentTarget;



		var oPosition = getPosition(e, oNode);

		oContainer.style.left = oPosition.x;

		oContainer.style.top = oPosition.y;

		

		if(showingAlready){

		oContainer.style.display = "block";}

		else{

		oContainer.style.display = "none";}

		

		isActive = true;

		// Let's put this event to a halt before it starts messing things up

		window.event ? window.event.cancelBubble = true : e.stopPropagation();

	}



	function setContainerContent(sOutput){

		sOutput = sOutput.replace(/&/g, "&amp;");

		if(document.createElementNS && window.DOMParser){

			var oXMLDoc = (new DOMParser()).parseFromString("<root xmlns=\""+sNameSpaceURI+"\">"+sOutput+"</root>", "text/xml");

			var oOutputNode = document.importNode(oXMLDoc.documentElement, true);

			var oChild = oOutputNode.firstChild;

			var nextChild;

			while(oChild){

				nextChild = oChild.nextSibling; // Once the child is appended, the nextSibling reference is gone

				oContainer.appendChild(oChild);

				oChild = nextChild;

			}

		} else {

			oContainer.innerHTML = sOutput;

		}

	}

	

	function removeContainerContent(){

		var oChild = oContainer.firstChild;

		var nextChild;



		if(!oChild){ return; }

		while(oChild){

			nextChild = oChild.nextSibling;

			oContainer.removeChild(oChild);

			oChild =  nextChild;

		}

	}

	

	function getPosition(e, oNode){

		var oViewport = getViewport();

		var oCoords;

		var commonEventInterface = window.event ? window.event : e;



		if(commonEventInterface.type == "focus"){

			oCoords = getNodePosition(oNode);	

			oCoords.x += nMarginX;

			oCoords.y += nMarginY;			

		} else {

			oCoords = { x : commonEventInterface.clientX + oViewport.x + nMarginX, y : commonEventInterface.clientY + oViewport.y + nMarginY};

		}

		

		// oContainer needs to be displayed before width and height can be retrieved

		if(showingAlready == false) // if statement prevents flickering in os x firefox when tracking cursor

			{oContainer.style.visiblity = "hidden"; 

			 oContainer.style.display =  "block";}

		var containerWidth = oContainer.offsetWidth;

		var containerHeight = oContainer.offsetHeight;

		if(showingAlready == false)

			{oContainer.style.display = "none"; 

			 oContainer.style.visiblity = "visible";}



		if(oCoords.x + containerWidth + 10 >= oViewport.width + oViewport.x){

			oCoords.x = oViewport.width + oViewport.x - containerWidth - 10;

		}

		if(oCoords.y + containerHeight + 10 >= oViewport.height + oViewport.y){

			oCoords.y = oViewport.height + oViewport.y - containerHeight - oNode.offsetHeight - 10;

		}



		oCoords.x += "px";

		oCoords.y += "px";



		return oCoords;

	}



	function parseTemplate(oNode){

		var sAttribute, collOptionalAttributes;

		var oFound = {};

		var sResult = sTemplate;

		

		if(sResult.match(/content\(\)/)){

			sResult = sResult.replace(/content\(\)/g, getContentOfNode(oNode));

		}

		

		var collSearch = sResult.split(/attr\(/);

		for(var i = 1; i < collSearch.length; i++){

			sAttribute = collSearch[i].split(")")[0];

			oFound[sAttribute] = oNode.getAttribute(sAttribute);

			if(oFound[sAttribute] && oFound[sAttribute].length > nStringMaxLength){

				oFound[sAttribute] = oFound[sAttribute].substring(0, nStringMaxLength) + "...";

			}

		}

		

		var collOptional = sResult.split("?")

		for(var i = 1; i < collOptional.length; i += 2){

			collOptionalAttributes = collOptional[i].split("attr(");

			for(var j = 1; j < collOptionalAttributes.length; j++){

				sAttribute = collOptionalAttributes[j].split(")")[0];



				if(!oFound[sAttribute]){ sResult = sResult.replace(new RegExp("\\?[^\\?]*attr\\("+sAttribute+"\\)[^\\?]*\\?", "g"), "");	}

			}

		}

		sResult = sResult.replace(/\?/g, "");

		

		for(sAttribute in oFound){

			if (oFound[sAttribute] == null || oFound[sAttribute] == ""){oFound[sAttribute] = "Perform a context related search of this term.";		oContainer.setAttribute("id", "yqcontainer");}

			else{oContainer.setAttribute("id", "nicetitlecontainer");}

			sResult = sResult.replace("attr\("+sAttribute+"\)", oFound[sAttribute]);

		}

		//alert(oFound[sAttribute]);

		return sResult;

	}	

		

	function getContentOfNode(oNode){

		var sContent = "";

		var oSearch = oNode.firstChild;



		while(oSearch){

			if(oSearch.nodeType == 3){

				sContent += oSearch.nodeValue;

			} else if(oSearch.nodeType == 1 && oSearch.hasChildNodes){

				sContent += getContentOfNode(oSearch);

			}

			oSearch = oSearch.nextSibling

		}

		return sContent;

	}

	

	function getNodePosition(oNode){

		var x = 0;

		var y = 0;



		do {

			if(oNode.offsetLeft){ x += oNode.offsetLeft }

			if(oNode.offsetTop){ y += oNode.offsetTop }

		}	while((oNode = oNode.offsetParent) && !document.all) // IE gets the offset 'right' from the start



		return {x : x, y : y}

	}

	

	// Idea from 13thParallel: http://13thparallel.net/?issue=2002.06&title=viewport

	function getViewport(){

		var width = 0;

		var height = 0;

		var x = 0;

		var y = 0;

		

		if(document.documentElement && document.documentElement.clientWidth){

			width = document.documentElement.clientWidth;

			height = document.documentElement.clientHeight;

			x = document.documentElement.scrollLeft;

			y = document.documentElement.scrollTop;

		} else if(document.body && document.body.clientWidth){

			width = document.body.clientWidth;

			height = document.body.clientHeight;

			x = document.body.scrollLeft;

			y = document.body.scrollTop;

		}

		// we don't use an else if here, since Opera 7 tends to get the height on the documentElement wrong

		if(window.innerWidth){ 

			width = window.innerWidth - 18;

			height = window.innerHeight - 18;

		}

		

		if(window.pageXOffset){

			x = window.pageXOffset;

			y = window.pageYOffset;

		} else if(window.scrollX){

			x = window.scrollX;

			y = window.scrollY;

		}

		

		return {width : width, height : height, x : x, y : y };		

	}

}



//=====================================================================

// Event Listener

// by Scott Andrew - http://scottandrew.com

// edited by Mark Wubben, <useCapture> is now set to false

//=====================================================================

function addEvent(obj, evType, fn){

	if(obj.addEventListener){

		obj.addEventListener(evType, fn, false); 

		return true;

	} else if (obj.attachEvent){

		var r = obj.attachEvent('on'+evType, fn);

		return r;

	} else {

		return false;

	}

}



//=====================================================================

// Here the default nice titles are created

//=====================================================================

NiceTitles.autoCreation = function(){

	if(!document.getElementsByTagName){ return; }



	NiceTitles.autoCreated = new Object();

	

	NiceTitles.autoCreated.anchors = new NiceTitles("<p class=\"titletext\">attr(nicetitle)</p><p class=\"destination\">attr(href)</p>", 600);

	NiceTitles.autoCreated.acronyms = new NiceTitles("<p class=\"titletext\">content(): attr(nicetitle)</p>", 600);

	//for image nicetitles based off alt tags

	NiceTitles.autoCreated.images = new NiceTitles("<p class=\"destination\">attr(nicetitle)</p>", 600);

	//for form nicetitles. just add title to input and textarea tags

	NiceTitles.autoCreated.input = new NiceTitles("<p class=\"destination\">attr(nicetitle)</p>", 600);

	

		



	NiceTitles.autoCreated.anchors.addElements(document.getElementsByTagName("a"), "title");

	NiceTitles.autoCreated.images.addElements(document.getElementsByTagName("img"), "alt"); //added

	NiceTitles.autoCreated.acronyms.addElements(document.getElementsByTagName("acronym"), "title");

	NiceTitles.autoCreated.acronyms.addElements(document.getElementsByTagName("abbr"), "title");

	NiceTitles.autoCreated.input.addElements(document.getElementsByTagName("input"), "title"); //added

	NiceTitles.autoCreated.input.addElements(document.getElementsByTagName("textarea"), "title"); //added

}



addEvent(window, "load", NiceTitles.autoCreation);
