
/***********************************************
* Show Hint script- © Dynamic Drive (www.dynamicdrive.com)
* This notice MUST stay intact for legal use
* Visit http://www.dynamicdrive.com/ for this script and 100s more.
***********************************************
* Dynamic Drive script adapted:
 - popup is positioned automatically depending on size of content and position on page such that it will not run outside of window, nor overlap calling element.
 - styling of popup possible (by applying a class to it)
* by O.P.Gobée
* You are allowed to use this script, provided this notice is included unmodified in all copies.
*
***********************************************
* DEPENDENCIES:
* jQuery library
*
***********************************************

/
/*Logfile PG
29-10-2007 CHG moved onload creation of popUp box to overall window.onload together w. other window.onload's)
30-10-2007 BUG removes setting of onmouseout, killed other mouseouts
30-10-2007 ADD possibility via ehShowhint to be called via E. Dean'es addEvent
5-11-2007 ADD possibilities to set class, shiftHor and offsetTop. All args in objArgs object. Only 1 global var: oPopUp.
6-11-2007 CHG Renamed all to popUpBox. Removed separate width setting in call (double with class). Set essential styling in createpopUpBox. Moved global var ie to local var in func clearbrowseredge. Removed uneffective global var ns6.
11-11-2007 ADD/CHG Major remake: all positioning of popupbox now called by function calcPosPopUp() and handled via 3 main functions: calcPreferredPos(), correctOutsideWindow(), correctOverlapCallingElem().
5-3-2009 CHG adapted to jQuery.
*/		

/*

SHOWS POPUP WINDOW
argument 'objArgs' should be an object with the following optional properties:
- contents: the html/text that should be displayed in the popup [string]
- className: name of the class that should style this popup [string]
- position: mainpos,alignment [one string, comma between mainpos and alignment]
	with:
	mainpos can be: left,right,top,bottom [string]
	alignment can be: center, alignLeft, alignRight, alignTop, alignBottom [string]
- shiftHor: nr of pixels horizontal shift form the postion requested in 'position' [integer]
- shiftVert: nr of pixels vertical shift form the postion requested in 'position' [integer]
- distanceToCallingElem: nr of pixels distance of popup to calling elem [integer]
- distanceToWindow: min. nr of pixels distance of popup to window edge [integer]

Example of use (assuming presence of jQuery library):

$(document).ready(function()
	{
	$("elementsToBeCalledOn").mouseover(function()
		{showPopUp($(this),{contents:"my text to show",className:"whitePopUp",position:"top,center"});
		});
	$("elementsToBeCalledOn").mouseout(hidePopUp); 
	});
	
*/


//create and insert popUpBox div, creates global var popUpBox containing DOM reference to the popUpBox-div
$(document).ready(createAndInsertPopUpBox)

/*niet werkend probeersel
$.popMeUp=function(e,settings)	
	{alert('yes')
	$(this).mouseover(function(e)
		{showPopUp(e.target,settings);
		});
	$(this).mouseout(hidePopUp); 
	}
*/
var popUpBox; //define global
function createAndInsertPopUpBox()
	{//global variable accessed, no 'var'!
	popUpBox=createPopUpBox();
	}
	
function createPopUpBox()
	{var divblock=document.createElement("div")
	divblock.setAttribute("id", "popUpBox")
	var popUpBox=document.body.appendChild(divblock);
	//popUpBox.style.visibility="hidden";
	popUpBox.style.position="absolute";
//	popUpBox.style.zIndex=1000; //set this in local css to allow popup under optiondiv
	return popUpBox;
	}


//own addition to allow linking to Dean Edwards addEvent script
function ehShowPopUp(e,objArgs)
	{var callingElem=this;
	showPopUp(callingElem,objArgs)
	}
	
function showPopUp(callingElem,objArgs)
	{var oPopUp=new Object();
	//defaults
	var defaultClass="popUpDefault";
	var defaultPosition="right,center" // position popUp related to calling Element
	var defaultShiftHor=0 //horizontal shift (in px) from position
	var defaultShiftVert=0 //vertical shift (in px) from position
	var defaultDistanceToCallingElem=10 //distance (in px) of popup from calling element
	var defaultDistanceToWindow=5 //distance (in px) of popup from window-edge
	
	//read objArgs, check if any or valid requests, else set defaults
	var popUpContents=objArgs.contents;
	var className=(typeof objArgs.className!="undefined")? objArgs.className : defaultClass; //default	
	oPopUp.reqPosition=(exists(objArgs.position) && objArgs.position!="")? objArgs.position : defaultPosition; //default	
	oPopUp.shiftHor=(exists(objArgs.shiftHor) && objArgs.shiftHor!="")? parseInt(objArgs.shiftHor) : defaultShiftHor; //default
	oPopUp.shiftVert=(exists(objArgs.shiftVert) && objArgs.shiftVert!="")? parseInt(objArgs.shiftVert) : defaultShiftVert; //default
	oPopUp.distanceToCallingElem=(exists(objArgs.distanceToCallingElem) && objArgs.distanceToCallingElem!="")? parseInt(objArgs.distanceToCallingElem) : defaultDistanceToCallingElem; //default	
	oPopUp.distanceToWindow=(exists(objArgs.distanceToWindow) && objArgs.distanceToWindow!="")? parseInt(objArgs.distanceToWindow) : defaultDistanceToWindow; //default	

	oPopUp.callingElem=callingElem;
	
	if (document.getElementById && document.getElementById("popUpBox"))
		{var popUpBox=document.getElementById("popUpBox");
		popUpBox.innerHTML=popUpContents;
		
		$("#popUpBox").addClass(className);
		
		oPopUp=calcPosPopUp(oPopUp);
		
		popUpBox.style.left= oPopUp.popUpLeft+"px"
		popUpBox.style.top= oPopUp.popUpTop+"px"

//givePopUpDebugInfo(oPopUp)
		
		popUpBox.style.visibility="visible";
		}
	}

function hidePopUp()
	{if(typeof popUpBox != "undefined")
		{popUpBox.style.visibility="hidden"
		popUpBox.style.left="-500px"
		}
	}

function getposOffset(what, offsettype)
	{var totaloffset=(offsettype=="left")? what.offsetLeft : what.offsetTop;
	var parentEl=what.offsetParent;
	while (parentEl!=null)
		{totaloffset=(offsettype=="left")? totaloffset+parentEl.offsetLeft : totaloffset+parentEl.offsetTop;
		parentEl=parentEl.offsetParent;
		}
	return totaloffset;
	}

function iecompattest()
	{return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
	}


function calcPosPopUp(oPopUp) //
    {
	oPopUp=calcPreferredPos(oPopUp);
	oPopUp=correctOutsideWindow(oPopUp);
	//$.log("1",oPopUp)
	oPopUp=correctOverlapCallingElem(oPopUp);
	return oPopUp;
    }	

	
function calcPreferredPos(oPopUp)
	{var callingElem=oPopUp.callingElem; //for ease of reading
	var reqPosition=oPopUp.reqPosition;
	var shiftHor=parseInt(oPopUp.shiftHor);
	var shiftVert=parseInt(oPopUp.shiftVert);
	var distanceToCallingElem=oPopUp.distanceToCallingElem; //distance of popup from calling elem

	//determine position requests
	reqPosition=reqPosition.split(",");
	var mainPos= oPopUp.mainPos= reqPosition[0];
	var align= oPopUp.align= reqPosition[1];
	//check for valid or present alignment request, else set default
	if(mainPos=="top" || mainPos=="bottom")
		{align= oPopUp.align= (align=="alignLeft" || align=="alignRight")? align : "center"}
	else if(mainPos=="left" || mainPos=="right")
		{align= oPopUp.align= (align=="alignTop" || align=="alignBottom")? align : "center"}
	else {alert("Error in func calcPosUp. Incorrect position '"+mainPos+"' requested for popup."); return};
 
 	//get position/dimensions of callingElem
	var callingElemLeft=oPopUp.callingElemLeft=getposOffset(callingElem, "left");
	var callingElemTop=oPopUp.callingElemTop=getposOffset(callingElem, "top");
	var callingElemWidth=oPopUp.callingElemWidth=callingElem.offsetWidth;
	var callingElemHeight=oPopUp.callingElemHeight=callingElem.offsetHeight;
	var callingElemRight=oPopUp.callingElemRight=callingElemLeft + callingElemWidth;
	var callingElemBottom=oPopUp.callingElemBottom=callingElemTop + callingElemHeight;
	var callingElemLRCenter=oPopUp.callingElemLRCenter= callingElemLeft + parseInt(callingElemWidth/2);
	var callingElemTBCenter=oPopUp.callingElemTBCenter= callingElemTop + parseInt(callingElemHeight/2);
	
	//get position/dimensions of popup
	var popUpWidth=oPopUp.popUpWidth=popUpBox.offsetWidth;
	var popUpHeight=oPopUp.popUpHeight=popUpBox.offsetHeight;
	//vars for calculated pref position
	var popUpLeft,popUpTop;
	
	//determine preferred position
	if(mainPos=="top" || mainPos=="bottom")
		{if(mainPos=="top")
			{popUpTop= callingElemTop - distanceToCallingElem - popUpHeight;}
		else if(mainPos=="bottom")
			{popUpTop= callingElemBottom + distanceToCallingElem;}
		if(align=="center")
			{popUpLeft= callingElemLRCenter - parseInt(popUpWidth/2) + shiftHor;}
		else if(align=="alignLeft")
			{popUpLeft= callingElemLeft + shiftHor;}
		else if(align=="alignRight")
			{popUpLeft= callingElemRight + shiftHor;}
		}

	else if(mainPos=="left" || mainPos=="right")
		{if(mainPos=="left")
			{popUpLeft= callingElemLeft - distanceToCallingElem - popUpWidth;}
		else if(mainPos=="right")
			{popUpLeft= callingElemRight + distanceToCallingElem;}
		if(align=="center")
			{popUpTop= callingElemTBCenter - parseInt(popUpHeight/2) + shiftVert;}
		else if(align=="alignTop")
			{popUpTop= callingElemTop + shiftVert;}
		else if(align=="alignBottom")
			{popUpTop= callingElemBottom + shiftVert;}
		}

	//set the found positions
	oPopUp.popUpLeft=popUpLeft;
	oPopUp.popUpTop=popUpTop;

	return oPopUp;
	}
	
	
function correctOutsideWindow(oPopUp)
	{var ie=document.all;
	var distanceToWindow=oPopUp.distanceToWindow;
	var ieWindowRightSafety=0; //30 in orig script
	var nsWindowRightSafety=0; //40 in orig script
	var ieWindowBottomSafety=0; //15 in orig script
	var nsWindowBottomSafety=0; //18 in orig script
	
	//determine window sizes		
	var windowRight= oPopUp.windowRight= (ie && !window.opera)? iecompattest().scrollLeft+iecompattest().clientWidth- ieWindowRightSafety : window.pageXOffset+window.innerWidth-nsWindowRightSafety;
	var windowBottom= oPopUp.windowBottom= (ie && !window.opera)? iecompattest().scrollTop+iecompattest().clientHeight-ieWindowBottomSafety : window.pageYOffset+window.innerHeight-nsWindowBottomSafety;
	
	//get/determine popUp dimensions
	var popUpLeft=oPopUp.popUpLeft;
	var popUpWidth=oPopUp.popUpWidth;
	var popUpRight=oPopUp.popUpRight= popUpLeft + popUpWidth;
	var popUpTop=oPopUp.popUpTop;
	var popUpHeight=oPopUp.popUpHeight;
	var popUpBottom=oPopUp.popUpBottom= popUpTop + popUpHeight;

	//correct over borders
	var overRightEdge= (popUpRight + distanceToWindow) - windowRight;
	popUpLeft= (overRightEdge>0)? popUpLeft - overRightEdge : popUpLeft; //correct over right border
	popUpLeft=oPopUp.popUpLeft= (popUpLeft>0)? popUpLeft : distanceToWindow; //correct over left border
	
	var overBottomEdge= (popUpBottom + distanceToWindow) - windowBottom;
	popUpTop= (overBottomEdge>0)? popUpTop - overBottomEdge : popUpTop; //correct over bottom border
	popUpTop=oPopUp.popUpTop= (popUpTop>0)? popUpTop : distanceToWindow; //correct over top border

	//recalculate right and bottom positions
	popUpRight=oPopUp.popUpRight= popUpLeft + popUpWidth;
	popUpBottom=oPopUp.popUpBottom=  popUpTop + popUpHeight;
	
	return oPopUp;
	}

	
function correctOverlapCallingElem(oPopUp)
	{//is there any overlap? if no correction needed, return directly
	var overlap=calcOverlap(convertPopUpNamesToEl1El2(oPopUp));
	//$.log(overlap)
	if(overlap==0) {return oPopUp;}
	
	//for ease of reading
	var minDistance=oPopUp.distanceToCallingElem
	var callingElemLeft= oPopUp.callingElemLeft;
	var callingElemTop =oPopUp.callingElemTop;
	var callingElemRight =oPopUp.callingElemRight;
	var callingElemBottom =oPopUp.callingElemBottom;
	var popUpWidth= oPopUp.popUpWidth;
	var popUpHeight =oPopUp.popUpHeight;
	
	//CONSIDER OPTIONS: MOVING POPUP TO: LEFT, RIGHT, TOP, BOTTOM, TOPLEFT, TOPRIGHT, BOTTOMLEFT, BOTTOMRIGHT of CALLINGELEM
	function tryLeft() {oTryPopUp.popUpLeft=  callingElemLeft - minDistance - popUpWidth}
	function tryRight()	{oTryPopUp.popUpLeft=  callingElemRight + minDistance}
	function tryTop() {oTryPopUp.popUpTop=  callingElemTop - minDistance - popUpHeight}
	function tryBottom() {oTryPopUp.popUpTop=  callingElemBottom + minDistance}
	function tryTopLeft() {tryTop(); tryLeft();}
	function tryTopRight()	{tryTop(); tryRight();}		
	function tryBottomLeft() {tryBottom(); tryLeft();}
	function tryBottomRight() {tryBottom(); tryRight();}

	//determine order in which to try options: prefer equal to requestedPos, prefer 1 move > 2 moves
	function getTryOrder()
		{var reqPos= oPopUp.mainPos +","+ oPopUp.align;  //get requested position
		switch(reqPos)
			{case "top,alignLeft": 
				return [tryTop,tryLeft,tryTopLeft,tryRight,tryTopRight,tryBottom,tryBottomLeft,tryBottomRight];
			case "top,center": 
				return [tryTop,tryLeft,tryRight,tryTopLeft,tryTopRight,tryBottom,tryBottomLeft,tryBottomRight];				
			case "top,alignRight": 
				return [tryTop,tryRight,tryTopRight,tryLeft,tryTopLeft,tryBottom,tryBottomRight,tryBottomLeft];		
			case "bottom,alignLeft": 
				return [tryBottom,tryLeft,tryBottomLeft,tryRight,tryBottomRight,tryTop,tryTopLeft,tryTopRight];
			case "bottom,center": 
				return [tryBottom,tryBottomLeft,tryBottomRight,tryLeft,tryRight,tryTop,tryTopLeft,tryTopRight];				
			case "bottom,alignRight": 
				return [tryBottom,tryRight,tryBottomRight,tryLeft,tryBottomLeft,tryTop,tryTopRight,tryTopLeft];						
			case "left,alignTop": 
				return [tryLeft,tryTop,tryTopLeft,tryBottom,tryBottomLeft,tryRight,tryTopRight,tryBottomRight];				
			case "left,center": 
				return [tryLeft,tryTop,tryBottom,tryTopLeft,tryBottomLeft,tryRight,tryTopRight,tryBottomRight];				
			case "left,alignBottom": 
				return [tryLeft,tryBottom,tryBottomLeft,tryTop,tryTopLeft,tryRight,tryTopRight,tryBottomRight];				
			case "right,alignTop": 
				return [tryRight,tryTop,tryTopRight,tryBottom,tryBottomRight,tryLeft,tryTopLeft,tryBottomLeft];				
			case "right,center": 
				return [tryRight,tryTop,tryBottom,tryTopRight,tryBottomRight,tryLeft,tryTopLeft,tryBottomLeft];				
			case "right,alignBottom": 
				return [tryRight,tryBottom,tryBottomRight,tryTop,tryTopRight,tryLeft,tryBottomLeft,tryTopLeft];				
			default: 
				return [tryLeft,tryRight,tryTop,tryBottom,tryTopLeft,tryTopRight,tryBottomLeft,tryBottomRight];				
			}
		}
		
	var options=getTryOrder();
			
	//set base values
	var smallestOverlap=overlap;
	var bestOptionLeft=oPopUp.popUpLeft;
	var bestOptionTop=oPopUp.popUpTop;
	
	//for each option in the set try-order, calculate resulting overlap
	//take 1st option with overlap==0, or if none found, option with smallest overlap
	for(var i=0;i<options.length;i++)
    	{oTryPopUp= $.extend({},oPopUp); //create copy to not damage original
		options[i](); //execute the try
		oTryPopUp=correctOutsideWindow(oTryPopUp) //correct for outside window
		overlap= calcOverlap(convertPopUpNamesToEl1El2(oTryPopUp)) //calc resulting overlap
		if(overlap<smallestOverlap) //if better than previous ones, set this one as best option
			{smallestOverlap=overlap;
			bestOptionLeft=oTryPopUp.popUpLeft;
			bestOptionTop=oTryPopUp.popUpTop;			
			}
		if(smallestOverlap==0) break; //at 1st occurence of 0 overlap, stop searching
    	}
	
	//set the data-container oPopUp to the best options and return
	oPopUp.popUpLeft=bestOptionLeft;
	oPopUp.popUpTop=bestOptionTop;
	return oPopUp;	
	}

	
	
//extract from oPopUp the positions to use in the generic function calcOverlap, convert to generic names 'el1, el2'
function convertPopUpNamesToEl1El2(oPopUp)
	{var elemInfo=new Object();
	//elem1=callingElem, elem2=popUp
	elemInfo.el1Left=oPopUp.callingElemLeft;
	elemInfo.el1Top=oPopUp.callingElemTop;
	elemInfo.el1Width=oPopUp.callingElemWidth;
	elemInfo.el1Height=oPopUp.callingElemHeight;	
	elemInfo.el2Left=oPopUp.popUpLeft; 
	elemInfo.el2Top=oPopUp.popUpTop;
	elemInfo.el2Width=oPopUp.popUpWidth;
	elemInfo.el2Height=oPopUp.popUpHeight;
	return elemInfo;
	}
	

function calcOverlap(elemInfo) //oPopUp can be removed when ebugstring removed
	{//for ease of reading
	var el1Left= elemInfo.el1Left;
	var el1Top= elemInfo.el1Top;
	var el1Width= elemInfo.el1Width;
	var el1Height= elemInfo.el1Height;
	var el1Right= el1Left + el1Width;
	var el1Bottom= el1Top + el1Height;
	var el2Left= elemInfo.el2Left;
	var el2Top= elemInfo.el2Top;
	var el2Width= elemInfo.el2Width;
	var el2Height= elemInfo.el2Height;
	var el2Right= el2Left + el2Width;
	var el2Bottom= el2Top + el2Height;
	var overlap=0; //default start. To contain overlap area in square pixels
	
	/*Possible ways of overlap: if:
	- any el2 corner is in el1
	- any el2 side overlaps el1
	- el2 completely overlaps el1.
	*/
	//corners of el2 inside el1?
	var topLeftCornerEl2InEl1=(el2Top>=el1Top && el2Top<=el1Bottom && el2Left>=el1Left && el2Left<=el1Right);
	var bottomLeftCornerEl2InEl1=(el2Bottom>=el1Top && el2Bottom<=el1Bottom && el2Left>=el1Left && el2Left<=el1Right);
	var topRightCornerEl2InEl1=(el2Top>=el1Top && el2Top<=el1Bottom && el2Right>=el1Left && el2Right<=el1Right);
	var bottomRightCornerEl2InEl1=(el2Bottom>=el1Top && el2Bottom<=el1Bottom && el2Right>=el1Left && el2Right<=el1Right);
	
	//sides of el2 overlap el1? (with corners el2 outside el1)
	var bottomEl2InEl1=(el2Bottom>=el1Top && el2Bottom<=el1Bottom && el2Left<=el1Left && el2Right>=el1Right);
	var topEl2InEl1=(el2Top>=el1Top && el2Top<=el1Bottom && el2Left<=el1Left && el2Right>=el1Right);
	var leftEl2InEl1=(el2Left>=el1Left && el2Left<=el1Right && el2Top<=el1Top && el2Bottom>=el1Bottom);
	var rightEl2InEl1=(el2Right<=el1Right && el2Right>=el1Left && el2Top<=el1Top && el2Bottom>=el1Bottom);
	
	//el2 completely overlaps el1?
	var el2CompletelyOverlapsEl1=(el2Top<=el1Top && el2Left<=el1Left && el2Bottom>=el1Bottom && el2Right>=el1Right)

//$.log("el1Left="+el1Left+", el1Right="+el1Right+", el1Top="+el1Top+", el1Bottom="+el1Bottom+", el2Left="+el2Left+", el2Right="+el2Right+", el2Top="+el2Top+", el2Bottom="+el2Bottom+" el2CompletelyOverlapsEl1="+el2CompletelyOverlapsEl1)

	//If there isoverlap,  calc overlap size in square pixels
	if(topLeftCornerEl2InEl1 || bottomLeftCornerEl2InEl1 || topRightCornerEl2InEl1 || bottomRightCornerEl2InEl1 || bottomEl2InEl1 || topEl2InEl1 || leftEl2InEl1 || rightEl2InEl1 || el2CompletelyOverlapsEl1) 
		{//coordinates of overlap-area
		var ovlLeft,ovlTop,ovlRight,ovlBottom; 		
		//set which sides border the overlap area
		if(topLeftCornerEl2InEl1) {ovlLeft=el2Left; ovlTop=el2Top; ovlRight=el1Right; ovlBottom=el1Bottom;}
		else if(bottomLeftCornerEl2InEl1) {ovlLeft=el2Left; ovlTop=el1Top; ovlRight=el1Right; ovlBottom=el2Bottom;}
		else if(topRightCornerEl2InEl1) {ovlLeft=el1Left; ovlTop=el2Top; ovlRight=el2Right; ovlBottom=el1Bottom;}
		else if(bottomRightCornerEl2InEl1) {ovlLeft=el1Left; ovlTop=el1Top; ovlRight=el2Right; ovlBottom=el2Bottom;}
		else if(bottomEl2InEl1) {ovlLeft=el1Left; ovlTop=el1Top; ovlRight=el1Right; ovlBottom=el2Bottom;}
		else if(topEl2InEl1) {ovlLeft=el1Left; ovlTop=el2Top; ovlRight=el1Right; ovlBottom=el1Bottom;}
		else if(leftEl2InEl1) {ovlLeft=el2Left; ovlTop=el1Top; ovlRight=el1Right; ovlBottom=el1Bottom;}
		else if(rightEl2InEl1) {ovlLeft=el1Left; ovlTop=el1Top; ovlRight=el2Right; ovlBottom=el1Bottom;}
		else if(el2CompletelyOverlapsEl1) {ovlLeft=el1Left; ovlTop=el1Top; ovlRight=el1Right; ovlBottom=el1Bottom;}
		//calculate overlap area in square pixels
		overlap=(ovlRight-ovlLeft)*(ovlBottom-ovlTop);
		
		return overlap;
		
		}
	}	

///////////////////////////////////////////////////////////////////////////////
//General support functions


function exists(subject) //
    {if(typeof subject != "undefined") return true
	else return false   
    }
	

