
/**
 * class to manage and handle events
 * see method EventHandler.prototype.add
 */
	function EventHandler(){
		this.aoCallbacks={};
		this.iLastGivenID=0;
	}
	
	
	EventHandler.Me=null;
	
	
	/**
	 * returns the singleton instance of this class
	 * @return EventHandler
	 */
	EventHandler.Instance=function(){
		if(EventHandler.Me==null)EventHandler.Me=new EventHandler();
		return EventHandler.Me;
	};
	
	
	/**
	 * this adds the event sEvent to HTMLElement obj. When the event occurs,
	 * fnCallback is called with objScope as the 'this' value(default window)
	 * optionally a return value for the event can be given 
	 *(might be necessary with links e.g.)
	 * the parameters of the callback function are: 
	 * Event e,HTMLElement obj - element the event occurred on
	 */
	EventHandler.prototype.addHandler=function(obj,sEvent,fnCallback,objScope,
	oReturnValue){
		if(!obj)return;
		if(!isDefined(objScope))objScope=window;
		if(!isDefined(oReturnValue))oReturnValue=null;
		
		var sAttribute=sEvent+'_EventHandlerID';
		var iID=checkInt(getElementAttribute(obj,sAttribute));
		if(iID==0){
			iID=++this.iLastGivenID;
			this.aoCallbacks[iID]={};
			this.aoCallbacks[iID].jseval=getFunctionString(obj,sEvent);
			this.aoCallbacks[iID].returnvalue=null;
			this.aoCallbacks[iID].callbackfunctions=[];
			eval("obj."+sEvent+"=function(e){ "+
					 "return EventHandler.prototype.handleEvent.call(this,e,'"+sEvent+"');"+
				 "};");
			setElementAttribute(obj,sAttribute,iID);
		}
		
		if(oReturnValue !=null||this.aoCallbacks[iID].returnvalue==null)
			this.aoCallbacks[iID].returnvalue=oReturnValue;
		var oNewCallback={};
		oNewCallback.fnCallback=fnCallback;
		oNewCallback.objScope=objScope;
		if(this.callbackExists(oNewCallback,iID)==-1)
		this.aoCallbacks[iID].callbackfunctions.push(oNewCallback);
	};
	
	
	/**
	 * removes given handler from given object. if this was the only handler and
	 * no handling in the html was defined
	 * @param HTMLElement obj
	 * @param String sEvent
	 * @param Function fnCallback
	 * @param Object objScope
	 * @return void
	 */
	EventHandler.prototype.removeHandler=function(obj,sEvent,fnCallback,objScope){
	var iID=checkInt(getElementAttribute(obj,sEvent+'_EventHandlerID'));
	
	var objCallbacks=this.getCallbackInfo(iID);
	if(objCallbacks !=null){
	for(var i=0;i<objCallbacks.callbackfunctions.length;i++){
	if(objCallbacks.callbackfunctions[i].objScope==objScope &&
	 objCallbacks.callbackfunctions[i].fnCallback==fnCallback){
	
	objCallbacks.callbackfunctions.splice(i,1);
	}
	}
	if(objCallbacks.callbackfunctions.length==0&&
	 objCallbacks.jseval=='')
	this.removeEvent(obj,sEvent);
	}
	};
	
	
	/**
	 * clears the whole event from given HTMLElement obj
	 * @param HTMLElement obj
	 * @param String sEvent
	 * @return void
	 */
	EventHandler.prototype.removeEvent=function(obj,sEvent){
	var iID=getElementAttribute(obj,sEvent+'_EventHandlerID');
	if(this.getCallbackInfo(iID)!=null)
	delete this.aoCallbacks[iID];
	eval('obj.'+sEvent+'=null;');
	setElementAttribute(obj,sEvent+'_EventHandlerID','');
	};
	
	
	/**
	 * returns the index of the given callback in the given event handler ID's
	 * callback array. returns -1 if not found;
	 * @param Object oCallback {fnCallback: Functions,ojbCallback: object}
	 * @param int iEventHandlerID
	 * @return int
	 */
	EventHandler.prototype.callbackExists=function(oCallback,iEventHandlerID){
	var aFunctions=this.aoCallbacks[iEventHandlerID].callbackfunctions;
	for(var i=0;i<aFunctions.length;i++){
	if(aFunctions[i].fnCallback==oCallback.fnCallback &&
	 aFunctions[i].objScope==oCallback.objScope)
	return i;
	}
	return -1;
	};
	
	
	/**
	 * private function to get the callback info for an event ID
	 * @param int iEventHandlerID
	 * @return Object {jseval: String,
	 * returnvalue: mixed,
	 * callbackfunctions: Array[{fnCallback: Function,
	 * objScope: Object},...]}
	 */
	EventHandler.prototype.getCallbackInfo=function(iEventHandlerID){
		return this.aoCallbacks[iEventHandlerID]||null;
	};
	
	
	/**
	 * called when the event is fired. this will call all functions coupled to this
	 * event
	 * @param Event e
	 * @param String sEvent
	 * @return mixed
	 */
	EventHandler.prototype.handleEvent=function(e,sEvent){
		
		var iID=checkInt(getElementAttribute(this,sEvent+'_EventHandlerID'));
		var oCallbackInfo=EventHandler.Instance().getCallbackInfo(iID);
		if(oCallbackInfo !=null){
			
			if(oCallbackInfo.jseval)eval(oCallbackInfo.jseval);
			var oReturn=oCallbackInfo.returnvalue;
			
			var aFunctions=oCallbackInfo.callbackfunctions;
			for(var i=0;i<aFunctions.length;i++){
				var oFuncReturn=aFunctions[i].fnCallback.call(
				aFunctions[i].objScope,getEvent(e),this);
				
				if(oFuncReturn !=undefined)
					if(oReturn==null)oReturn=oFuncReturn;
					else if(oCallbackInfo.returnvalue==null)oReturn=oReturn&&oFuncReturn;
			}
			
			if(oReturn !=null)return oReturn;
		}
	};

var EventManager={
_registry: null,

Initialise: function(){
if(this._registry==null){
this._registry=[];


EventManager.Add(window,"unload",this.CleanUp);
}
},

/**
 * Registers an event and handler with the manager.
 *
 * @paramobj Object handler will be attached to.
 * @paramtypeName of event handler responds to.
 * @paramfnHandler function.
 * @paramuseCaptureUse event capture. False by default.
 * If you don't understand this,ignore it.
 *
 * @return True if handler registered,else false.
 */
Add: function(obj,type,fn,useCapture){
if(!isDefined(useCapture))useCapture=false;
this.Initialise();


if(typeof obj=="string")obj=getObj(obj);
if(obj==null||fn==null)return false;


if(obj.addEventListener){
obj.addEventListener(type,fn,useCapture);
this._registry.push({obj: obj,type: type,fn: fn,useCapture: useCapture});
return true;
}


if(obj.attachEvent&&obj.attachEvent("on" + type,fn)){
this._registry.push({obj: obj,type: type,fn: fn,useCapture: false});
return true;
}

return false;
},

/**
 * removes given event from given object
 * @param HTMLElement obj
 * @param String type
 * @param Function fn
 * @param boolean useCapture - default false
 * @return voi
 */
Remove: function(obj,type,fn,useCapture){
if(!isDefined(useCapture))useCapture=false;

if(obj.removeEventListener){
obj.removeEventListener(type,fn,useCapture);
}

else if(obj.detachEvent){
obj.detachEvent("on" + type,fn);
}
},

/**
 * Cleans up all the registered event handlers.
 */
CleanUp: function(){
for(var i=0;i < EventManager._registry.length;i++){
with(EventManager._registry[i]){
EventManager.Remove(obj,type,fn,useCapture);
}
EventManager._registry[i]=null;
}



EventManager._registry=null;
}
};


/**
 * singleton class used to load js scripts(as an import)
 */
function LoadJS(){
}


/**
 * loads the js from given location. 
 * calls the return function when script is loaded...
 * PRE: page is loaded
 * @param String sSrcLocation
 * @param Object oReturnFuncion {fn: function,
 * obj: 'this' reference to use in the function}
 * @param Object oParam - optional parameter that will be passed through to 
 *the return function
 * @return void
 */
LoadJS.prototype.load=function(sSrcLocation,oReturnFunction,oParam){
if(!isDefined(oParam))oParam=null;
if(!isDefined(oReturnFunction))oReturnFunction=null;

var oJS=document.createElement('script');
oJS.setAttribute('type','text/javascript');
oJS.setAttribute('src',sSrcLocation);
oJS.onreadystatechange=function(){
if(this.readyState.toLowerCase()=='loaded' ||
 this.readyState.toLowerCase()=='complete'){
if(oReturnFunction !=null)
oReturnFunction.fn.call(oReturnFunction.obj,oParam);
}
};
oJS.onload=function(){ 
if(oReturnFunction !=null){
oReturnFunction.fn.call(oReturnFunction.obj,oParam);
}
};
document.body.appendChild(oJS);
};


/** create kind of singleton */
var LoadJS=new LoadJS();
var Log={write: function(){},writeText: function(){}};

/**
 * SEC stands for Standard Element Content
 * You can give a form element(as a textbox)a standard content. when the
 * element gets the focus,that content will disappear. when the element looses
 * the focus and the content is still empty,then the standard content will return
 * Besides the content a classname can be switched in the same way
 */
function SEC(){
this.aElements=new Array();
}


/**
 * register an element to the SEC system
 * @param string sID
 * @param string sContent
 * @param string sClassName
 * @return void
 */
SEC.prototype.setSEC=function(sID,sContent,sClassName){
if(!isDefined(sClassName))sClassName=null;
this.aElements[sID]={ sSEC: sContent,
sSCN: sClassName };
var objElement=getObj(sID);
objElement.onfocus=SEC.getFocus;
EventManager.Add(objElement,'blur',SEC.looseFocus);
if(sClassName)objElement.className +=' '+sClassName;
};


/**
 * this function is the event handler for a element that gets the focus
 * @param Event e
 * @return void
 */
SEC.prototype.getFocus=function(e){

if(SEC.aElements[this.id].sSEC==this.value){
this.value='';
}

if(SEC.aElements[this.id].sSCN)
removeObjClassName(this,SEC.aElements[this.id].sSCN);
};


/**
 * this function is the event handler for a element that looses the focus
 * @param Event e
 * @return void
 */
SEC.prototype.looseFocus=function(e){
var objTarget=getEventTarget(e);
if(objTarget.value==''){
objTarget.className=objTarget.className + ' ' + SEC.aElements[objTarget.id].sSCN;
objTarget.value=SEC.aElements[objTarget.id].sSEC;
}
};


/**
 * call this function on a form submit. if the value of a SEC element is the same
 * as the default value,then the value is cleared
 * @return void
 */
SEC.prototype.formSubmit=function(){
for(var sID in SEC.aElements){
if(SEC.aElements[sID].sSEC==getObj(sID).value)
getObj(sID).value='';
}
};


 /** #############################################################
* global SEC var to enable functionality like SEC.setSEC();
* sort of singleton
*/
var SEC=new SEC();
/** 
* This js file contains all standard functions that can be used in 
* several projects and purposes. Don't forget to import this js file in your
* HTML page.
*/

/**
 * use this var to check if the browser is Microsoft Internet Explorer
 */ 
var bIE=document.all ? true : false;
/**
 * use this var to check if the page is loaded already(will be set to true in
 * body onload event)
 */
var bPageLoaded=false;
/**
 * use this var to check if the site is running in debug mode
 */
var DEBUG_MODE=true;
/**
 * use this var to check if the current page is reloading due to a submit action
 */
var bSubmitting=false;
/**
 * the current window. this can be used to use universal calls from outside an
 * iframe to the iframe. only works on same domains
 * @example wndCurWindow.globalFunction();
 * @example wndCurWindow.Class.Instance().function();
 */
var wndCurWindow=window;
try {
if(parent)parent.wndCurWindow=window;
} catch(e){}

var FWSendRequestOptions={showurl: true};

/**
 * little struct/class to store a pixel location in
 * @param int iLeft - default 0
 * @param int iTop - default 0
 */
function Pixel(iLeft,iTop){
if(!isDefined(iLeft))iLeft=0;
if(!isDefined(iTop))iTop=0;
this.left=iLeft;
this.top=iTop;
}

/**
 * little struct/class to store a(pixel)size in
 * @param int iWidth - default 0
 * @param int iHeight - default 0
 */
function Size(iWidth,iHeight){
if(!isDefined(iWidth))iWidth=0;
if(!isDefined(iHeight))iHeight=0;
this.width=iWidth;
this.height=iHeight;
}
/**
 * swaps the width and height
 */
Size.prototype.swap=function(){
var iTemp=this.width;
this.width=this.height;
this.height=iTemp;
};
 
 
/**
 * onerror handler for this window
 * @param String sMsg
 * @param String sUrl
 * @param int iLineNr
 * @return bool
 */
window.onerror=function(sMsg,sURL,iLineNr){
Log.writeText('JS Error: '+sMsg+' in '+sURL+' on line '+iLineNr);
return !DEBUG_MODE;
};


/**
 * strips all the html-tags from given string
 * @param String s
 * @return String
 */
stripHTMLTags=function(s){
return s.replace(/<\/?[^>]+(>|$)/g,'');
};


/**
 * enables or disables selecting on the current page
 * @param boolean bEnable
 * @return void
 */
function enableSelecting(bEnable){
if(bEnable){
if(bIE)document.onselectstart=new Function("return true;");
else setObjStyle(document.body,'MozUserSelect','');
}
else {
if(bIE)document.onselectstart=new Function("return false;");
else setObjStyle(document.body,'MozUserSelect','none');
}
}


/**
 * can be called at any time to load the tiny mce jscripts
 */
function loadTinyMCE(iJSUpdated){
html_doc=document.getElementsByTagName("head").item(0);
	js=document.createElement("script");
	js.setAttribute("type","text/javascript");
	js.setAttribute("src",'scripts/tiny_mce/tiny_mce_src.js?'+iJSUpdated);
	js.onreadystatechange=function(){
if(this.readyState.toLowerCase()=='loaded' ||
 this.readyState.toLowerCase()=='complete'){
tinyMCE.onLoad();
}
	};
	js.onload=function(){ tinyMCE.onLoad();	};
	html_doc.appendChild(js);
}


/**
 * called from tiny_mce_src.js at the bottom of the script
 * @return void
 */
function tinyMCELoaded(){
if(window.initTinyMCE)
initTinyMCE();
}
 

/**
* gets current timestamp in milliseconds,so /1000==UNIX_TIMESTAMP
* @return int
*/
function getCurTime(){
return(new Date()).getTime();
}


/**
 * returns a string in format H:i:s(PHP style)based on the given seconds
 * @param int iSeconds
 * @return String
 */
function getTimeString(iSeconds){
return padDigits(Math.floor(iSeconds/3600),2)+':'+
 padDigits(Math.floor(iSeconds%3600/60),2)+':'+
 padDigits(Math.floor(iSeconds%3600%60),2);
}


/**
 * checks of given variable is defined
 * @return bool
 */
function isDefined(variable,bGlobal){
if(String(typeof bGlobal)=='undefined')bGlobal=false;
if(typeof variable=='string'&&bGlobal)variable=window[variable];
return(String(typeof variable)!='undefined');
}


/**
* pads given number with leading zeros
* 
* @param int iNumber
* @param int iTotalDigits
* @return String
*/
function padDigits(iNumber,iTotalDigits){ 
var sNumber=iNumber.toString();
while(sNumber.length < iTotalDigits)
sNumber='0' + sNumber;
return sNumber;
}


/**
 * rounds given number with given precision
 * @param float fNumber
 * @param int iPrecision
 * @param boolean bAsFloat - default true
 * @return float|string
 */
function roundNumber(fNumber,iPrecision,bAsFloat){
if(!isDefined(iPrecision))iPrecision=-1;
if(!isDefined(bAsFloat))bAsFloat=true;

if(iPrecision >=0){
var sNumber=checkFloat(fNumber).toFixed(iPrecision);
return bAsFloat ? checkFloat(sNumber): sNumber;
}
else return bAsFloat ? checkFloat(fNumber): String(fNumber);
}


/**
* checks if given string is a number
* @return bool
*/
function isNumeric(sNumber){
return checkFloat(sNumber)==sNumber&&sNumber !='';
}


/**
 * converts a decimal value to a hex string
 * @param int iNumber
 * @return String
 */
function dec2hex(iNumber){
return checkInt(iNumber).toString(16);
}


/**
 * converts a hex string to a decimal value
 * @param String sNumber
 * @return int
 */
function hex2dec(sNumber){
var iNumber=parseInt(sNumber,16);
if(isNaN(iNumber))return 0;
else return iNumber;
} 


/**
 * converts radians to degrees
 * @param float fRad
 * @return float
 */
function radToDeg(fRad){
return fRad * 180 / Math.PI;
}


/**
 * converts degrees to radians
 * @param float fDeg
 * @return float
 */
function degToRad(fDeg){
return fDeg * Math.PI / 180;
}


/**
 * returns the value of the radio group with given name.
 * returns null if nothing is selected.
 * @param String sName
 * @return String
 */
function getRadioValue(sName){
		var objRadio=document.getElementsByName(sName);
		if(!objRadio)objRadio=getObj(sName);
		if(!objRadio)return null;
		
		if(!isDefined(objRadio.length))
			if(objRadio.checked)return objRadio.value;
			else return null;
			
		for(var i=0;i<objRadio.length;i++)
			if(objRadio[i].checked)	return objRadio[i].value;				
		return null;
	}
	
	
	function setRadioValue(sName,sValue){
var objRadio=document.getElementsByName(sName);
if(!objRadio)objRadio=getObj(sName);
if(!objRadio)return;

if(!isDefined(objRadio.length))
objRadio.checked=objRadio.value==sValue;

for(var i=0;i<objRadio.length;i++)
objRadio[i].checked=objRadio[i].value==sValue;
}
	
	
	/**
	 * returns true if the given element is visible to the user
	 * @param String sObjID
	 * @return bool
	 */
	function isVisible(sObjID){ return isObjVisible(getObj(sObjID));}	
/**
	 * returns true if the given element is visible to the user
	 * @param HTMLElement obj
	 * @return bool
	 */
	function isObjVisible(obj){
	if(!obj)
	return false;
	
while(obj.tagName.toLowerCase()!='body'&&
 getObjStyle(obj,'display')!='none'&&
 getObjStyle(obj,'visibility')!='hidden'){
obj=obj.parentNode;
}

if(obj.tagName.toLowerCase()=='body')return true;
else return false;
}


/**
 * sets the focus at the given element and places the cusor at the
 * end of it(in case of a textbox)
 * 
 * @param String sElementID 
 * @return void
 */
function setFocus(sElementID){
setObjFocus(getObj(sElementID));
}
/**
 * sets the focus at the given element and places the cusor at the
 * end of it(in case of a textbox)
 * 
 * @param HTMLElement objFocus
 * @return void
 */
function setObjFocus(objFocus){
if(!objFocus)return;
if(objFocus.type=="checkbox")return;
try { objFocus.focus();}
catch(e){ print_r(e);}
if(objFocus.createTextRange){
try {
var trRange=objFocus.createTextRange();
trRange.moveStart('character',objFocus.value.length);
trRange.collapse();
trRange.select();
} catch(e){ }
}
}


/**
 * gets the content of the given function in string format
 * @return String
 */
function getFunctionString(obj,sFunction){
if((typeof obj).toLowerCase()=='function')fnFunction=obj;
else if(!obj)fnFunction=window[sFunction];
else fnFunction=obj[sFunction];

if(!isDefined(fnFunction))return '';
var sFunction=String(fnFunction);
if(isDefined(sFunction))
sFunction=sFunction.substring(sFunction.indexOf('{')+1,
sFunction.lastIndexOf('}')-1);
else sFunction='';
return sFunction.trim();
}


/**
 * add slashes to the given sString.
 * @example addSlashes('adj? asd[fa asd "f asdf',['"','?','[']);=> adj\? asd\[fa asd \"f asdf
 * @param String sString
 * @param array aSlashStrings
 * @return String
 */
function addSlashes(sString,aSlashStrings){
for(var iIndex in aSlashStrings){
sReplace='/\\'+aSlashStrings[iIndex]+'/g';
sReplacement='\\\\'+aSlashStrings[iIndex];
sString=eval("sString.replace("+sReplace+",'"+sReplacement+"');");
}
return sString;
}


/**
* creates and returns a div(zIndex 101)within given element,
* to catch mouse events
* @param HTMLElement eElement
* @param HTMLElement eContainer - default eElement. if true -> document.body;
* @return Div
*/
function getMouseCatchDiv(eElement,eContainer){
if(!eElement)return;
if(!isDefined(eContainer))eContainer=null;
if(eContainer===true)eContainer=document.body;
if(eContainer===false)eContainer=null;

var eCheckPosition=eContainer&&eContainer !=document.body ? 
 eContainer : eElement;

var sCurPositionStyle=getObjStyle(eCheckPosition,'position');
if(sCurPositionStyle !='relative'&&sCurPositionStyle !='absolute')
setObjStyle(eCheckPosition,'position','relative');


var oSize=getElementSize(eElement);

var divCatch=document.createElement("div");
setObjStyle(divCatch,'position','absolute');
var oPos=new Pixel();

if(eContainer)oPos=getElementPosition(eElement,eContainer);


setObjMultStyle(divCatch,
['left','top','width','height','zIndex','backgroundColor'],
[oPos.left+'px',oPos.top+'px',oSize.width+'px',oSize.height+'px',
 '101','white']);
setObjTransparency(divCatch,100);

if(eContainer)eContainer.appendChild(divCatch);
else eElement.appendChild(divCatch);
return divCatch;
}


/**
 * A general-purpose function to get the absolute position of the mouse 
 * @return struct(left,top)
 */
function getGlobalMousePosition(e){
	var posx=0;
	var posy=0;
	var e=getEvent(e);
	if(!e)return new Pixel();
	
	if(e.pageX||e.pageY){
		posx=e.pageX;
		posy=e.pageY;
	} 
	else if(e.clientX||e.clientY){
	var oScroll=getDocumentScroll();
		posx=e.clientX + oScroll.x;
		posy=e.clientY + oScroll.y;
	}	
	return new Pixel(posx,posy);
}


/**
 * returns the scrolling to the left(x)and top(y)
 * @return Pixel
 */
function getDocumentScroll(){
var oScroll=new Pixel();
oScroll.x=document.documentElement.scrollLeft?
document.documentElement.scrollLeft:
document.body.scrollLeft;
oScroll.y=document.documentElement.scrollTop?
document.documentElement.scrollTop:
document.body.scrollTop;
return oScroll;
}


/**
 * gets the mouse button wich is pressed
 * return values: 1=Left button,other returns means Right button.
 * @return int
 */
function getMouseButton(e){
var e=getEvent(e);
if(!e)return null;
var clickType=1;
if(parseInt(navigator.appVersion)> 3){
if(navigator.appName=="Netscape")
clickType=e.which;
else
clickType=event.button;
}
return clickType;
}


/**
 * returns 0 if no scrolling was done,
 * returns < 0 if scrolling was downwards
 * returns > 0 if scrolling was upwards
 */
function getScrollWheelDirection(e){
e=getEvent(e);
var iDelta=0;
if(e.wheelDelta){
iDelta=e.wheelDelta/120;
if(window.opera)iDelta=-iDelta;
} 
else if(e.detail){
iDelta=-e.detail/3;
}
return iDelta;
}


/**
 * returns keycode from given event
 * @param Event e
 */
function getKeyCode(e){
var e=getEvent(e);
if(!e)return null;
return e.keyCode;
}


/**
 * cancels the current event. if bCancelBubbling is true,all element under the
 * element the event was triggered on won't catch this event either.
 * @param Event e
 * @param boolean bCancelBubbling
 * @return void
 */
function cancelEvent(e,bCancelBubbling){
if(!isDefined(bCancelBubbling))bCancelBubbling=false;
e=getEvent(e);
e.returnValue=false;
e.cancelBubble=bCancelBubbling;
if(e.preventDefault&&e.stopPropagation){ 

e.preventDefault();
e.stopPropagation();
}
}


/**
 * gets window event,returns given Event e if e is an event itself
 * @param Event e
 */
function getEvent(e){
if(!e)var e=window.event;
if(!e)var e=null;
return e;
}


/**
 * gets the target object where given event is triggered on
 * @return HTMLElement
 */
function getEventTarget(e){
var e=getEvent(e);
if(!e)return null;
var oTarget=null;
	if(e.target)oTarget=e.target;
	else if(e.srcElement)oTarget=e.srcElement;
	if(oTarget&&oTarget.nodeType==3)
		oTarget=oTarget.parentNode;
return oTarget;
}


/**
 * find first occurrance of parent with given tagname
 * @param HTMLElement objElement
 * @param String sParentTag
 * @return HTMLElement
 */
function findParent(objElement,sParentTag){
while(objElement.parentNode&&objElement !=document.body){
if(objElement.parentNode.tagName.toLowerCase()==sParentTag.toLowerCase())
return objElement.parentNode;
objElement=objElement.parentNode;
}
}


/**
 * replaces objElement by objReplace
 * @param HTMLElement objElement
 * @param HTMLElement objReplace
 * @return void
 */
function replaceObj(objElement,objReplace){
objElement.parentNode.insertBefore(objReplace,objElement);
removeObjElement(objElement);
}


/**
 * perform a click on the element with given ID
 * @param String sID
 * @return void
 */
function performClick(sID){
if(!bPageLoaded){
setTimeout("performClick('"+sID+"');",200);
return;
}
if(getObj(sID)&& getObj(sID).onclick)
getObj(sID).onclick();
}


/**
 * returns true if the cursor is currently above the given element
 * @param Event e
 * @param HTMLElement eElement
 * @return bool
 */
function isMouseAboveElement(e,eElement){
var oPos=getGlobalMousePosition(e);
return posAboveElement(oPos,eElement);
}


/**
 * returns the mouse position relative to the given HTMLElement
 * @param Event e||Pixel(global mouse position)
 * @param HTMLElement eElement
 * @param int iElementBorder - default 0
 * @return Pixel
 */
function getObjMousePosition(e,eElement,iElementBorder){
if(!isDefined(iElementBorder))iElementBorder=0;
if(bIE)iElementBorder=iElementBorder * 2 + 1;

var oMousePos=null;
if(isDefined(e)&& e !=null&&isDefined(e.top)&& isDefined(e.left))
oMousePos=e;
else oMousePos=getGlobalMousePosition(e);

var oElPos=getElementPosition(eElement);
oElPos.top+=iElementBorder;
oElPos.left +=iElementBorder;
return new Pixel(oMousePos.left - oElPos.left,
 oMousePos.top- oElPos.top);
}


/**
* To Use: 
	* var pos=getElementPosition(element);
	* var left=pos.left;
	* var top=pos.top;
	* 
	* @param HTMLElement eElement
	* @param HTMLElement eRoot - default document.body
	* @return struct(left,top)
*/
function getElementPosition(eElement,eRoot){
if(!eElement)return new Pixel();
if(!isDefined(eRoot))eRoot=document.body;
var iLeftPos=eElement.offsetLeft;
	var iTopPos=eElement.offsetTop;
	var eParElement=eElement.offsetParent;
	while(eParElement !=eRoot&&eParElement!=null){ 
	iLeftPos +=eParElement.offsetLeft;
		iTopPos+=eParElement.offsetTop;
		eParElement=eParElement.offsetParent;
	}
	return new Pixel(iLeftPos,iTopPos);
}


/**
 * returns the size of given element
 * @param HTMLElement eElement
 * @return Size
 */
function getElementSize(eElement){
return new Size(getObjStyle(eElement,'width',true),
getObjStyle(eElement,'height',true));
}


/**
 * returns the inner size of the window
 * @param DOMDocument doc - document to use(default window.document)
 * @return Size
 */
function getWindowSize(doc){
if(!isDefined(doc))doc=document;
if(navigator.userAgent.toLowerCase().indexOf('opera')> 0 ||
 navigator.appVersion.toLowerCase().indexOf('safari')!=-1)
return new Size(wndCurWindow.innerWidth,
wndCurWindow.innerHeight);
else 
return new Size(doc.documentElement.clientWidth ||
doc.body.clientWidth ||
doc.body.scrollWidth,
doc.documentElement.clientHeight ||
doc.body.clientHeight ||
doc.body.scrollHeight);
}


/**
 * checks if given element has given parent
 * @param HTMLElement eElement
 * @param HTMLElement eParent
 * @return bool
 */
function elementHasParent(eElement,eParent){
while(eElement.parentNode&&eElement !=document.body){
if(eElement.parentNode==eParent)return true;
eElement=eElement.parentNode;
}
return false;
}


/**
 * checks if given Pixel(oPos)is within given bounds
 * @param Pixel oPos
 * @param int iLeft
 * @param int iTop
 * @param int iWidth
 * @param int iHeight
 * @return bool
 */
function posWithinBounds(oPos,iLeft,iTop,iWidth,iHeight){
return !(oPos.left < iLeft||oPos.left > iLeft + iWidth ||
 oPos.top< iTop|| oPos.top> iTop + iHeight);
}


/**
 * checks if given Pixel(oPos)is above given element
 * @param Pixel oPos
 * @param HTMLElement eElement
 * @return bool
 */
function posAboveElement(oPos,eElement){
var oElPos=getElementPosition(eElement);
var oElSize=getElementSize(eElement);
return posWithinBounds(oPos,oElPos.left,oElPos.top,
 oElSize.width,oElSize.height);
}


/**
 * makes a copy of given element with his children
 * it returns the copied HTMLElement with '_copy' added to the IDs
 * @param HTMLElement eElement
 * @return HTMLElement
 */
function makeValidCopy(eElement){
var eNewElement=eElement.cloneNode(true);
return addRecursiveToID(eNewElement,'_copy');
}


/**
 * adds the given addition to the id of eElement and all of his children
 * and returns the HTMLElement with the IDs extended
 * @param HTMLElement eElement
 * @param String sAddition
 * @return HTMLElement
 */
function addRecursiveToID(eElement,sAddition){
if(eElement.id)eElement.id +=sAddition;
for(var i=0;i<eElement.childNodes.length;i++)
addRecursiveToID(eElement.childNodes.item(i),sAddition);
return eElement;
}


/**
 * returns the window object of the iframe with given id.
 * in order to call: getFrame('iframeid').functionname();
 * returns null if iframe was not found.
 * @param String sFrameID
 * @return Window
 */
function getIFrame(sFrameID){
var frFrame=document.frames ? 
document.frames[sFrameID] : 
document.getElementById(sFrameID);
if(frFrame)
		return frFrame.window||frFrame.contentWindow;
else return null;
}


/**
 * short for document.getElementById;Return value can be null
 * @param String sID
 * @return HTMLElement
 */
function getObj(sID){
return document.getElementById(sID);
}


/**
 * returns the HTMLElement with given id in given document
 * return value can be null
 * @param DOMDocument doc
 * @param String sID
 * @return HTMLElement
 */
function getDocObj(doc,sID){
return doc.getElementById(sID);
}


/**
 * cuts the text off when it is larger than the specified amount of chars
 * returns true when the text is cut off,false otherwise
 * @param HTMLElement eElement
 * @param int iMaxLength
 * @param String sTitleText - optional
 * @return boolean
 */
function cutOffElementText(eElement,iMaxLength,sTitleText){
if(eElement.innerHTML.length > iMaxLength){
eElement.title=sTitleText||eElement.innerHTML;
eElement.innerHTML=eElement.innerHTML.substr(0,iMaxLength-3)+ '...';
return true;
} 
else return false;
};


/**
 * remove element with given id from his parent
 * @param String sID
 * @return void
 */
function removeElement(sID){
var eElement=getObj(sID);
removeObjElement(eElement);
}


/**
 * remove given element from his parent
 * @param HTMLElement eElement
 * @return void
 */
function removeObjElement(eElement){
if(!eElement)return false;
if(!eElement.parentNode)return false;
try {
eElement.parentNode.removeChild(eElement);
return true;
} catch(e){ return false;}
}


/**
 * removes all child nodes from given element
 * @param HTMLElement eElement
 * @return void
 */
function removeElementChilds(eElement){
if(!eElement||!eElement.childNodes){
if(eElement&&eElement.innerHTML)eElement.innerHTML='';
return;
}
while(eElement.childNodes.length > 0)
eElement.removeChild(eElement.childNodes[0]);
eElement.innerHTML='';
}


/**
 * removes the childs of given obj which are not visible
 * @param HTMLElement obj
 * @return void
 */
function removeHiddenElements(obj){
		for(var i=0;i<obj.childNodes.length;i++){
			if(!isDefined(obj.childNodes[i].tagName))continue;
			if(!isObjVisible(obj.childNodes[i])&& 
			String(obj.childNodes[i].className).indexOf('tinyMCETextarea')==-1 &&
obj.childNodes[i].getAttribute('type')!='hidden')
				if(removeObjElement(obj.childNodes[i]))i--;	
			else removeHiddenElements(obj.childNodes[i]);					
		}
	}


/** gets the style with given sStyleName of given object obj
 * @param String sObjID
 * @param String sStyleName
 * @param boolean bReturnInt - default false
 * @return String
 */
function getObjStyle(obj,sStyleName,bReturnInt){
if(!obj)return null;
if(!isDefined(bReturnInt))bReturnInt=false;

var value=obj.style[sStyleName];
if(!value||value=='auto')
if(document.defaultView){
value=document.defaultView.
getComputedStyle(obj,"").
getPropertyValue(sStyleName);
}
else if(obj.currentStyle)
value=obj.currentStyle[sStyleName];
if((typeof value).toLowerCase()=='string')
value=value.toLowerCase();
if(bReturnInt){
value=parseInt(value);
if(isNaN(value)){
value=0;
if(sStyleName=='width')value=obj.offsetWidth;
if(sStyleName=='height')value=obj.offsetHeight;
}
}

return !isDefined(value)?null:value;
}


/**
 * gets the style with given sStyleName of object with given ID
 * @param String sObjID
 * @param String sStyleName
 * @param boolean bReturnInt - default false
 * @return String | int
 */
function getStyle(sObjID,sStyleName,bReturnInt){
if(sObjID==null||sObjID=='')return;
return getObjStyle(getObj(sObjID),sStyleName,bReturnInt);
}


/**
 * sets the style of given object
 * @param HTMLElement obj
 * @param String sStyleName
 * @param String sValue
 * @return void
 */
function setObjStyle(obj,sStyleName,sValue){
if(obj !=null&&isDefined(obj)&& isDefined(obj.style)){
if(sStyleName.toLowerCase()=='float'){
if(bIE)sStyleName='styleFloat';
else sStyleName='cssFloat';
}
try { obj.style[sStyleName]=sValue;}
catch(e){ Log.write(obj.id+': '+sStyleName+'='+sValue);print_r(e);}
}
}


/**
 * sets the style of the given object and its children
 * @param HTMLElement obj
 * @param String sStyleName
 * @param String sValue
 * @return void
 */
function setObjStyleRecursive(obj,sStyleName,sValue){
setObjStyle(obj,sStyleName,sValue);
for(var i=0;i<obj.childNodes.length;i++)
setObjStyleRecursive(obj.childNodes.item(i),sStyleName,sValue);
}


/**
 * set multiple styles for one or more objects
 * @param HTMLElement([])
 * @param String[] aStyleNames
 * @param String[] aValues
 * @return void
 */
function setObjMultStyle(obj,aStyleNames,aValues){
if(!isArray(obj))obj=[obj];
for(var iIndex in obj){
for(var i=0;i<aStyleNames.length;i++)
if(isDefined(aStyleNames[i])&& isDefined(aValues[i]))
setObjStyle(obj[iIndex],aStyleNames[i],aValues[i]);
}
}


/**
* sets the style of object with given object ID
* @param String sObjID
* @param String sStyleName
* @param String sValue
* @return void
*/
function setStyle(sObjID,sStyleName,sValue){
setObjStyle(getObj(sObjID),sStyleName,sValue);
}


/**
 * sets the transparency of given object
 * @param String sObjID
 * @param int iPercent - 0: no transparency,opaque,100: fully transparent
 * @return void
 */
function setTransparency(sObjID,iPercent){
setObjTransparency(getObj(sObjID),iPercent);
}


/**
 * sets the transparency of the given DOM-object
 * @param HTMLElement obj
 * @param int iPercent - 0: no transparency,opaque,100: fully transparent
 * @return void
 */
function setObjTransparency(obj,iPercent){
iPercent=100 - iPercent;
if(bIE)
setObjStyle(obj,'filter','alpha(opacity='+iPercent+')');
else {
setObjStyle(obj,'MozOpacity',iPercent/100);
setObjStyle(obj,'opacity',iPercent/100);
}
}


/**
 * sets the position of given HTMLElement
 * @param HTMLElement obj
 * @param Pixel oPos
 * @return void
 */
function setObjPosition(obj,oPos){
setObjMultStyle(obj,['left','top'],[oPos.left+'px',oPos.top+'px'])
}


/**
 * sets the size of given HTMLElement(the width and height css styles)
 * @param HTMLElement obj
 * @param Size oSize
 * @return void
 */
function setObjSize(obj,oSize){
setObjMultStyle(obj,['width','height'],[oSize.width+'px',oSize.height+'px']);
}


/**
 * replaces given classname with another on given object
 * @param HTMLElement obj
 * @param String sSearch - may be a reg exp
 * @param String sReplace
 * @return void
 */
function replaceObjClassName(obj,sSearch,sReplace){
if(!obj||!obj.className)return;
var sClassName=String(obj.className);
sClassName=sClassName.replace(new RegExp(sSearch,"g"),sReplace);
obj.className=sClassName;
}


/**
 * swaps classes 1 en 2 within the class of given object
 * if class1 exists in object,1 is replaced with 2,otherwise 2 is replaced with 1
 * @param HTMLElement obj
 * @param String sClass1
 * @param String sClass2
 * @return void
 */
function swapObjClassName(obj,sClass1,sClass2){
if(obj==null)return;
if(hasClassName(obj,sClass1))
replaceObjClassName(obj,sClass1,sClass2);
else replaceObjClassName(obj,sClass2,sClass1);
}


/**
 * adds given class to given object
 * @param HTMLElement obj
 * @param String sClassName
 * @return void
 */
function addObjClassName(obj,sClassName){
if(obj==null)return;
if(!hasClassName(obj,sClassName)){
if(obj.className)obj.className=obj.className + ' ' + sClassName;
else obj.className=sClassName;
}
}


/**
 * removes given classname from given object
 * @param HTMLElement obj
 * @param String sClassName
 * @return void
 */
function removeObjClassName(obj,sClassName){
if(obj==null)return;
if(hasClassName(obj,sClassName+' '))sClassName +=' ';
else if(hasClassName(obj,' '+sClassName))sClassName=' ' + sClassName;
replaceObjClassName(obj,sClassName,'');
}


/**
 * returns true if the given object has given classname
 * @param HTMLElement obj
 * @param String sClassName
 * @return boolean
 */
function hasClassName(obj,sClassName){
if(obj==null)return false;
else {
var sCurName=String(obj.className);
return sCurName.indexOf(sClassName)!=-1;
}
}


/**
 * replaces given classname with another on given object and its children
 * @param HTMLElement obj
 * @param String sSearch - may be a reg exp
 * @param String sReplace
 * @return void
 */
function replaceObjClassNameRecursive(obj,sSearch,sReplace){
replaceObjClassName(obj,sSearch,sReplace);
for(var i=0;i<obj.childNodes.length;i++)
replaceObjClassNameRecursive(obj.childNodes.item(i),sSearch,sReplace);
}


/**
 * replaces the classname of the object with given ID
 * @param String sObjID
 * @param String sSearch - may be a reg exp
 * @param String sReplace
 * @return void
 */
function replaceClassName(sObjID,sSearch,sReplace){
replaceObjClassName(getObj(sObjID),sSearch,sReplace);
}


/**
 * loads given css as given media
 * PRE: page is loaded
 * @param String sSrcLocation
 * @param String sMedia
 * @return void
 */
function loadCSS(sCSSLocation,sMedia){
var oCSS=document.createElement('style');
oCSS.setAttribute('type','text/css');
oCSS.setAttribute('media',sMedia);
oCSS.innerHTML=sCSSLocation;
document.body.appendChild(oCSS);
}


/**
 * checks if given value is a valid int. if it is,it returns that value as an
 * int. if it is not valid,it returns 0;
 * @param mixed value
 * @return int
 */
function checkInt(value){
var iReturn=parseInt(value);
if(isNaN(iReturn))iReturn=0;
return iReturn;
}


/**
 * checks if given value is a valid float. if it is,it returns that value as an
 * float. if it is not valid,it returns 0.0;
 * @param mixed value
 * @return float
 */
function checkFloat(value){
var fReturn=parseFloat(value);
if(isNaN(fReturn))fReturn=0.0;
return fReturn;
}


/**
 * returns true if obj is an array
 * @param Object obj
 * @return bool
 */
function isArray(obj){
if(!obj)return false;
if(String(obj.constructor).toLowerCase().indexOf("array")!=-1)
return true;
return false;
} 


/**
 * returns true if given value is in the given array
 * @param Array array
 * @param object value
 * @return bool
 */
function inArray(array,value){
for(var iIndex in array)
if(array[iIndex]==value)return true;
return false;
} 


/**
 * gets an element's attribute value
 * @param HTMLElement eElement
 * @param String sAttribute
 * @return String
 */
function getElementAttribute(eElement,sAttribute){
if(!eElement)return null;
if(eElement.getAttribute)return eElement.getAttribute(sAttribute);
else return eElement[sAttribute];
}


/**
 * sets an element's attribute value
 * @param HTMLElement eElement
 * @param String sAttribute
 * @param String sValue
 * @return void
 */
function setElementAttribute(eElement,sAttribute,sValue){
if(!eElement)return null;
if(eElement.setAttribute)eElement.setAttribute(sAttribute,sValue);
else eElement[sAttribute];
}


/**
 * returns the value of the attribute with given name of the child
 * with given childnode name within the given parent node xmlParent
 * @param XMLNode xmlParent
 * @param String sChildNodeName
 * @param String sAttributeName
 * @return String
 */
function getXMLAttribute(xmlParent,sChildNodeName,sAttributeName){
var sText='';
try {
var xmlChilds=xmlParent.getElementsByTagName(sChildNodeName);
if(xmlChilds&&xmlChilds.length > 0)
sText=xmlChilds[0].getAttribute(sAttributeName);
} catch(e){}
return sText;
}


/**
 * returns the value of the first child node with given child node name
 * this must be a child of given parent xmlNode
 * @param XMLNode xmlParent
 * @param String sChildNodeName
 * @return String
 */
function getXMLElementText(xmlParent,sChildNodeName){
var sText='';
try {
var xmlChilds=xmlParent.getElementsByTagName(sChildNodeName);
if(xmlChilds&&xmlChilds.length > 0 &&
 xmlChilds[0].firstChild)
sText=xmlChilds[0].firstChild.data;
} catch(e){}
return sText;
}


/**
 * returns the CDATA value of the first child node with given node name
 * this must be a child of the given parent xmlNode
 * @param XMLNode xmlParent
 * @param String sChildNodeName
 * @return String
 */
function getXMLElementData(xmlParent,sChildNodeName){
var sData='';
try {
var xmlChilds=xmlParent.getElementsByTagName(sChildNodeName);
if(xmlChilds.length > 0){
if(xmlChilds[0].text)
sData=xmlChilds[0].text;
else if(xmlChilds[0].childNodes&&
xmlChilds[0].childNodes.length > 0&&
xmlChilds[0].childNodes[0].nodeValue)
sData=xmlChilds[0].childNodes[0].nodeValue;
}
} catch(e){}
return sData;
}


/**
* creates XMLHttpRequest object for AJAX purposes
* @return XMLHttpRequest
*/
function createXMLHttpRequest(){
var xmlhttp=null;

if(window.XMLHttpRequest){
	try { xmlhttp=new XMLHttpRequest();}
catch(e){ }
} 
else if(window.ActiveXObject){
for(var i=5;i>0&&xmlhttp==null;i--){
try { 
if(i==2)xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
else xmlhttp=new ActiveXObject("Msxml2.XMLHTTP."+ i + ".0");
}
	catch(e){ xmlhttp=null;}
}
}
if(!xmlhttp)
alert('Your browser doesn\'t support AJAX communications...');

return xmlhttp;
}


/**
 * call this to enable/disable Log.write(url);when executing sendRequest
 * @param boolean bShowURL
 * @return void
 */
function showSendRequestURL(bShowURL){
FWSendRequestOptions.showurl=bShowURL==true;
}


/**
 * sends a request to the given php filename with the supplied parameters
 * you can specify whether is is a post request or a get request
 * sReturnFunction is the name the function that must be called
 * this may also be a assoc. array with an obj and a fn value
 * Example: {obj: this,fn: Test.prototype.functionname}
 * on a valid result from the server(the XMLHttpRequest object is supplied 
 * as the first parameter of that function)
 * @param String sPHP
 * @param String sParameters
 * @param bool bPost
 * @param String sReturnFunction
 * @param object oParam - passed through to the returnfunction
 * @param boolean bAddAjaxcallParam - default true(&ajaxcall added to the paramstring)
 * @return {XMLHttpRequest xmlhttp,boolean bStopped}
 */
function sendRequest(sPHP,sParameters,bPost,sReturnFunction,oParam,bAddAjaxcallParam){
if(!isDefined(bAddAjaxcallParam))bAddAjaxcallParam=true;
if(!isDefined(oParam))oParam=null;
if(!isDefined(sReturnFunction))sReturnFunction='void';
if(!isDefined(bPost))bPost=false;
var oRequest={xmlhttp: createXMLHttpRequest(),stopped: false};
var sURL=sPHP;

if(!sParameters)sParameters='';
else if(bAddAjaxcallParam)sParameters +='&';
if(bAddAjaxcallParam)
sParameters +='ajaxcall'+(bPost?'=':'');


if(!bPost){
if(sURL.indexOf('?')==-1)sURL +='?'+sParameters;
else sURL +='&'+sParameters;
}
if(bPageLoaded&&FWSendRequestOptions.showurl)
Log.writeText(sURL+(bPost?'?'+sParameters:''));


try { 
oRequest.xmlhttp.open((bPost?"POST":"GET"),sURL,true);
oRequest.xmlhttp.onreadystatechange=
	function(){
	if(oRequest.xmlhttp.readyState==4&&!oRequest.stopped){
	if(oRequest.xmlhttp.responseText&&
	 oRequest.xmlhttp.responseText.trim &&
	 oRequest.xmlhttp.responseText.trim()=='refresh'){
	refreshPage();
	}
	else {
	
	if(isDefined(sReturnFunction.obj)&& isDefined(sReturnFunction.fn))
sReturnFunction.fn.call(sReturnFunction.obj,oRequest.xmlhttp,oParam);
	else eval(sReturnFunction+"(oRequest.xmlhttp,oParam);");
	}
	}
	};
	
	
	if(bPost){
	oRequest.xmlhttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
oRequest.xmlhttp.setRequestHeader("Content-length",sParameters.length);
	}
	oRequest.xmlhttp.setRequestHeader("Connection","close");
oRequest.xmlhttp.send((bPost?sParameters:null));
}
catch(e){}
oRequest.stopped=false;
return oRequest;
}


/**
 * updates the element with given sID,by calling the given PHP and replacing 
 * the element with the result of that callback;
 * NOTE: does not work with TD and TR yet
 * @param String sID
 * @param String sPHPCallback
 * @param String sLoadingGif
 * @param String sJScript
 * @return void
 */
function updateElement(sID,sPHPCallback,sLoadingGif,sJScript,sOverlayClassName){
if(bSubmitting)return;
if(!isDefined(sLoadingGif)|| !sLoadingGif)sLoadingGif='loading.gif';
if(!bPageLoaded||!document.body){
getJSCall('updateElement',[sID,sPHPCallback,sLoadingGif,sJScript,sOverlayClassName]);
setTimeout(getJSCall('updateElement',[sID,sPHPCallback,sLoadingGif,sJScript,sOverlayClassName]),500);
return;
}

sPHPCallback=sPHPCallback.replace(/&amp;/g,'&');

var objElement=getObj(sID);
if(!objElement){
Log.write('obj "'+sID+'" not found');
return;
}


var oPos=getElementPosition(objElement);
var iWidth=objElement.offsetWidth;
var iHeight=objElement.offsetHeight;
var divOverlay=document.createElement('div');
setObjMultStyle(divOverlay,
['position','left','top','width','height','zIndex'],
['absolute',oPos.left+'px',oPos.top+'px',iWidth+'px',iHeight+'px','10']);
if(isDefined(sOverlayClassName))
divOverlay.className=sOverlayClassName;
else setObjStyle(divOverlay,'backgroundColor','white');

var imgLoading=document.createElement('img');
if(sLoadingGif.substr(0,4)=='http'&&sLoadingGif.indexOf(':\/\/')!=-1)
imgLoading.src=sLoadingGif;
else imgLoading.src='/images/'+sLoadingGif;
setObjMultStyle(imgLoading,['marginTop','marginLeft'],
[(iHeight*0.5 - 16)+'px',(iWidth*0.5 - 16)+'px']);
divOverlay.appendChild(imgLoading);
var aSelects=objElement.getElementsByTagName('select');
for(var i=0;i<aSelects.length;i++)
setObjStyle(aSelects.item(i),'display','none');
document.body.appendChild(divOverlay);

sendRequest(sPHPCallback,null,false,'updateElementResponse',
{sID: sID,sJScript: sJScript,divOverlay: divOverlay});
}


/**
 * reponse of the XMLHttpRequest object that called php to update the given
 * element
 * @param XMLHttpRequest xmlhttp
 * @param object oParam
 * @return void
 */
function updateElementResponse(xmlhttp,oParam){
var objElement=getObj(oParam.sID);
var newNode=document.createElement('span');
newNode.innerHTML=xmlhttp.responseText;
if(bIE)
objElement.outerHTML=xmlhttp.responseText;
else objElement.parentNode.replaceChild(newNode,objElement);

objElement=getObj(oParam.sID);


if(bIE)var aJScripts=newNode.getElementsByTagName('script');
else var aJScripts=[];

for(var i=0;i<aJScripts.length;i++){
var oJScript=aJScripts.item(i);
Log.write('eval('+oJScript.innerHTML+');');
eval(oJScript.innerHTML);
if(!bIE)objElement.getElementsByTagName('script').item(i).innerHTML='';
}

if(isDefined('MES',true))MES.recalculateAcceptPositions();
if(isDefined(oParam.sJScript)&& oParam.sJScript)
eval(oParam.sJScript);
try { document.body.removeChild(oParam.divOverlay);}
catch(e){}
}


function setExtending(sSubClass,sSuperClass){
eval("if(isDefined("+sSubClass+")&& isDefined("+sSuperClass+")){"+
sSubClass+".prototype=new "+sSuperClass+"();} "+
 "else { setTimeout(\"setExtending('"+sSubClass+"','"+sSuperClass+"');\"," +
"500);}");
}


/**
* checks if given object is an instance of given constructor
* @return bool
*/
function instanceOf(object,constructor){
while(object !=null){ 
if(object==constructor.prototype)
return true;
object=object.__proto__;
}
return false;
}


/**
 * returns the classname of the given object as a string 
 * @return String
 */
function getClassName(obj){
if(typeof obj !="object"||obj==null)
return typeof obj;
return /(\w+)\(/.exec(obj.constructor.toString())[1];
}


/**
 * adds an eventhandler for given event(without the 'on' prefix!!)to the given object.
 * @example addObjEvent(divTest,'click',testFunction);
 * @example addObjEvent(divTest,'click',function(){ alert('test');});
 * @param HTMLElement objElement
 * @param String sEvent
 * @param Function fnFunction
 * @return void
 */
function addObjEvent(objElement,sEvent,fnFunction){
EventManager.Add(objElement,sEvent,fnFunction);
}


/**
* encodes string to URL format
* @return String
*/
function encodeHtml(sHTML){
if(Utf8.useUTF8)return encodeURIComponent(sHTML);
else {
sHTML=escape(sHTML);
sHTML=sHTML.replace(/%u20AC/g,"%80");
sHTML=sHTML.replace(/\//g,"%2F");
sHTML=sHTML.replace(/\+/g,'%2B');
sHTML=sHTML.replace(/@/g,"%40");
return sHTML;
}
} 


/**
* refreshes current page.
* @return void
*/
function refreshPage(){

var sCurLoc=window.location.href;

if(sCurLoc.indexOf('?')!=-1){
var iRefreshPos=sCurLoc.indexOf('refresh=');
if(iRefreshPos !=-1){
var sRefreshString=sCurLoc.substr(iRefreshPos);
var iEndPos=sRefreshString.indexOf('&');
var sStartString=sCurLoc.substr(0,iRefreshPos);
var iEqualPos=sRefreshString.indexOf('=')+1;
if(iEndPos !=-1){
var iNumber=parseInt(sRefreshString.substring(iEqualPos,iEndPos));
sCurLoc=sStartString + 'refresh='+(++iNumber)+ sRefreshString.substr(iEndPos);
}
else {
var iNumber=parseInt(sRefreshString.substr(iEqualPos));
sCurLoc=sStartString + 'refresh='+(++iNumber);
}
}
else sCurLoc +='&refresh=1';
}
else sCurLoc +='?refresh=1';
window.location.href=sCurLoc;
}


/**
* returns the source of the given array
* @return String
*/
function arrayToSource(aArray){
var sArray='';
var bAssoc=true;
if(isDefined(aArray[0]))bAssoc=false;

for(var iIndex in aArray){
if(bAssoc){
sArray +=','+iIndex+':'+paramToString(aArray[iIndex]);
}
else {
if(isNumeric(aArray[iIndex]))sArray +=',' + aArray[iIndex];
else sArray +=',\'' + aArray[iIndex]+'\'';
}
}
if(bAssoc&&sArray.length > 0)sArray='{'+sArray.substring(1)+'}';
else sArray='['+sArray.substring(1)+']';
return sArray;
}


/**
* returns the given array as a string representation
* @return String
*/
function arrayToString(aArray){
if(!(typeof aArray=='array'||typeof aArray=='object'))
		return aArray;	
var sArray='';
for(var sIndex in aArray)
sArray +=',' + sIndex + '=> ' + arrayToString(aArray[sIndex]);
sArray='['+sArray.substring(2)+']';
return sArray;
}

/**
 * function that returns a param string corresponding to the contents
 * of the array. Param will begin with given sParamName
 * Example: array=['number1'=>2,'number2'=>5,'test','other Text'];
 *call=arrayToParamString(array,'par');
 *result='parnumber1=2&parnumber2=5&par0=test&par1=other%20Text';
 * @return String
 */
function arrayToParamString(aArray,sParamName){
var sParamString='';
for(var sIndex in aArray)
sParamString +='&' + sParamName+sIndex + '=' + encodeHtml(aArray[sIndex]);
return sParamString.substring(1);
}


/**
 * returns the last element of the given array. if the given array is not an
 * array of it is empty,then it will return null
 * @return mixed
 */
function arrayGetLast(aArray){
if(isArray(aArray)){
if(aArray.length > 0)
return aArray[aArray.length-1];
}
return null;
}


/**
 * equivalent of PHP print_r
 * @param Object obj
 * @param bool bReturn(default false)
 * @return String or void
 */
function print_r(obj,bReturn){

var pad=function(iDim){
sPadding='';
for(var i=0;i<iDim;i++)sPadding +=sPad;
return sPadding;
};

var getObjRepresentation=function(obj,iDim){
if(obj==null)return 'null';
var sReturn='';
try {
switch(typeof obj){
case 'string':
case 'number':
sReturn=String(obj);
if(sReturn.length > 200)
sReturn=sReturn.substr(0,200);
break;
case 'object':
sReturn='Array {\n' +(iDim > 1?'':outputFormat(obj,iDim))+
pad(iDim)+ '}';
break;
default:
sReturn=(typeof obj)+ '('+String(obj)+')';
}
} catch(e){}
return sReturn;
};

var outputFormat=function(obj,iDim){
var sReturn='';
for(var key in obj){
if(isArray(obj[key])){
sReturn +=sPad + pad(iDim)+ '[' + key + ']=> Array {\n' +
 outputFormat(obj[key],iDim + 1)+ 
 '\n'+sPad + pad(iDim)+ '}\n';
}
else if((typeof obj[key]).toLowerCase()=='function'){
var sFunction=String(obj[key]);
sReturn +=sPad + pad(iDim)+ '[' + key + ']=> ' + 
 sFunction.substr(0,sFunction.indexOf('{'))+ '{ }\n';
}
else
sReturn +=sPad + pad(iDim)+ '[' + key + ']=> ' + 
 getObjRepresentation(obj[key],iDim+1)+ '\n';
}
return sReturn;
};

if(!isDefined(bReturn))bReturn=false;
var iDim=0;
var sPad='\xA0\xA0\xA0\xA0\xA0';
var sReturn=getObjRepresentation(obj,iDim);
if(bReturn)return sReturn;
else Log.writeText(sReturn);
}


/**
 * returns the length of the array. Works also on assoc. arrays
 * @param Array array
 * @return int
 */
function count(array){
var iCount=array.length;
var bAssoc=false;
for(var sIndex in array){
if(iCount==0)bAssoc=true;
break;
}
if(bAssoc)for(var sIndex in array)iCount++;

return iCount;
}


/**
 * sets each item in the array to null
 * @param Array array
 * @return void
 */
function clearArray(array){
for(var sIndex in array)
array[sIndex]=null;
}


/**
* returns the given string with the first character in upper case
* @return String
*/
function ucfirst(sString){
var sFirstChar=sString.substr(0,1);
return sFirstChar.toUpperCase()+ sString.substring(1);
}


/**
 * create a cookie with a name,value and expirement in days
 * @param String sName
 * @param String sValue
 * @param int iDays - default 0(then max_date(2038)will be used)
 * @param boolean bUnixTime - default false
 * @return void
 */
function createCookie(sName,sValue,iDays,bUnixTime){
if(!isDefined(bUnixTime))bUnixTime=false;
if(!isDefined(iDays))iDays=0;
var sExpires="";
if(!iDays){
iDays=2147483647;
bUnixTime=true;
}
		var dtDate=new Date();
		if(bUnixTime)dtDate.setTime(iDays*1000);
		else dtDate.setTime(dtDate.getTime()+(iDays*24*60*60*1000));
		sExpires=";expires="+dtDate.toGMTString();
	document.cookie=escape(sName)+"="+escape(sValue)+sExpires+";path=/";
}


/**
 * reads a cookie's value
 * @param String sName
 * 
 * @return String
 */
function readCookie(sName){
	var sNameEQ=sName + "=";
	var aCookies=getAllCookies();
if(isDefined(aCookies[sName]))return aCookies[sName];
	else return null;
}


/**
 * returns all cookie values in an assoc. array
 * @return array
 */
function getAllCookies(){
var aCookies=document.cookie.split(';');
var aValues={};
	for(var i=0;i < aCookies.length;i++){
var aCookieValue=aCookies[i].split('=');
aValues[String(unescape(aCookieValue[0])).trim()]=unescape(aCookieValue[1]);
	}
	return aValues;
}


/**
 * erase the cookie with the given name
 * @param String sName
 * 
 * @return void
 */
function eraseCookie(sName){
	createCookie(sName,"",-1);
}


/**
 * get a string with the function call of given function with
 * given params
 * @param String sFunctionName
 * @param array aParams
 * @return String
 */
function getJSCall(sFunctionName,aParams){
var sJSCall=sFunctionName+'(';
for(var i=0;i<aParams.length;i++){
sJSCall +=paramToString(aParams[i]);
if(i !=aParams.length-1)sJSCall +=',';
}
sJSCall +=');';
return sJSCall;
}


/**
 * returns a string representation of the given mixed input
 * @param mixed oParam
 * @return String
 */
function paramToString(oParam){
var sParam='';
if(!isDefined(oParam))sParam +='undefined';
else if(oParam==null)sParam +='null';
else if(isArray(oParam)|| typeof oParam=='object')sParam +=arrayToSource(oParam);
else if(isNumeric(oParam)|| oParam=='this')
sParam +=oParam;
else if((oParam===true||oParam===false)&& oParam !=='')
sParam +=String(oParam);
else {
if(String(oParam).indexOf('.')!=-1)sParam +=oParam;
else sParam +="'"+oParam+"'";
}
return sParam;
}


/**
 * equivalent function as the PHP variant
 * 
 * @params String sString
 * @return String
 */
function htmlEntities(sString){
var aChars=new Array(38,224,225,226,227,228,229,230,231,232,233,234,235,236,
237,238,239,240,241,242,243,244,245,246,248,249,250,251,
252,253,254,255,192,193,194,195,196,197,198,199,200,201,
202,203,204,205,206,207,208,209,210,211,212,213,214,216,
217,218,219,220,221,222,8364,34,223,60,62,162,163,164,165,
166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,
181,182,183,184,185,186,187,188,189,190);

var aEntities=new Array('amp','agrave','aacute','acirc','atilde','auml','aring',
'aelig','ccedil','egrave','eacute','ecirc','euml','igrave',
'iacute','icirc','iuml','eth','ntilde','ograve','oacute',
'ocirc','otilde','ouml','oslash','ugrave','uacute','ucirc',
'uuml','yacute','thorn','yuml','Agrave','Aacute','Acirc',
'Atilde','Auml','Aring','AElig','Ccedil','Egrave','Eacute',
'Ecirc','Euml','Igrave','Iacute','Icirc','Iuml','ETH','Ntilde',
'Ograve','Oacute','Ocirc','Otilde','Ouml','Oslash','Ugrave',
'Uacute','Ucirc','Uuml','Yacute','THORN','euro','quot','szlig',
'lt','gt','cent','pound','curren','yen','brvbar','sect','uml',
'copy','ordf','laquo','not','shy','reg','macr','deg','plusmn',
'sup2','sup3','acute','micro','para','middot','cedil','sup1',
'ordm','raquo','frac14','frac12','frac34');
for(var i=0;i < aChars.length;i++){
var iStart=0;
var iPos=-1;
while((iPos=sString.indexOf(String.fromCharCode(aChars[i]),iStart))!=-1){
sString=sString.substr(0,iPos)+ '&' + aEntities[i] + ';' + sString.substr(iPos+1);
iStart=iPos + aEntities[i].length +2;
}
}
return sString;
}


/**
 * draws a Line between the given points
 * returns the div(s)that are created to draw this line;
 * 1 div for a straight line,multiple divs for a 
 * @param int x1
 * @param int x1
 * @param int x1
 * @param int x1
 * @param int iWidth
 * @param String sColor
 * @param int iBorderWidth
 * @param String sBorderColor
 * @return HTMLElement([])
 */
function drawLine(x1,y1,x2,y2,iWidth,sColor,iBorderWidth,sBorderColor){
if(!isDefined(iBorderWidth))iBorderWidth=0;
if(!isDefined(sBorderColor))sBorderColor=null;
var dX=Math.abs(x2-x1);
var dY=Math.abs(y2-y1);
if(dY==0||dX==0){ 
if(dX==0&&dY==0)return null;
var divLine=document.createElement('div');
setObjMultStyle(divLine,
['position','top','left','width','height','backgroundColor','fontSize'],
['absolute',Math.min(y1,y2)+'px',Math.min(x1,x2)+'px',
(dX==0?iWidth:dX)+'px',(dY==0?iWidth:dY)+'px',sColor,'1px']);
if(iBorderWidth)
setObjStyle(divLine,'border','solid '+iBorderWidth+'px '+sBorderColor);
if(bPageLoaded)document.body.appendChild(divLine);
return divLine;
}
else {
var aDivs=new Array();
var fIncr;
if(dX > dY)fIncr=dX /(dY+1);
else fIncr=dY /(dX+1);

var fRest=0.0;
var iTo=Math.min(dX,dY)+1;
var iYMultiply=y2-y1>0 ? 1 : -1;
var iXMultiply=x2-x1>0 ? 1 : -1;
var oTo=new Pixel(x2,y2);
x2=x1;y2=y1;
for(var i=0;i<iTo;i++){
if(i > 0){
if(dX > dY){
y1 +=iYMultiply;y2=y1;
}
else {
x1 +=iXMultiply;x2=x1;
}
}

var fPlus=fIncr + fRest;
fRest=fPlus - Math.floor(fPlus);
var iPlus=Math.floor(fPlus);

if(i==iTo-1){
x2=oTo.left;
y2=oTo.top;
}
else {
if(dX > dY)x2=x1 + iPlus*iXMultiply;
else y2=y1 + iPlus*iYMultiply;
}

aDivs.push(drawLine(x1,y1,x2,y2,iWidth,sColor,iBorderWidth,sBorderColor));

if(dX > dY)x1=x2;
else y1=y2;
}

return aDivs;
}
}



/**
 * #############################################################
 * #Standard Objects Extending #
 * #(do not extend the Array object! If you do,the function #
 * # name is added as a key with the function itself as value#
 * # to the Array and will come by with the#
 * # for(var i in array)statement...)#
 * #############################################################
 */

/**
 * ---------------------------
 * String
 * ---------------------------
 */
 
/**
 * returns true if string is numeric
 * @return bool
 */
String.prototype.isNumeric=function(){
return isNumeric(this);
};


/**
 * trims this string
 * @return String
 */
String.prototype.trim=function(){
var sString=this.replace(/^\s+/g,"");
return sString.replace(/\s+$/g,"");
};


/**
 * ---------------------------
 * Number
 * ---------------------------
 */

/**
 * returns string with this number padded with '0' to given length of iTotalDigits
 * @return String
 */
Number.prototype.padDigits=function(iTotalDigits){
return padDigits(this,iDigits);
};

/**
 * this class is used to set a class name to an item and remove that classname
 * when an other item in the same group is clicked
 */
function SwitchClasses(){
this.aOrigClasses=new Array();
}

/**
 * @param string sElementID - ID of the element that must have sClassname as a class
 * @param string sGroup - Group where sElementID belongs to
 * @param string sClassname
 * @return void
 */
SwitchClasses.prototype.setItemClass=function(sElementID,sGroup,sClassname,bAddClass){
var obj=getObj(sElementID);
if(!obj)return;
if(!isDefined(this.aOrigClasses[sGroup]))
this.aOrigClasses[sGroup]=new Array();
this.aOrigClasses[sGroup][sElementID]=obj.className;
if(bAddClass)obj.className +=' '+sClassname;
else obj.className=sClassname;

for(var sClassGroup in this.aOrigClasses){
if(sClassGroup==sGroup){
for(var sID in this.aOrigClasses[sClassGroup]){
if(sID !=sElementID)
getObj(sID).className=this.aOrigClasses[sClassGroup][sID];
}
}
}
};

var SC=new SwitchClasses();


Timeout.iLastID=1;
Timeout.aTimeouts={};

/**
 * starts a timeout that can be cancelled and calls back a function on an object
 * @param int iMS
 * @param Function fnCaller
 * @param Object objCaller(optional)
 * @param Object oParam(optional)
 */
function Timeout(iMS,fnCaller,objCaller,oParam){
if(!isDefined(objCaller))objCaller=window;
if(!isDefined(oParam))oParam=null;

this.iID=Timeout.iLastID++;
Timeout.aTimeouts['TO_'+this.iID]={objCaller: objCaller,
 fnCaller: fnCaller,
 oParam: oParam};
Timeout.aTimeouts['TO_'+this.iID].iTimeoutID=
setTimeout("Timeout.prototype.timeoutPassed.call(window,"+this.iID+");",
 iMS);
}


/**
 * cancels this timeout
 * @return void
 */
Timeout.prototype.cancelTimeout=function(){
clearTimeout(Timeout.aTimeouts['TO_'+this.iID].iTimeoutID);
delete Timeout.aTimeouts['TO_'+this.iID];
};


/**
 * called when a timeout has passed
 * @return void
 */
Timeout.prototype.timeoutPassed=function(iID){
var oCaller=Timeout.aTimeouts['TO_'+iID];
oCaller.fnCaller.call(oCaller.objCaller,oCaller.oParam);
delete Timeout.aTimeouts['TO_'+iID];
};

/**
 * @constructor
 * @return DatePicker
 */
function DatePicker(){
this.aValues=new Array();
this.aMonths=new Array();
this.aDays=new Array();
this.bShowing=false;
this.sShownDateID='';
this.divDP=null;
this.oDateFormat={d: {iStart:0,iLength:0},
m: {iStart:0,iLength:0},
y: {iStart:0,iLength:0},
separator: '-'};
this.sTodayText='Today';
this.oImages=null;
this.sCloseImg=null;
this.cmbMonths=null;
this.cmbYears=null;
this.oCurDates=new Array();
this.bEnableHeaderClick=true;
this.iStartDay=1;
}


/**
 * sets the monthnames for the datepickers on the current page
 * @param array aMonthNames
 * @return void
 */
DatePicker.prototype.init=function(aMonthNames,aDayNames,
 sDateFormat,sTodayText){
this.aMonths=aMonthNames;
this.aDays=aDayNames;
this.sTodayText=sTodayText;


sDateFormat=sDateFormat.toLowerCase();
var aSearch=['d','m','y'];
for(var i=0;i<aSearch.length;i++){
var iStart=sDateFormat.indexOf(aSearch[i]);
eval("this.oDateFormat."+aSearch[i]+".iStart="+iStart+";");
var iLength=0;
while(sDateFormat.substr(iStart,1)==aSearch[i]){
iLength++;
iStart++;
}
eval("this.oDateFormat."+aSearch[i]+".iLength="+iLength+";");
}
this.oDateFormat.separator=sDateFormat.substr(
this.oDateFormat.d.iStart+this.oDateFormat.d.iLength,1);



this.cmbMonths=document.createElement('select');
for(var i=0;i<12;i++){
var oOption=document.createElement('option');
oOption.value=i;
oOption.innerHTML=this.aMonths[i];
this.cmbMonths.appendChild(oOption);
}
this.cmbMonths.onfocus=function(){ this.blur();};
setObjStyle(this.cmbMonths,'display','none');
};


/**
 * set the start day of the day grid(0=sunday,1=monday,etc.)
 * @param int iStartDay
 * @return void
 */
DatePicker.prototype.setStartDay=function(iStartDay){
this.iStartDay=iStartDay;
};


/**
 * create div for the datepicker
 * @return void
 */
DatePicker.prototype.createPickerDiv=function(){
if(!bPageLoaded){
setTimeout('DP.createPickerDiv();',100);
return;
}

if(this.divDP){
try { document.body.removeChild(this.divDP);}
catch(e){}
}


this.divDP=document.createElement('div');
setObjMultStyle(this.divDP,['display','position'],
['none','absolute']);
document.body.appendChild(this.divDP);
};


/**
 * set the images that will be used by all datepickers on current page
 * @param string sLeftImg
 * @param string sRightImg
 * @return void
 */
DatePicker.prototype.setImages=function(sLeftImg,sRightImg){
this.oImages={sLeftImg: sLeftImg,sRightImg: sRightImg};
};


/**
 * set the close image that will be used by all datepickers on this page
 * @param string sCloseImg
 * @return void
 */
DatePicker.prototype.setCloseImage=function(sCloseImg){
this.sCloseImg=sCloseImg;
};


/**
 * shows the datepicker for given ID
 * @param string sDateID
 * @param string sClassName
 * @param string sAlignID
 * @param bool bHideOn2nd
 * @return void
 */
DatePicker.prototype.showDatepicker=function(sDateID,sClassName,sAlignID,
 bHideOn2nd){
if(this.sShownDateID==sDateID&&bHideOn2nd){
this.hideDatePicker();
return;
}
if(!bHideOn2nd&&!(getObjStyle(this.divDP,'display')=='block'))
return;

this.sShownDateID=sDateID;


var iDate=this.parseDate(sDateID);
if(iDate !=null)var dtDate=new Date(iDate);
else var dtDate=new Date();

this.oCurDates[sDateID]={d: dtDate.getDate(),m: dtDate.getMonth(),
 y: dtDate.getFullYear()};
 

this.fillDatePicker(sDateID,sClassName,dtDate,true);
var oPos=getElementPosition(getObj(sAlignID));
setObjMultStyle(this.divDP,['left','top','display'],
[(oPos.left+1)+'px',(oPos.top+getObj(sAlignID).offsetHeight+5)+'px','block']);
};


/**
 * fills datepicker div
 * @param Date dtDate
 * @return void
 */
DatePicker.prototype.fillDatePicker=function(sDateID,sClassName,dtDate,
 bNew){

if(bNew){
if(!dtDate)return;
var divHeader=this.getDPHeaderDiv(sDateID,dtDate);
this.createPickerDiv();
this.divDP.className=sClassName;
this.divDP.appendChild(divHeader);

MoveElement.setDraggable(this.divDP,divHeader);
}


var divDayGrid=this.getDayGridDiv(sDateID);


if(getObj('DPDayGrid'))
this.divDP.replaceChild(divDayGrid,getObj('DPDayGrid'));
else this.divDP.appendChild(divDayGrid);

/************************ Today button *****************************/
if(bNew){
var divToday=document.createElement('div');
divToday.id='DPTodayDiv';
setObjStyle(divToday,'clear','both');
var btnToday=document.createElement('input');
btnToday.type='button';
btnToday.value=this.sTodayText;
btnToday.id='DPTodayButton';
btnToday.onclick=function(){
var dtNow=new Date();
DP.oCurDates[sDateID]={ d: dtNow.getDate(),m: dtNow.getMonth(),
y: dtNow.getFullYear()};
getObj('DPMonthname').innerHTML=DP.aMonths[dtNow.getMonth()];
getObj('DPYearname').innerHTML=dtNow.getFullYear();
getObj('cmbDPMonths').selectedIndex=dtNow.getMonth();
getObj('cmbDPYears').selectedIndex=dtNow.getFullYear()- 
DP.aValues[sDateID].iMinYear;
getObj(sDateID).value=DP.getFormattedDate(dtNow);
DP.fillDatePicker(sDateID,sClassName,new Date(),false);
};
divToday.appendChild(btnToday);
this.divDP.appendChild(divToday);
}
/************************ END Today button *************************/
};


/**
 * creates a div that can be used as a header for the datepicker;this header
 * includes a month and year selection
 * @param string sDateID
 * @param Date dtDate
 * @return HTMLElement(Div)
 */
DatePicker.prototype.getDPHeaderDiv=function(sDateID,dtDate){
var divHeader=document.createElement('div');
divHeader.id='DP_header';
divHeader.onclick=function(){
if(!DP.bEnableHeaderClick){
DP.bEnableHeaderClick=true;
return;
}
setStyle('cmbDPMonths','display','none');
setStyle('cmbDPYears','display','none');
setStyle('DPMonthname','display','block');
setStyle('DPYearname','display','block');
};

var tblHeader=document.createElement('table');
tblHeader.id='DPHeaderTable';
var tHeaderBody=document.createElement('tbody');
var trHeader=document.createElement('tr');
tHeaderBody.appendChild(trHeader);tblHeader.appendChild(tHeaderBody);


if(this.oImages){
var tdLeftImg=document.createElement('td');
tdLeftImg.id='DPPrevMonth';
var aLeft=document.createElement('a');
aLeft.href='javascript: void(0);';
aLeft.onfocus=function(){ this.blur();};
aLeft.onclick=function(){
DP.oCurDates[sDateID].m--;
if(DP.oCurDates[sDateID].m < 0){
DP.oCurDates[sDateID].m=11;DP.oCurDates[sDateID].y--;
if(DP.oCurDates[sDateID].y < DP.aValues[sDateID].iMinYear){
DP.oCurDates[sDateID].m=00;DP.oCurDates[sDateID].y++;
return false;
}
}
getObj('DPMonthname').innerHTML=DP.aMonths[DP.oCurDates[sDateID].m];
getObj('DPYearname').innerHTML=DP.oCurDates[sDateID].y;
getObj('cmbDPMonths').selectedIndex=DP.oCurDates[sDateID].m;
getObj('cmbDPYears').selectedIndex=DP.oCurDates[sDateID].y - 
 DP.aValues[sDateID].iMinYear;

DP.fillDatePicker(sDateID,null,new Date(
Date.UTC(DP.oCurDates[sDateID].y,DP.oCurDates[sDateID].m,1)),false);
};
var imgLeft=document.createElement('img');
imgLeft.src=this.oImages.sLeftImg;
aLeft.appendChild(imgLeft);
tdLeftImg.appendChild(aLeft);
trHeader.appendChild(tdLeftImg);
} 
 

var tdMonth=document.createElement('td');
tdMonth.className='rightAlign';
var tdYear=document.createElement('td');


var cmbMonths=this.cmbMonths.cloneNode(true);
cmbMonths.id='cmbDPMonths';

var cmbYears=document.createElement('select');
for(var i=this.aValues[sDateID].iMinYear;i<=this.aValues[sDateID].iMaxYear;i++){
var oOption=document.createElement('option');
oOption.value=i;oOption.innerHTML=i;
cmbYears.appendChild(oOption);
}
setObjMultStyle(cmbYears,['display'],['none']);
cmbYears.id='cmbDPYears';


cmbMonths.selectedIndex=dtDate.getMonth();
cmbYears.selectedIndex=(dtDate.getFullYear()- this.aValues[sDateID].iMinYear);


cmbMonths.onclick=function(){ DP.bEnableHeaderClick=false;};
cmbMonths.onchange=function(){ 
setObjStyle(this,'display','none');
getObj('DPMonthname').innerHTML=DP.aMonths[this.value];
setStyle('DPMonthname','display','block');
DP.oCurDates[sDateID].m=parseInt(this.value,10);
var dtNewDate=new Date(Date.UTC(DP.oCurDates[sDateID].y,
DP.oCurDates[sDateID].m,
DP.oCurDates[sDateID].d));
DP.fillDatePicker(sDateID,null,dtNewDate,false);
};
cmbYears.onclick=function(){ DP.bEnableHeaderClick=false;};
cmbYears.onchange=function(){ 
setObjStyle(this,'display','none');
getObj('DPYearname').innerHTML=this.value;
setStyle('DPYearname','display','block');
DP.oCurDates[sDateID].y=parseInt(this.value,10);
var dtNewDate=new Date(Date.UTC(DP.oCurDates[sDateID].y,
DP.oCurDates[sDateID].m,
DP.oCurDates[sDateID].d));
DP.fillDatePicker(sDateID,null,dtNewDate,false);
};


var aMonth=document.createElement('a');
aMonth.href='javascript: void(0);';
aMonth.onfocus=function(){ this.blur();};
aMonth.onclick=function(){
DP.bEnableHeaderClick=false;
setObjStyle(this,'display','none');
setStyle('cmbDPYears','display','none');
setStyle('DPYearname','display','block');
setStyle('cmbDPMonths','display','block');
};
aMonth.innerHTML=this.aMonths[dtDate.getMonth()];
aMonth.id='DPMonthname';

var aYear=document.createElement('a');
aYear.href='javascript: void(0);';
aYear.onfocus=function(){ this.blur();};
aYear.onclick=function(){
DP.bEnableHeaderClick=false;
setObjStyle(this,'display','none');
setStyle('cmbDPMonths','display','none');
setStyle('DPMonthname','display','block');
setStyle('cmbDPYears','display','block');
};
aYear.innerHTML=dtDate.getFullYear();
aYear.id='DPYearname';
setObjMultStyle([aYear,aMonth],['display'],['block']);


tdMonth.appendChild(aMonth);
tdMonth.appendChild(cmbMonths);
tdYear.appendChild(aYear);
tdYear.appendChild(cmbYears);
trHeader.appendChild(tdMonth);
trHeader.appendChild(tdYear);


if(this.oImages){
var tdRightImg=document.createElement('td');
tdRightImg.id='DPNextMonth';
var aRight=document.createElement('a');
aRight.href='javascript: void(0);';
aRight.onfocus=function(){ this.blur();};
aRight.onclick=function(){
DP.oCurDates[sDateID].m++;
if(DP.oCurDates[sDateID].m > 11){
DP.oCurDates[sDateID].m=0;DP.oCurDates[sDateID].y++;
if(DP.oCurDates[sDateID].y > DP.aValues[sDateID].iMaxYear){
DP.oCurDates[sDateID].m=11;DP.oCurDates[sDateID].y--;
return false;
}
}
getObj('DPMonthname').innerHTML=DP.aMonths[DP.oCurDates[sDateID].m];
getObj('DPYearname').innerHTML=DP.oCurDates[sDateID].y;
getObj('cmbDPMonths').selectedIndex=DP.oCurDates[sDateID].m;
getObj('cmbDPYears').selectedIndex=DP.oCurDates[sDateID].y - 
 DP.aValues[sDateID].iMinYear;

DP.fillDatePicker(sDateID,null,new Date(
Date.UTC(DP.oCurDates[sDateID].y,DP.oCurDates[sDateID].m,1)),false);
};
var imgRight=document.createElement('img');
imgRight.src=this.oImages.sRightImg;
aRight.appendChild(imgRight);
tdRightImg.appendChild(aRight);
trHeader.appendChild(tdRightImg);
} 

divHeader.appendChild(tblHeader);


if(this.sCloseImg){
var aClose=document.createElement('a');
aClose.href='javascript: void(0);';
aClose.onfocus=function(){ this.blur();};
aClose.onclick=function(){ DP.hideDatePicker();};
aClose.id='DPClose';
var imgClose=document.createElement('img');
imgClose.src=this.sCloseImg;
aClose.appendChild(imgClose);
divHeader.appendChild(aClose);
}
return divHeader;
};


/**
 * get day grid Div element;this includes date selecting
 * @param string sDateID
 * @return HTMLElement(Div)
 */
DatePicker.prototype.getDayGridDiv=function(sDateID){
var divDayGrid=document.createElement('div');
divDayGrid.id='DPDayGrid';
setObjStyle(divDayGrid,'clear','both');

var tblDays=document.createElement('table');
tblDays.id='DPDayGridTable';
tblDays.cellSpacing="0";
var tBody=document.createElement('tbody');


var trWeekDays=document.createElement('tr');
trWeekDays.id='DPWeekdayRow';
var iStart=this.iStartDay;var iEnd=this.iStartDay+6;
for(var i=iStart;i<=iEnd;i++){
var tdWeekday=document.createElement('th');
tdWeekday.innerHTML=this.aDays[i>6?i-7:i];
trWeekDays.appendChild(tdWeekday);
}
tBody.appendChild(trWeekDays);


var iDayLength=24*60*60*1000;
var dtFirstDate=new Date(Date.UTC(this.oCurDates[sDateID].y,
this.oCurDates[sDateID].m,1));
while(dtFirstDate.getDay()!=iStart)
dtFirstDate=new Date(dtFirstDate.getTime()-iDayLength);


if(iEnd > 6)iEnd=iEnd-7;
var dtLastDate=new Date(Date.UTC(this.oCurDates[sDateID].y,
 this.oCurDates[sDateID].m+1,1)-iDayLength);
while(dtLastDate.getDay()!=iEnd)
dtLastDate=new Date(dtLastDate.getTime()+iDayLength);
 


var iDate=this.parseDate(sDateID);
if(iDate !=null)var dtSelectedDate=new Date(iDate);
else var dtSelectedDate=new Date();


var iCounter=0;
var dtCurDate=dtFirstDate;
while(dtCurDate.getTime()<=dtLastDate.getTime()){

if(iCounter % 7==0){
var trDayRow=document.createElement('tr');
trDayRow.className='DPDayRow';
tBody.appendChild(trDayRow);
}

var tdDay=document.createElement('td');

if(dtCurDate.getMonth()!=this.oCurDates[sDateID].m)
tdDay.className='DPGreyDay';
else tdDay.className='DPNormalDay';
if(dtCurDate.getTime()==dtSelectedDate.getTime())
tdDay.className +=' DPSelectedDay';
if(dtCurDate.getDay()==6||dtCurDate.getDay()==0)
tdDay.className +=' DPWeekendDay';

var aDay=document.createElement('a');
aDay.href='javascript: void(0);';
aDay.innerHTML=dtCurDate.getDate();

aDay.onclick=function(){ 
getObj(sDateID).value=DP.getFormattedDate(new Date(
Date.UTC(DP.oCurDates[sDateID].y,DP.oCurDates[sDateID].m,this.innerHTML)));
DP.hideDatePicker();
setFocus(sDateID);
};
tdDay.appendChild(aDay);
trDayRow.appendChild(tdDay);

dtCurDate=new Date(dtCurDate.getTime()+ iDayLength);
iCounter++;
}

tblDays.appendChild(tBody);
divDayGrid.appendChild(tblDays);
return divDayGrid;
};


/**
 * returns a formatted date,according to the formatting rules stored in
 * oDateFormat
 * @param Date dtDate
 * @return void
 */
DatePicker.prototype.getFormattedDate=function(dtDate){
if(!dtDate)return null;
return padDigits(dtDate.getDate(),DP.oDateFormat.d.iLength)+ 
 DP.oDateFormat.separator +
 padDigits(dtDate.getMonth()+1,DP.oDateFormat.m.iLength)+ 
 DP.oDateFormat.separator +
 padDigits(dtDate.getFullYear(),DP.oDateFormat.y.iLength);
};


/**
 * returns the timestamp that belongs to the value of the datebox with sDateID
 * return value is the amount of milliseconds since midnight of January 1,1970
 * return value can be null,due to an incorrect input
 * @return int
 */
DatePicker.prototype.parseDate=function(sDateID){
var sDate=getObj(sDateID).value;
var iDay=parseInt(sDate.substr(this.oDateFormat.d.iStart,
 this.oDateFormat.d.iLength),10);
var iMonth=parseInt(sDate.substr(this.oDateFormat.m.iStart,
 this.oDateFormat.m.iLength),10);
var iYear=parseInt(sDate.substr(this.oDateFormat.y.iStart,
 this.oDateFormat.y.iLength),10);
if(isNaN(iDay)|| isNaN(iMonth)|| isNaN(iYear))return null;
return Date.UTC(iYear,iMonth-1,iDay);
};


/**
 * hide the current DatePicker
 * @return void
 */
DatePicker.prototype.hideDatePicker=function(){
if(DP.bShowing){
DP.bShowing=false;
return;
}
this.sShownDateID='';

if(this.divDP){
setObjStyle(this.divDP,'display','none');
try { document.body.removeChild(this.divDP);}
catch(e){}
}
};


/**
 * sets the required values for the datebox with sDateID
 * @param string sDateID
 * @param int iMinYear
 * @param int iMaxYear
 * @param int iDefaultTime
 * @return void
 */
DatePicker.prototype.setValues=function(sDateID,iMinYear,iMaxYear,iDefaultTime){
this.aValues[sDateID]={ iMinYear: iMinYear,iMaxYear: iMaxYear,iDate: iDefaultTime};
};
 

var DP=new DatePicker();
/**
 * This is a 'singleton' class. You don't have to instance it. Just call
 * DCM.functionname();
 * DCM stands for Dynamic Context Menu
 */
function DCM(){
this.aParents=new Array();
this.sJSMenuID='';
this.jsMenu=null;
this.oLastCMObject=null;
}


/**
 * adds context menu div to the body of the page
 */
DCM.prototype.init=
function(){


};

 
/**
 * set the inner HTML of the Context Menu
 * @param string sHTML
 */
DCM.prototype.setCM=
function(sJSMenuID){
this.sJSMenuID=sJSMenuID;
};

 
/**
 * show the Context Menu on given position
 * @param Object obj {top: int,left: int }
 */
DCM.prototype.showCM=
function(oPos){
var bHideAll=true;
if(DCM.oLastCMObject){
var obj=DCM.oLastCMObject;
while(obj !=document.body){
if(obj.id&&isDefined(JSMenu.aMenus[obj.id])){
bHideAll=false;
break;
}
obj=obj.parentNode;
}
}
if(bHideAll)JSMenu.onBodyClick(true);
else if(this.jsMenu)this.jsMenu.hide();
this.jsMenu=new JSMenu(null,this.sJSMenuID,false,oPos,false,false);

};


/**
 * show the Context Menu when even e is triggered
 * @param Event e
 * @param string sHTML
 * @param HTMLElement obj
 */
DCM.prototype.showCMOnEvent=
function(e,sJSMenuID,obj){
var iMouseButton=getMouseButton(e);
if(iMouseButton > 1){
if(DCM.aParents.length==0){
DCM.oLastCMObject=obj;
DCM.setCM(sJSMenuID);
var oPos=getGlobalMousePosition(e);
oPos.left=oPos.left - 1;
oPos.top=oPos.top - 1;
DCM.showCM(oPos);


var oTarget=getEventTarget(e);
var iNrOfCMs=0;
while(oTarget.parentNode){
var sOnMouseDown=String(oTarget.onmousedown);
if(sOnMouseDown !=null&&sOnMouseDown.indexOf('DCM.showCMOnEvent')!=-1){
if(iNrOfCMs > 0)DCM.aParents.push(oTarget);
iNrOfCMs++;
}
oTarget=oTarget.parentNode;
}
}
else DCM.aParents.pop();
}
};


/**
 * show the Context Menu on the position of the given object
 * @param HTMLElement obj
 */
DCM.prototype.showCMOnObject=
function(obj){
if(!obj)return;
DCM.showCM(getElementPosition(obj));
};

 
/**
 * returns the div that contains the current context menu
 * @return HTMLElement(Div)
 */
DCM.prototype.getCM=
function(){
return this.jsMenu;
};


/* ###########################################################################
 * create DCM variable,so that DCM.functionname can be a valid call
 * sort of singleton
 */
var DCM=new DCM();

/**
 * FM stands for Fold Menu
 * With this singleton class menu's or other HTMLElements can be folded.
 * The css tags display:none and display:block are used.
 */
function FM(){
this.aFoldGroups=new Array();
this.aFoldElements=new Array();
this.aFoldCallers=new Array();
this.aFoldImages=new Array();
this.aElementCallers=new Array();
this.aFoldOpen=new Array();
this.objLastCaller=null;
this.bDblClick=false;
this.iAsyncCalls=0;
}


/**
 * set the IDs of the elements that must be shown when the element with sCallerID
 * is clicked;like images as plus.gif and min.gif
 * @param string sCallerID
 * @param string sFoldInID
 * @param string sFoldOutID
 * @return void
 */
FM.prototype.setFoldingImages=function(sCallerID,sFoldInID,sFoldOutID){
this.aFoldImages[sCallerID]=[sFoldInID,sFoldOutID];
};


/**
 * fold submenu with following options
 * @param HTMLElement objCaller
 * @param string sID - ID of submenu that must be folded
 * @param string sFoldGroup- unique groupname of the given submenu
 * @param bool bUnfoldOn2ndClick - if true and given submenu is visible,
 * then the submenu will be hidden
 * @param bool bUnfoldOthers - if true,other elements in the given group will be hidden
 * @param string sSelectedClass - optional class to add to objCallers className
 * @return void
 */
FM.prototype.foldSubMenu=function(objCaller,sID,sFoldGroup,bUnfoldOn2ndClick,
bUnfoldOthers,sSelectedClass,bChkDblClick){
if(bPageLoaded){
EventManager.Add(objCaller,'dblclick',FM.dblClick);
if(!isDefined(bChkDblClick)){
this.objLastCaller=objCaller;
this.iAsyncCalls++;
this.aFoldOpen[sID]=getStyle(sID,'display')=='none';
setTimeout(getJSCall('FM.foldSubMenu',
['FM.objLastCaller',sID,sFoldGroup,bUnfoldOn2ndClick,bUnfoldOthers,
 sSelectedClass,true]),200);
return;
}
else {
this.iAsyncCalls--;
if(bChkDblClick&&this.bDblClick){
Log.write('it is a dbl click. calls: '+this.iAsyncCalls);
if(this.iAsyncCalls==0)this.bDblClick=false;
return;
}
}
}

this.iAsyncCalls=0;


if(isDefined('MES',true)&& MES.isDragging()&& MES.oLastPosition&&
 !posAboveElement(MES.oLastPosition,objCaller))
return;

 

if(sFoldGroup){
this.registerMenu(objCaller.id,sID,sFoldGroup);


if(isDefined(sSelectedClass)&& sSelectedClass){
objCaller.className=sSelectedClass+" "+objCaller.className;
if(bUnfoldOthers){
for(var sCallerID in this.aFoldCallers){
if(sCallerID !=objCaller.id&&
 this.aFoldCallers[sCallerID]==sFoldGroup){
var objFoldCaller=getObj(sCallerID);
if(!objFoldCaller)continue;
replaceObjClassName(objFoldCaller,sSelectedClass.trim(),'');
}
}
}
}
}

var obj=getObj(sID);
if(obj){
if((this.aFoldOpen[sID] !=null&&this.aFoldOpen[sID])||
 getObjStyle(obj,'display')=='none'){ 
setObjStyle(obj,'display','block');
this.showFoldImage(objCaller.id,true);
}
else if(bUnfoldOn2ndClick){
setObjStyle(obj,'display','none');
this.showFoldImage(objCaller.id,false);
if(isDefined(sSelectedClass)&& sSelectedClass)
replaceObjClassName(objCaller,sSelectedClass,'');
}
}

this.aFoldOpen[sID]=null;


if(bUnfoldOthers&&sFoldGroup)this.hideGroup(sFoldGroup,sID);


if(isDefined('MES',true))MES.recalculateAcceptPositions();


};



FM.prototype.dblClick=function(){ 
FM.bDblClick=true;
};


/**
 * handles fold images if any are defined
 * @param string sCallerID
 * @param bool bFoldIn
 * @return void
 */
FM.prototype.showFoldImage=function(sCallerID,bFoldIn){
if(isDefined(this.aFoldImages[sCallerID])){
var iFoldIn=bFoldIn?1:0;
var iFoldOut=bFoldIn?0:1;
setStyle(this.aFoldImages[sCallerID][iFoldIn],'display','');
replaceClassName(this.aFoldImages[sCallerID][iFoldIn],'hide','');
setStyle(this.aFoldImages[sCallerID][iFoldOut],'display','none');
}
};


/**
 * registers caller with child menu and the group the submenu belongs to
 * @param string sCallerID
 * @param string sSubMenuID
 * @param string sFoldGroup
 * @return void
 */
FM.prototype.registerMenu=function(sCallerID,sSubMenuID,sFoldGroup){
if(!isDefined(this.aFoldGroups[sFoldGroup]))
this.aFoldGroups[sFoldGroup]=new Array();
if(!isDefined(this.aFoldElements[sSubMenuID])){
this.aFoldGroups[sFoldGroup].push(sSubMenuID);
this.aFoldElements[sSubMenuID]=sFoldGroup;
}
if(getObj(sCallerID)|| !bPageLoaded){
this.aFoldCallers[sCallerID]=sFoldGroup;
this.aElementCallers[sSubMenuID]=sCallerID;
}
};


/**
 * gets the ID of the first submenu folded by the caller with given ID
 * @param string sCallerID
 * @return string
 */
FM.prototype.getSubMenuByCaller=function(sCallerID){
for(var sSubMenuID in this.aElementCallers)
if(this.aElementCallers[sSubMenuID]==sCallerID)
return sSubMenuID;
return null;
};


/**
 * hide submenus in given group and their submenus(recursively)
 * optionally an except ID can be provided. This ID will not be hidden
 * @param string sGroupName
 * @param string sExceptID
 * @return void
 */
FM.prototype.hideGroup=function(sGroupName,sExceptID){
for(var iIndex in this.aFoldGroups[sGroupName]){
var sHideID=this.aFoldGroups[sGroupName][iIndex];
if(sHideID !=sExceptID&&getObj(sHideID)){
setStyle(sHideID,'display','none');
this.showFoldImage(this.aElementCallers[sHideID],false);


}
}
};


/**
 * This function returns an array of groupnames that childs of given element
 * can fold. This is an recursive function that will seek through all the childs.
 * @param HTMLElement objCheck
 * @param Array aGroups - prefilled array(optional)
 * @return array
 */
FM.prototype.getInnerFoldGroups=function(objCheck,aGroups){
if(!isDefined(aGroups))var aGroups=new Array();
for(var i=0;i<objCheck.childNodes.length;i++){
if(objCheck.childNodes.item(i).id&&
 this.aFoldCallers[objCheck.childNodes.item(i).id]){
aGroups.push(this.aFoldCallers[objCheck.childNodes.item(i).id]);
}
aGroups=this.getInnerFoldGroups(objCheck.childNodes.item(i),aGroups);
}
return aGroups;
};


 /** #############################################################
* global FM var to enable functionality like FM.foldSubMenu();
* sort of singleton
*/
var FM=new FM();
JSMenu.aMenus=new Array();
JSMenu.iLastID=12345;
JSMenu.iLastZindex=300;
JSMenu.oFocusAt=null;
JSMenu.bInitialized=false;
JSMenu.bAllowBrowserCM=true;
JSMenu.openDelay=300;
JSMenu.hideDelay=500;
JSMenu.objLastObject=null;
JSMenu.aCallerMouseOver=new Array();
JSMenu.aCallerMouseOut=new Array();

function JSMenu(obj,sMenuID,bAtRight,oPos,bHideOnMouseOut,bDelay,bUseHideDelay){
if(!getObj(sMenuID))return;


if(obj==null&&JSMenu.objLastObject !=null){
obj=JSMenu.objLastObject;
JSMenu.objLastObject=null;
}


var oHolder=getObj('holder');
var oHolderPos=getElementPosition(oHolder);
var iHolderWidth=oHolder.offsetWidth;
var iHolderHeight=document.documentElement.scrollTop + 
document.documentElement.clientHeight;
var iMenuWidth=getObjStyle(getObj(sMenuID),'width',true);
var aItems=getObj(sMenuID).getElementsByTagName('li');
var iMenuHeight=23 * aItems.length + 1;


if(!oPos){
oPos={left:0,top:0};
oElPos=getElementPosition(obj);

if(bAtRight){ 
oPos.left=oElPos.left + 
obj.offsetWidth;
oPos.top=oElPos.top;

if(iMenuWidth &&
 oPos.left + iMenuWidth > oHolderPos.left + iHolderWidth){
oPos.left=oElPos.left - iMenuWidth;
}
if(iMenuHeight &&
 oPos.top + iMenuHeight > oHolderPos.top + iHolderHeight){
oPos.top -=iMenuHeight;
oPos.top +=obj.offsetHeight;
}
}
else { 
oPos.left=oElPos.left;
oPos.top=oElPos.top + 
 obj.offsetHeight;
if(iMenuWidth &&
 oPos.left + iMenuWidth > oHolderPos.left + iHolderWidth){
oPos.left=oElPos.left + obj.offsetWidth - iMenuWidth;
}
if(iMenuHeight&&
 oPos.top + iMenuHeight > oHolderPos.top + iHolderHeight){
oPos.top=oElPos.top - iMenuHeight;
}
}
}
else { 
if(iMenuWidth &&
 oPos.left + iMenuWidth > oHolderPos.left + iHolderWidth){
oPos.left -=iMenuWidth;
}
if(iMenuHeight&&
 oPos.top + iMenuHeight > oHolderPos.top + iHolderHeight){
oPos.top -=iMenuHeight;
}
}

if(oPos.top < 0)oPos.top=0;
if(oPos.left < 0)oPos.left=0;

if(bDelay){ 
if(obj&&!isDefined(JSMenu.aCallerMouseOut[obj.id])){
var sOnMouseOut=getFunctionString(obj,'onmouseout');
JSMenu.aCallerMouseOut[obj.id]=sOnMouseOut;
sOnMouseOut +=' JSMenu.objLastObject=null;';
obj.onmouseout=function(){ eval(sOnMouseOut);};
}
JSMenu.objLastObject=obj;
setTimeout("new JSMenu(null,'"+sMenuID+"',"+(bAtRight?'true':'false')+
 ",{top:"+oPos.top+",left:"+oPos.left+"},"+
(bHideOnMouseOut?'true':'false')+",false,true);",JSMenu.openDelay);
return;
}

if(JSMenu.objHasSubmenu(obj))return;
if(!JSMenu.bInitialized)JSMenu.init();


this.callerItem=obj;
JSMenu.oFocusAt=obj;


this.bMouseIsAboveMe=false;
if(this.callerItem&&
(this.callerItem==JSMenu.oFocusAt||JSMenu.oFocusAt==null))
this.bMouseIsAboveCaller=true;
else this.bMouseIsAboveCaller=false;

if(this.callerItem&&!isDefined(JSMenu.aCallerMouseOver[this.callerItem.id])){

JSMenu.aCallerMouseOver[this.callerItem.id]=
getFunctionString(this.callerItem,'onmouseover');
this.callerItem.onmouseover=
function(){
eval(JSMenu.aCallerMouseOver[this.id]);
JSMenu.oFocusAt=this;
var sID=JSMenu.getSubMenuIDFromCaller(this);
if(isDefined(sID))
JSMenu.aMenus[sID].bMouseIsAboveCaller=true;
};


if(obj&&!isDefined(JSMenu.aCallerMouseOut[obj.id])){
var sOnMouseOut=getFunctionString(obj,'onmouseout');
JSMenu.aCallerMouseOut[obj.id]=sOnMouseOut;
}

this.callerItem.onmouseout=
function(){
if(isDefined(JSMenu.aCallerMouseOut[this.id]))
eval(JSMenu.aCallerMouseOut[this.id]);
JSMenu.objLastObject=null;
JSMenu.oFocusAt=null;
var sID=JSMenu.getSubMenuIDFromCaller(this);
if(isDefined(sID)){
JSMenu.aMenus[sID].bMouseIsAboveCaller=false;
setTimeout("if(isDefined(JSMenu.aMenus['"+sID+"']))JSMenu.aMenus['"+sID+"'].hideOnMouseout();",bUseHideDelay?JSMenu.hideDelay:0);
}
};
}

this.ulMenu=getObj(sMenuID);
if(this.ulMenu.parentNode !=document.body)
this.ulMenu.parentNode.removeChild(this.ulMenu);
var sClass=this.ulMenu.className.replace(/hide /,'');
this.ulMenu.className=sClass;
setObjMultStyle(this.ulMenu,['position','display','top','left','zIndex'],
 ['absolute','block',oPos.top+'px',oPos.left+'px',JSMenu.iLastZindex++]);
this.sMenuID=sMenuID;
JSMenu.aMenus[sMenuID]=this;


this.ulParentMenu=null;
this.oParentMenu=null;


if(bHideOnMouseOut){
var objCheck=this.callerItem;
while(objCheck.parentNode){
if(objCheck.id.indexOf('FW_JSMenu_')!=-1){
this.ulParentMenu=objCheck;
this.oParentMenu=JSMenu.aMenus[objCheck.id];
break;
}
objCheck=objCheck.parentNode;
}

this.ulMenu.onmouseout=function(){
if(isDefined(JSMenu.aMenus[this.id])){
JSMenu.showBrowserCM();
JSMenu.aMenus[this.id].bMouseIsAboveMe=false;
setTimeout("if(isDefined(JSMenu.aMenus['"+this.id+"']))JSMenu.aMenus['"+this.id+"'].hideOnMouseout();",JSMenu.hideDelay);
}
};
}
else {
this.ulMenu.onmouseout=function(){
if(isDefined(JSMenu.aMenus[this.id])){ 
JSMenu.aMenus[this.id].bMouseIsAboveMe=false;
JSMenu.showBrowserCM();
}
};
}

this.ulMenu.onmouseover=function(){
if(isDefined(JSMenu.aMenus[this.id]))
JSMenu.aMenus[this.id].bMouseIsAboveMe=true;
JSMenu.hideBrowserCM();
};
 
if(this.ulMenu.parentNode !=document.body){
document.body.appendChild(this.ulMenu);
}
}


/**
 * hides this menu and parents(if the cursor is not above them)
 */
JSMenu.prototype.hideOnMouseout=
function(){
var bAboveSubMenu=false;
var aItems=this.ulMenu.getElementsByTagName('li');
for(var i=0;i<aItems.length;i++){
var liItem=aItems.item(i);
var sSubID=JSMenu.getSubMenuIDFromCaller(liItem);
if(sSubID){
if(isDefined(JSMenu.aMenus[sSubID])&& JSMenu.aMenus[sSubID].bMouseIsAboveMe)
bAboveSubMenu=true;
break;
}
}

if(!this.bMouseIsAboveMe&&!(JSMenu.oFocusAt==this.callerItem)&&
 !bAboveSubMenu){
if(this.oParentMenu)
this.oParentMenu.hideOnMouseout();
this.hide();
}
};


/**
 * hides this menu and deletes it from the JSMenu.aMenus array
 */
JSMenu.prototype.hide=
function(){
setObjStyle(this.ulMenu,'display','none');
delete JSMenu.aMenus[this.ulMenu.id];
};


/**
 * returns the ID of the submenu of given caller returns null if none
 * @param HTMLElement objCaller
 * @return string
 */
JSMenu.getSubMenuIDFromCaller=
function(objCaller){
for(var sID in JSMenu.aMenus){
if(JSMenu.aMenus[sID].callerItem==objCaller){
return sID;
}
}
};


/**
 * Static function that checks if given object has a sub menu
 * @param HTMLElement objCaller
 * @return string
 */
JSMenu.objHasSubmenu=
function(obj){
for(var sID in JSMenu.aMenus){
if(JSMenu.aMenus[sID].callerItem==obj)
return true;
}
return false;
};


/**
 * static initialising function
 */
JSMenu.init=
function(){
document.body.onclick=JSMenu.onBodyClick;
JSMenu.initialized=true;
};


/**
 * static function that is called when the document is clicked
 */
JSMenu.onBodyClick=
function(bJustHide){
if(isDefined(bJustHide)&& bJustHide==true){
for(var sID in JSMenu.aMenus){
JSMenu.aMenus[sID].hide();
delete JSMenu.aMenus[sID];
}
}
else {
var bHide=true;
for(var sID in JSMenu.aMenus){
if(JSMenu.aMenus[sID].bMouseIsAboveCaller){
bHide=false;
break;
}
}
if(bHide)JSMenu.onBodyClick(true);
}
};


/**
 * static functions to allow or disallow the browser to show its CM
 */
JSMenu.showBrowserCM=
function(){
JSMenu.bAllowBrowserCM=true;
};
JSMenu.hideBrowserCM=
function(){
JSMenu.bAllowBrowserCM=false;
};


/**
 * this function is called when a user clicks the right mousebutton in the browser
 * used to disable the browsers contextmenu when a custom cm is shown
 */
JSMenu.onContextMenu=
function(){
if(JSMenu.bAllowBrowserCM)JSMenu.onBodyClick(true);
return JSMenu.bAllowBrowserCM;
};



/**
 * Moving Element System
 * @constructor
 */
function MES(){
this.objCME=null;
this.sCMEID=null;
this.objClone=null;
this.oRSP=null;
this.divCME=null;
this.bElementMouseDown=false;
this.bDivCMEAdded=false;
this.sDraggingID=null;
this.sLastDraggingID=null;
/**
 * in this variable the elements will be stored that can accept a draggable element
 * format: aAcceptElements[sGroupID][]={ left: iLeft,top: iTop,obj: HTMLElement };
 * sGroupID is the ID of the group of the elements that will be accepted
 */
this.aAcceptElements=new Array();
/**
 * in this variable the actions will be stored that are done when a draggable element is
 * accepted. format: aAcceptActions[sID]={ sPHP: phpFile to call,
 * oVar: {name: sName,value: sValue} used for querystring,
 * sJScript: script that will be executed when element is accepted
 * sNewClass: new classname for the moved element
 * sID is the ID of the accepting element
 * @see setAcceptAction
 */
this.aAcceptActions=new Array();
/**
 * in this variable the elements will be stored that are draggable. 
 * format: aDragElements[sID]={ oVar: {name: sName,value: sValue},
 *aGroupIDs: ['groupid1','groupid2] }
 * sID is the ID of the element.
 */
this.aDragElements=new Array();
this.oLastPosition={left: 0,top:0};
this.bAllowMouseMove=false;
this.iCMEOffset=0;
}


/**
* inits the System;creates div that will contain the CME;
* sets the event handler methods
* @return void
*/
MES.prototype.init=function(bCreateCME){ 
if(!isDefined(bCreateCME))bCreateCME=false;
if(this.divCME==null){ 

	this.divCME=document.createElement("div");
	setObjStyle(this.divCME,'position','absolute');
	setObjStyle(this.divCME,'backgroundColor','white');
	setObjStyle(this.divCME,'filter','alpha(opacity=80)');
	setObjStyle(this.divCME,'opacity','0.8');
	setObjStyle(this.divCME,'zIndex','400');
	setObjStyle(this.divCME,'display','none');
	if(!bCreateCME){
	setInterval('MES.bAllowMouseMove=true;',200);
	document.onmousemove=this.documentMouseMove;
	document.onmouseup=this.documentMouseUp;
	document.onmousedown=this.documentMouseDown;
	document.onkeydown=this.documentKeyDown;
	}
}
};


/**
* hides CME,resetting vars;without doing an action
* @param Event e
* @return void
*/
MES.prototype.releaseCME=function(e){
	this.objCME=null;
	this.oRSP=null;
	this.sCMEID=null;
	this.sDraggingID=null;

	this.objClone=null;
	setObjStyle(this.divCME,'display','none');
	
	this.bElementMouseDown=false;
	document.onselectstart=new Function("return true");
	
	
	document.body.style.cursor='default';
};


/**
* function that puts an element in a draggable element implementing the onmousedown event
* @param string sID
* @param array aGroupIDs - the IDs of the groups where the given element belongs to. 
* @param struct oVar - format {name: sName,value: sValue};this will be passed through to the 
*doCallback function(if triggered).
* @return void
* @see setElementAccept
*/
MES.prototype.setElementDraggable=function(sID,aGroupIDs,oVar,sParentClass){
this.init();
var sMousedown=getFunctionString(getObj(sID),'onmousedown');
getObj(sID).onmousedown=function(event){
eval(sMousedown);
MES.CMEMouseDown(event,this);
};
	
	this.aDragElements[sID]={ oVar: null,aGroupIDs: [],sParentClass: null };
	this.aDragElements[sID].oVar=oVar;
	this.aDragElements[sID].aGroupIDs=aGroupIDs;
	this.aDragElements[sID].sParentClass=sParentClass;
	this.aDragElements[sID].objDragElement=getObj(sID);
	setStyle(sID,'cursor','move');
};


/**
 * registers element with given ID as an acceptor for a draggable element
 * when a draggable element is released above this element,then the 
 * onmouseup event will be triggered
 * @param string sID
 * @return void
 */
MES.prototype.setElementAccept=function(sID,aForGroups,sMouseOverClass){
if(!bPageLoaded){
setTimeout("MES.setElementAccept('"+sID+"',"+arrayToSource(aForGroups)+",'"+
 sMouseOverClass+"');",100);
return;
}
var objElement=getObj(sID);
if(!objElement)return;
var oPos=getElementPosition(objElement);
for(var iIndex in aForGroups){
var sForGroup=aForGroups[iIndex];
if(!isDefined(this.aAcceptElements[sForGroup]))
this.aAcceptElements[sForGroup]=new Array();
this.aAcceptElements[sForGroup].push({ left : oPos.left,
top: oPos.top,
obj: objElement,
mouseoverclass: sMouseOverClass });
}
};


/**
 * sets the action that must be done when a CME is released above the element with given ID
 * @param string sID - the ID of the accepting element
 * @param string sPHP - optionally the PHP file that must be called when accepted
 * @param string oVar - optionally a struct { name: sName,value: sValue } that will be used in the PHP querystring
 * @param string sJScript - optionally a JScript that must be called when accepted
 * @param string sNewClass - optionally a new classname for the moved element
 * @return void
 */
MES.prototype.setAcceptAction=function(sID,sPHP,oVar,sJScript,sNewClass){
this.aAcceptActions[sID]={ sPHP: null,oVar: null,sJScript: null,sNewClass: null };
if(isDefined(sPHP))this.aAcceptActions[sID].sPHP=sPHP;
if(isDefined(oVar))this.aAcceptActions[sID].oVar=oVar;
if(isDefined(sJScript))this.aAcceptActions[sID].sJScript=sJScript;
if(isDefined(sNewClass))this.aAcceptActions[sID].sNewClass=sNewClass;
};


/**
 * do a callback to a php file with given vars
 * @param string sPHP - PHP file to callback;given relatively
 * @param struct oVar1 - format {name: sName,value: sValue}
 * @param struct oVar2 - format {name: sName,value: sValue}
 * @param string sJScript - optional script string that will be executed with eval();after the callback
 * @return void
 */
MES.prototype.doCallBack=function(sPHP,oVar1,oVar2,sJScript){

var sParamString=sPHP.indexOf('?')==-1?'?':'&';
if(isDefined(oVar1)&& oVar1 &&
 isDefined(oVar1.name)&&
 isDefined(oVar1.value))
sParamString +=oVar1.name+'='+oVar1.value+'&';
if(isDefined(oVar2)&& oVar2&&
 isDefined(oVar2.name)&&
 isDefined(oVar2.value))
sParamString +=oVar2.name+'='+oVar2.value;
sendRequest(sPHP+sParamString,null,false,'MES.callBackResponse',
{sJScript: sJScript});
};


/**
 * function that is called on server response
 * @param XMLHttpRequest xmlhttp
 * @param struct oParam
 * @return void
 */
MES.prototype.callBackResponse=function(xmlhttp,oParam){
if(isDefined(oParam.sJScript))eval(oParam.sJScript);
};


/**
 * returns a element that is registerd with setElementAccept and that
 * is under the given oPos
 * @param struct oPos {left,top}
 * @param int iIndex -index of the mouseupelement
 * @return HTMLElement
 */
MES.prototype.aboveAcceptElement=function(oPos,sGroupID,iIndex){
MES.aAcceptElements[sGroupID][iIndex].obj=
getObj(MES.aAcceptElements[sGroupID][iIndex].obj.id);
if(!MES.aAcceptElements[sGroupID][iIndex].obj){
delete MES.aAcceptElements[sGroupID][iIndex];
return;
}

var iLeft=MES.aAcceptElements[sGroupID][iIndex].left;
var iTop=MES.aAcceptElements[sGroupID][iIndex].top;
var objAcceptor=MES.aAcceptElements[sGroupID][iIndex].obj;
var iWidth=objAcceptor.offsetWidth;
var iHeight=objAcceptor.offsetHeight;
if(iHeight==0){
iHeight=getObjStyle(objAcceptor,'height',true);
if(iHeight==0){
iHeight=getObjStyle(objAcceptor,'borderWidth',true);
}
}

if(oPos.left > iLeft &&
 oPos.left < iLeft + iWidth &&
 oPos.top> iTop &&
 oPos.top< iTop + iHeight){
return true;
}
return false;
};


/**
 * recalculates the positions of the elements that can accept a draggeble element
 */
MES.prototype.recalculateAcceptPositions=function(){
for(var sForGroup in this.aAcceptElements){
for(var iIndex in this.aAcceptElements[sForGroup]){
var objAcceptElement=getObj(this.aAcceptElements[sForGroup][iIndex].obj.id);
if(!objAcceptElement){
delete this.aAcceptElements[sForGroup][iIndex];
continue;
}

this.aAcceptElements[sForGroup][iIndex].obj=objAcceptElement;
var oPos=getElementPosition(objAcceptElement);
this.aAcceptElements[sForGroup][iIndex].top=oPos.top;
this.aAcceptElements[sForGroup][iIndex].left=oPos.left;
}
}
};


/**
 * redefines the events on the draggable elements. must be called when 
 * an action like obj.innerHTML=obj2.innerHTML was performed;
 * @return void
 */
MES.prototype.redefineDragEvents=function(){
for(var sIndex in this.aDragElements){
if(!getObj(sIndex)&& !this.getDraggingID()==sIndex){
delete this.aDragElements[sIndex];
continue;
}
if(getObj(sIndex)){
getObj(sIndex).onmousedown=this.aDragElements[sIndex].objDragElement.onmousedown;
this.aDragElements[sIndex].objDragElement=getObj(sIndex);
}
}
};


/**
 * adds the given classname to the given element and all its children
 * @param HTMLElement objElement
 * @param string sNewClassName
 * @return void
 */
MES.prototype.setElementClassRecursive=function(objElement,sNewClassName){
if(!objElement||!isDefined(objElement.className))return;
var sCurClass=objElement.className;
objElement.className=sCurClass + ' ' + sNewClassName;
for(var i=0;i<objElement.childNodes.length;i++)
this.setElementClassRecursive(objElement.childNodes.item(i),sNewClassName);
};


/**
 * returns whether a element is dragging
 * @return bool
 */
MES.prototype.isDragging=function(){
return this.sDraggingID!=null;
};


/**
 * returns the ID of the element that currently is being dragged
 * can be null
 * @return string
 */
MES.prototype.getDraggingID=function(){
return this.sDraggingID;
};


/**
 * returns the ID of the last element being dragged. if null,no element has
 * been dragged yet
 * @return string
 */
MES.prototype.getLastDraggingID=function(){
return this.sLastDraggingID;
};




/**
 * ##################################################################
 * #Event HandlersEvent Handlers#
 * ##################################################################
 */

/**
* function that checks if there is a CME and moves it
* @param Event e
* @return void
*/
MES.prototype.documentMouseMove=function(e){
	if(MES.objCME==null||MES.divCME==null)return;
	if(MES.oRSP==null)Log.write("oRSP is not correctly set by the onmousedown event handler");
	var oPos=getGlobalMousePosition(e);

var iBorderLeft=getStyle('holder','borderLeftWidth',true);
var iBorderTop=getStyle('holder','borderTopWidth',true);
	if(Math.abs(MES.oLastPosition.left - oPos.left)> 2 ||
	 Math.abs(MES.oLastPosition.top - oPos.top)> 2){
	var iLeft=(oPos.left - MES.oRSP.left)+iBorderLeft;
	if(iLeft + MES.objCME.offsetWidth > document.documentElement.clientWidth)
	 iLeft -=iLeft + MES.objCME.offsetWidth - document.documentElement.clientWidth;
		var iTop=oPos.top - MES.oRSP.top - MES.iCMEOffset + iBorderTop -(bIE?2:0);
 	
 	MES.oLastPosition=oPos;	
 	
		if(getObjStyle(MES.divCME,'display')=='none'){
		Log.write('show');
		setObjStyle(MES.divCME,'display','block');
		}
		setObjStyle(MES.divCME,'left',iLeft + 'px');
		setObjStyle(MES.divCME,'top',iTop + 'px');
	}
		if(MES.bAllowMouseMove){
	MES.bAllowMouseMove=false;
		
		
		var aGroups=MES.aDragElements[MES.sCMEID].aGroupIDs;
		for(var iGroupIndex in aGroups){
		
		var sGroupID=aGroups[iGroupIndex];
		for(var iIndex in MES.aAcceptElements[sGroupID]){
		
		if(!getObj(MES.aAcceptElements[sGroupID][iIndex].obj.id)){
		delete MES.aAcceptElements[sGroupID][iIndex];
		continue;
		}
		
		
		if(MES.aboveAcceptElement(oPos,sGroupID,iIndex)){
		if(isDefined(MES.aAcceptElements[sGroupID][iIndex].mouseoverclass)&&
		 MES.aAcceptElements[sGroupID][iIndex].mouseoverclass)
		MES.aAcceptElements[sGroupID][iIndex].obj.className +=' '+
		MES.aAcceptElements[sGroupID][iIndex].mouseoverclass;
		
		if(isDefined(MES.aAcceptElements[sGroupID][iIndex].obj.onmouseover)&&
		 String(MES.aAcceptElements[sGroupID][iIndex].obj.onmouseover)!='null'){
		MES.aAcceptElements[sGroupID][iIndex].obj.onmouseover(e);
		}
		}
		else {
 		if(isDefined(MES.aAcceptElements[sGroupID][iIndex].mouseoverclass)&&
		 MES.aAcceptElements[sGroupID][iIndex].mouseoverclass)
		replaceObjClassName(MES.aAcceptElements[sGroupID][iIndex].obj,
		MES.aAcceptElements[sGroupID][iIndex].mouseoverclass,'');
				
		if(isDefined(MES.aAcceptElements[sGroupID][iIndex].obj.onmouseout)&&
		 String(MES.aAcceptElements[sGroupID][iIndex].obj.onmouseout)!='null'){
		MES.aAcceptElements[sGroupID][iIndex].obj.onmouseout(e);
		}
		}
		}
		}
	}
};


/*
* function that releases the CME
* @param Event e
* @return void
*/
MES.prototype.documentMouseUp=function(e){
if(MES.objCME !=null){

var oPos=getGlobalMousePosition(e);

		var aGroups=MES.aDragElements[MES.sCMEID].aGroupIDs;
		for(var iGroupIndex in aGroups){
		
		var sGroupID=aGroups[iGroupIndex];
		for(var iIndex in MES.aAcceptElements[sGroupID]){
		
		if(isDefined(MES.aAcceptElements[sGroupID][iIndex].mouseoverclass)&&
		 MES.aAcceptElements[sGroupID][iIndex].mouseoverclass){
		replaceObjClassName(MES.aAcceptElements[sGroupID][iIndex].obj,
		MES.aAcceptElements[sGroupID][iIndex].mouseoverclass,'');
}
		
		var sAcceptID=MES.aAcceptElements[sGroupID][iIndex].obj.id;
 		if(sAcceptID==MES.sDraggingID)continue;
if(MES.aboveAcceptElement(oPos,sGroupID,iIndex)&&
 isDefined(MES.aAcceptActions[sAcceptID])){
if(MES.aAcceptActions[sAcceptID].sPHP){
MES.doCallBack(MES.aAcceptActions[sAcceptID].sPHP,
 MES.aAcceptActions[sAcceptID].oVar,
 MES.aDragElements[MES.sCMEID].oVar,
 MES.aAcceptActions[sAcceptID].sJScript);
}
if(MES.aAcceptActions[sAcceptID].sNewClass){
MES.setElementClassRecursive(MES.objCME,
 MES.aAcceptActions[sAcceptID].sNewClass);
MES.recalculateAcceptPositions();
}
if(MES.aAcceptActions[sAcceptID].sJScript&&
 !MES.aAcceptActions[sAcceptID].sPHP){
eval(MES.aAcceptActions[sAcceptID].sJScript);
}
if(isDefined(MES.aAcceptElements[sGroupID][iIndex].obj.onmouseout)&&
 String(MES.aAcceptElements[sGroupID][iIndex].obj.onmouseout)!='null')
MES.aAcceptElements[sGroupID][iIndex].obj.onmouseout(e);

}
		}
}
MES.sDraggingID=null;
}


 	MES.releaseCME(e);
};


/**
 * disables or enables selecting in FF
 * @param Event e
 * @return bool
 */
MES.prototype.documentMouseDown=function(e){ 
		if(MES.bElementMouseDown){
			 MES.bElementMouseDown=false;
			 return false;
		}
		return true;
	};


/**
* function that handles the escape key to cancel movement
* @param Event e
* @return void
*/
MES.prototype.documentKeyDown=function(e){
	var key=getKeyCode(e);

if(key==27){ 
	MES.releaseCME();
	if(isDefined(JSMenu))JSMenu.onBodyClick(true);
}
};


/**
 * function that handles the mousedown event on a draggable element
 * @param Event e
 * @param HTMLElement objCME
 */
MES.prototype.CMEMouseDown=function(e,objCME,bForceClick){
if(!isDefined(bForceClick))bForceClick=false;


if(!MES.bDivCMEAdded){
document.body.appendChild(MES.divCME);
MES.bDivCMEAdded=true;
}

var iMouseButton=getMouseButton(e);
if(iMouseButton==1||bForceClick){ 
MES.sDraggingID=MES.sLastDraggingID=objCME.id;
		MES.bElementMouseDown=true;
		document.onselectstart=new Function("return false");
		var oEPos=getElementPosition(objCME);
		var oPos=getGlobalMousePosition(e);
		MES.oLastPosition=oPos;
		MES.sCMEID=objCME.id;
		MES.oRSP={left: oPos.left - oEPos.left,top: oPos.top - oEPos.top};
		MES.objCME=objCME;
	removeObjElement(MES.divCME);
		MES.divCME=null;
MES.init(true);
document.body.appendChild(MES.divCME);

		
var objClone=makeValidCopy(objCME);

objClone.onmouseout=objCME.onmouseout;
objClone.onmouseover=function(){};
if(isDefined(objClone.onmouseout)&& getFunctionString(objClone,'onmouseout')){
objClone.onmouseout(e);
}


if(objCME.tagName.toLowerCase()=='td'){
var objTable=document.createElement('table');
var objTR=document.createElement('tr');
var objOrigTR=findParent(objCME,'tr');
var objOrigTable=findParent(objCME,'table');
objTR.className=objOrigTR.className;
objTR.appendChild(objClone);
objTable.className=objOrigTable.className;
objTable.appendChild(objTR);
setObjStyle(objTR,'width',objCME.offsetWidth+'px');
setObjStyle(objTable,'width',objCME.offsetWidth+'px');
MES.objClone=objTable;
}
else if(objCME.tagName.toLowerCase()=='tr'){
var objTable=document.createElement('table');
var objOrigTable=findParent(objCME,'table');
objTable.className=objOrigTable.className;
setObjStyle(objTable,'width',objCME.offsetWidth+'px');
objTable.appendChild(objClone);
MES.objClone=objTable;
}
else MES.objClone=objClone;


if(isDefined(this.aDragElements[objCME.id].sParentClass)){
setObjStyle(MES.divCME,'backgroundColor','');
MES.divCME.className=this.aDragElements[objCME.id].sParentClass;
}
else {
MES.divCME.className='';
setObjStyle(MES.divCME,'backgroundColor','white');
}

if(bIE)MES.divCME.innerHTML=MES.objClone.outerHTML;
else MES.divCME.appendChild(MES.objClone);
		setObjMultStyle(MES.divCME,['left','top'],
		[MES.oRSP.left + 'px',MES.oRSP.top+ 'px']);
}
	};
	

 	
	/* ##################################################################################
 * create MES variable,so that MES.function can be a valid call
 * sort of singleton
 */
var MES=new MES();



/**
 * use this class to get a low(er)CPU mouse move event on a object
 */
function MouseMoveEvent(){




this.aElementRegister={};

this.iLastKeyGiven=1;
}


MouseMoveEvent.Me=null;


/**
 * returns the static singleton instance of this class
 * @return MouseMoveEvent
 */
MouseMoveEvent.Instance=function(){
if(MouseMoveEvent.Me==null)MouseMoveEvent.Me=new MouseMoveEvent();
return MouseMoveEvent.Me;
};


/**
 * - registers given element. 
 * - a mousemove event will be set on this element
 * - given callback function will be called when a mousemove event is triggered
 * - the callback function will not be called more often then 1 time in iMaxFreq ms
 * - the params to the callback function will be: 
 * eElement,oPos {left: int,top: int}(global mouse position)
 * - optionally an callback object can be given,so that the callback function 
 * can be on an instance of a class 
 * @example MouseMoveEvent.Instance().registerElement(
 *divMove,50,MyClass.prototype.divMoved,this);
 * 
 * @param HTMLElement eElement
 * @param int iMaxFreq - maximum frequency in ms that the callback may be called
 * @param Function fnCallback
 * @param Object objCallback - default the global window object
 * @return void
 */
MouseMoveEvent.prototype.registerElement=
function(eElement,iMaxFreq,fnCallback,objCallback){
if(eElement==null||fnCallback==null)return;

if(!isDefined(objCallback)|| objCallback==null)
objCallback=window;

var sID=getElementAttribute(eElement,'MouseMoveID');
if(!sID||!isDefined(this.aElementRegister[sID])){ 

sID='genMoveID_'+this.iLastKeyGiven++;
setElementAttribute(eElement,'MouseMoveID',sID);
}
else { 
var oReg=this.aElementRegister[sID];
EventHandler.Instance().removeHandler(oReg.element,'onmousemove',
MouseMoveEvent.prototype.mouseMoved,this);
this.aElementRegister[sID]=null;
}


this.aElementRegister[sID]={obj: objCallback,fn: fnCallback,
maxfreq: iMaxFreq,lastmovetime: 0,
timeout: null,element: eElement};
EventHandler.Instance().addHandler(eElement,'onmousemove',
MouseMoveEvent.prototype.mouseMoved,this);
};


/**
 * removes the given element from the mousemove register and removes the 
 * mousemove event
 * @param HTMLElement eElement
 * @return void
 */
MouseMoveEvent.prototype.removeElement=function(eElement){
var sID=getElementAttribute(eElement,'MouseMoveID');
if(sID){
var oReg=this.aElementRegister[sID];
if(oReg){
if(oReg.timeout !=null)
clearTimeout(oReg.timeout);
EventHandler.Instance().removeHandler(oReg.element,'onmousemove',
MouseMoveEvent.prototype.mouseMoved,this);
oReg=null;
delete this.aElementRegister[sID];
}
}
};
 
 
/**
 * returns true if given element is in a timeout state. that means that
 * another mouse movement will be processed after the timeout is past
 * @param HTMLElement eElement
 * @return boolean
 */ 
MouseMoveEvent.prototype.isInTimeout=function(eElement){
var sID=getElementAttribute(eElement,'MouseMoveID');
if(sID&&isDefined(this.aElementRegister[sID])){
return this.aElementRegister[sID].timeout !=null;
}
return false;
};


/**
 * called when a mousemove event occurs on a registered element
 * @param Event e
 * @param HTMLElement obj
 * @param Object oPos {left: int,top: int}(global mouse pos)
 * @return void
 */
MouseMoveEvent.prototype.mouseMoved=function(e,obj,oPos,sID){

if(!isDefined(sID)){
sID=getElementAttribute(obj,'MouseMoveID');
}
var oReg=this.aElementRegister[sID];
if(isDefined(oReg)){

if(!isDefined(oPos)){

if(oReg.timeout !=null)clearTimeout(oReg.timeout);

oPos=getGlobalMousePosition(e);

if(getCurTime()- oReg.lastmovetime < oReg.maxfreq){
oReg.timeout=setTimeout(
getJSCall('MouseMoveEvent.Instance().mouseMoved',[null,null,oPos,sID]),
oReg.maxfreq);
return true;
}
}


oReg.timeout=null;
oReg.lastmovetime=getCurTime();


oReg.fn.call(oReg.obj,oReg.element,oPos);
}
};

/**
 * class to set elements draggable / movable
 */
function MoveElement(){
this.iLastID=1;
this.aCheckCodes=new Array();
this.aCouples=new Array();
this.bMoving=false;
this.sMovingID=null;
this.oMoveStartPos={top:0,left:0};
}

/**
 * sets the given objMove draggable / movable;objMove may be an id
 * sCheckCode is a piece of code(returning a bool)that indicates whether
 * the given obj may be moved;eval()will be called on this value;
 * 
 * @param HTMLElement objMove - object to move
 * @param HTMLElement objEvent - object where the mousedown event must be placed on
 * @param string sCheckCode
 * @return void
 */
MoveElement.prototype.setDraggable=function(objMove,objEvent,sCheckCode){

if((typeof objMove).toLowerCase()=='string')
objMove=getObj(objMove);
if(!objMove)return;

if((typeof objEvent).toLowerCase()=='string')
objEvent=getObj(objEvent);
if(!objEvent)return;


if(getObjStyle(objMove,'position')!='absolute'){
var oCurPos=getElementPosition(objMove);
var iWidth=getObjStyle(objMove,'width',true);
var iHeight=getObjStyle(objMove,'height',true);
var objReplace=document.createElement('div');
setObjMultStyle(objReplace,['width','height'],
[iWidth+'px',iHeight+'px']);
setObjMultStyle(objMove,['position','top','left','width','height'],
['absolute',oCurPos.top+'px',oCurPos.left+'px',iWidth+'px',iHeight+'px']);
replaceObj(objMove,objReplace);
document.body.appendChild(objMove);
}



if(!objEvent.id)objEvent.id='MovingElement_'+this.iLastID++;
this.aCheckCodes[objEvent.id]=isDefined(sCheckCode)?sCheckCode:null;
this.aCouples[objEvent.id]=objMove;
if(objEvent.tagName.toLowerCase()=='form'){
var aFieldsets=objEvent.getElementsByTagName('fieldset');
for(var i=0;i<aFieldsets.length;i++)
setObjStyle(aFieldsets[i],'cursor','move');
}
setObjStyle(objEvent,'cursor','move');


EventHandler.Instance().addHandler(objEvent,'onmousedown',
MoveElement.elementMouseDown,this);
MouseMoveEvent.Instance().registerElement(document.documentElement,20,
MoveElement.documentMouseMove,this);
EventHandler.Instance().addHandler(document.documentElement,'onmouseup',
MoveElement.documentMouseUp,this);
};


/**
 * handles mouse down event.
 * @param Event e
 * @param HTMLElement objEvent
 */
MoveElement.prototype.elementMouseDown=function(e,objEvent){

if(this.aCheckCodes[objEvent.id]&&
 !eval(this.aCheckCodes[objEvent.id]))
return true;
 
var oMousePos=getGlobalMousePosition(e);
var oElementPos=getElementPosition(this.aCouples[objEvent.id]);
if(oElementPos.top !=0&&oElementPos.left !=0){
this.oMoveStartPos.top=oMousePos.top- oElementPos.top;
this.oMoveStartPos.left=oMousePos.left - oElementPos.left;
}
else this.oMoveStartPos={top:0,left:0};
this.bMoving=true;
this.sMovingID=objEvent.id;
if(bIE)document.onselectstart=new Function("return false");
else return false;
};


/**
 * handles mouse move event
 * @param Event e
 */
MoveElement.prototype.documentMouseMove=function(eElement,oPos){
if(this.bMoving){
setObjMultStyle(this.aCouples[this.sMovingID],
['top','left'],
[(oPos.top - this.oMoveStartPos.top)+ 'px',
(oPos.left - this.oMoveStartPos.left)+ 'px']);
}
};


/**
 * handles mouse down event
 * @param Event e
 */
MoveElement.prototype.documentMouseUp=function(e,objEvent){
this.bMoving=false;
this.sMovingID=null;
if(bIE)document.onselectstart=new Function("return true");
else return true;
};


var MoveElement=new MoveElement();
