function RTFEditor(id, context, head, contentkey, dbkey, autofocus, width){
	// id: the id of the element to edit.
	// context: path to WGA project
	// head: only Mozilla: headelemets (styles, ...) to be copied into iframe

	this.getWidth=function(){
		if(ie)
			return this.editelement.offsetWidth;
		else return this.iframe.width;
	}
	this.getHeight=function(){
		if(ie)
			return this.editelement.offsetHeight;
		else return this.iframe.height;
	}
	
	this.getRTFHTML=function(){
		return WGA.util.makeScriptlets(this.getHTML(),
				(contentkey&&dbkey)?{contentinfo:{contentkey:contentkey, dbkey:dbkey}} : {}
			);
	}

	this.changeViewMode=function(mode){
		switch(mode){
			case "wysiwyg":
				if (this.viewmode=="html")
					editor.setHTML(editor.sourcecodeElement.value);
				editor.sourcecodeElement.style.display="none";
				editor.orgElement.style.display="none";
				editor.spanElement.style.display="block";
				if (!ie){
					try{
						editor.doc.designMode = "on";
					}catch(e){}
				}
				if (this.toolbar)
					this.toolbar.disableAllButtons(false);
			break;
			case "html":
				editor.sourcecodeElement.value=editor.getHTML();
				editor.orgElement.style.display="none";
				editor.spanElement.style.display="none";
				editor.sourcecodeElement.style.display="inline";	// MUST be "inline". if "block" is used, Mozilla positions textarea over toolbar!
				if (this.toolbar)
					this.toolbar.disableAllButtons(true);
				editor.sourcecodeElement.focus();
			break;
			case "preview":
				if (this.viewmode=="html")
					editor.setHTML(editor.sourcecodeElement.value);
				editor.sourcecodeElement.style.display="none";
				editor.orgElement.style.display="block";
				editor.spanElement.style.display="none";
				editor.orgElement.innerHTML=String(editor.getHTML());
				if (this.toolbar)
					this.toolbar.disableAllButtons(true);
			break;			
		}
		this.viewmode=mode;
	}	

	function __processEventCaller(event){
		return editor._processEvent(event);
	}
	this.registerEvents=function(events){
		for (var ev in events){
			if(ie)
				editor.editelement.attachEvent(events[ev], __processEventCaller);
			else editor.doc.addEventListener(events[ev], __processEventCaller, true);
		}		
	}
		
	this.unregisterEvents=function(events){
		for (var ev in events){
			if(ie)
				editor.editelement.detachEvent(events[ev], __processEventCaller);				 
			else editor.doc.removeEventListener(events[ev], __processEventCaller, true);				 
		}		
	}

	this._processEvent=function (ev){
		//console.log("event " + ev.type + "/" + ev.charCode);
		var key = String.fromCharCode(ie ? ev.keyCode : ev.charCode).toLowerCase();
		if (ev.ctrlKey){		
			switch (key) {
		    	case 'h':
		    		this.changeViewMode("html");
		    		_stopEvent(ev);
		    		break;
		    	case 'j':	// for Mozilla.
		    		this.changeViewMode("wysiwyg");
		    		_stopEvent(ev);
		    		break;
			}
		}
		else if(ev.keyCode==27 && this.frm && confirm("Cancel Editing?")){
			_cancel();
			_stopEvent(ev);			
		}

		/**
		 * WGA 4.1:
		 * Firefox3 is now able to handle <p>-tags correctly, so we insert a paragraph on ENTER

		else if(ev.keyCode==13 && (WGA.isFirefox3||WGA.isSafari)){
			try{
				//editor.doc.execCommand("insertparagraph", false, null);
				var paraType = "p";
				var h = ["H1", "H2", "H3", "H4", "H5", "H6"];
				for(var i=0; i<h.length; i++){
					if(_getNearestTagFromSelection(h[i])){
						paraType=h[i];
						break;
					}
				}
				console.log("formatblock: "+paraType);
				if(paraType=="p")
					editor.doc.execCommand("insertparagraph", false, null);
				else editor.doc.execCommand("formatblock", false, paraType);
			}
			catch(e){}	// ignore exceptions
		}
		*/
		
		/**
			WGA 4.0.7:
			Habe ich mal implementiert, weil CMD-Left history.back() aufgerufen hat.
			Nach aktuellen Test ist dies aber weder bei Safari noch bei FF der Fall, also habe ich es wieder herausgenommen.

		else if(ev.keyCode==37 && (isWindows?ev.altKey:ev.metaKey)){
			// CMD-Left on MAC-OS, ALT-left on Windows
			_stopEvent(ev);			
		}
		*/
		if(ev.type=="focus" && this.toolbar){
			this.toolbar.editorGotFocus();
			return;
		}
		if(ev.type=="blur" && this.toolbar){
			this.toolbar.editorLostFocus();
			return;
		}
		
		// update the toolbar state after some time
		if (this.toolbar){
			if (ev.ctrlKey && this.toolbar.doKeyFunction(key))
				_stopEvent(ev);
			else if(ev.type=="contextmenu")
				this.toolbar.showContextMenu(ev);	// don't update toolbar here!		
			else{
				if (this._timerToolbar) {
					clearTimeout(this._timerToolbar);
				}
				this._timerToolbar = setTimeout(function() {
					editor.toolbar.update();
					editor._timerToolbar = null;
				}, 150);
			}
		}
	}
	
	function _stopEvent(ev) {
		if (ie){
			ev.cancelBubble = true;
			ev.returnValue = false;
		}
		else {
			ev.preventDefault();
			ev.stopPropagation();
		}
	}
	
	//--- generate form for user with WGA BI ---
	this.generateForm=function (item, contentkey, dbkey, editor){
		var frm=document.createElement("form");
		frm.style.display="none";
		frm.name="_RTF_Editor_Form_";
		frm.id=frm.name;
		frm.enctype="application/x-www-form-urlencoded";
		frm.action=this.contextPath + "/write" ;
		frm.method="post";
		this.frm=frm;
		this.orgElement.parentNode.insertBefore(frm, this.orgElement);
		
		var inp=document.createElement("input");
		inp.name="targetField";
		inp.value=item;
		frm.appendChild(inp);
		
		inp=document.createElement("input");
		inp.name="Editor";
		inp.value=editor;
		frm.appendChild(inp);
		
		inp=document.createElement("input");
		inp.name="contentKey";
		inp.value=contentkey;
		frm.appendChild(inp);
		
		inp=document.createElement("input");
		inp.name="dbKey";
		inp.value=dbkey;
		frm.appendChild(inp);

		inp=document.createElement("textarea");
		inp.name="HTMLDATA";
		this.textarea=inp;	// remember this element for onsubmit()
		frm.appendChild(inp);

		inp=document.createElement("img");
		inp.alt="OK";
		inp.src=this.contextPath+"/bi/images/ok.gif";
		inp.onclick=_save;
		this.orgElement.parentNode.insertBefore(inp, this.orgElement);
		
		this.orgElement.parentNode.insertBefore(document.createTextNode(" "), this.orgElement);
		
		inp=document.createElement("img");
		inp.alt="Cancel";
		inp.src=this.contextPath+"/bi/images/cancel.gif";
		inp.onclick=_cancel;
		this.orgElement.parentNode.insertBefore(inp, this.orgElement);		
	}
	
	function _save(){
		if(!editor.textarea){
			alert("no textarea");
			return;
		}
		editor.textarea.value=editor.getRTFHTML();
		window.onbeforeunload =null;
		editor.frm.submit();		
	}
	
	function _cancel(){
		if(editor.frm){
			window.onbeforeunload =null;		
			self.location.href = self.location.href;
		}
	}
	//-----------------------
	
	this.focus=function(){
		setFocus();		
	}	
	function setFocus(){
		if(ie)
			editor.editelement.focus();
		else {
			try {
				editor.iframe.contentWindow.focus();
			} 
			catch(e) { 
				//alert(e);
				// Sometimes this gives an "permition denied" exception, but everything works well.
			}
		}
	}

	// returns the current selection object
	function _getSelection() {
		if (ie) {
			return editor.doc.selection;
		} else {
			return editor.iframe.contentWindow.getSelection();
		}		
	}
	
	// returns a range for the current selection
	function _createRange(sel) {
		if (ie) {
			//alert("editor:" + sel.createRange().parentElement().tagName);
			return sel.createRange();
		} else {
			if (sel && typeof sel != "undefined") {
				return sel.getRangeAt(0);
			} else {
				return editor.doc.createRange();
			}
		}		
	}
	
	this.getRange=function(){
		return _createRange(_getSelection());
	}
	
	function _getNearestTag(ptag, tagNameToFind){
		while(ptag && ptag.tagName!="BODY" && ptag!=editor.spanElement && ptag.tagName!=tagNameToFind){
			//alert("tag is " + ptag.tagName + " searching " + tagNameToFind);
			ptag=ptag.parentNode;			
		}
		if (ptag && ptag.tagName==tagNameToFind)
			return ptag;
		else return null;
	}
	
	function _getNearestTagFromSelection(tagNameToFind){
		var range = _createRange(_getSelection());
		//alert(range.parentElement().tagName);
		if (ie){
			try{
				return _getNearestTag(range.parentElement(), tagNameToFind);
			} catch (e){
				return _getNearestTag(range(0), tagNameToFind);
			}
		}
		else {
			var startNode=range.startContainer;
			if (startNode.nodeType==1)		// Element
				return _getNearestTag(startNode.childNodes[range.startOffset], tagNameToFind);
			else // Textnode or other nodes ...
				return _getNearestTag(startNode.parentNode, tagNameToFind);
		}
	}
	this.getNearestTagFromSelection=function(tagNameToFind){
		return _getNearestTagFromSelection(tagNameToFind.toUpperCase());
	}


	this.getParentNodeFromSelection=function(){
		var range = _createRange(_getSelection());
		//alert(range.parentElement().tagName);
		if (ie){
			try{
				return range.parentElement();
			} catch (e){
				return range(0);
			}
		}
		else {
			var startNode=range.startContainer;
			if (startNode.nodeType==1)		// Element
				return startNode.childNodes[range.startOffset];
			else // Textnode or other nodes ...
				return startNode.parentNode;
		}
	}
	this.getPathFromSelection=function(){
		var path = [];
		try{
			var ptag = this.getParentNodeFromSelection();
			while(ptag && ptag.tagName!="BODY" && ptag!=editor.spanElement){
				path.push(ptag);
				ptag=ptag.parentNode;			
			}
		} catch(e){};
		return path;
	}

	
	function _getParentTagFromSelection(){
		var range = _createRange(_getSelection());
		if (ie)
			return range.parentElement();
		else return range.startContainer.parentNode;
	}

	function insertNodeAtSelection(node){
		var range = _createRange(_getSelection());
		if(ie)
			try{
				range.pasteHTML(node.outerHTML);				
			} catch(e){
				range(0).outerHTML=node.outerHTML;
			}
		else{
			range.deleteContents();	// deletes the selected Text
			range.insertNode(node);
		}
	}
	
	function getSelectedText(){
		if(ie)
			return _createRange(_getSelection()).text;
		else 
			return _getSelection();
	}
	
	this.getHTML=function(){
		//alert("getHTML: " + editor.doc.body.innerHTML);
		var ret="";
		if (editor.viewmode=="html"){
			//alert("viewmode=html");
			ret=editor.sourcecodeElement.value;
		}
		else ret= ie ? editor.editelement.innerHTML : editor.doc.body.innerHTML;
		//alert("ret=" + ret);
		return ret;
	}

	this.getText=function(){		
		if(ie)
			return editor.editelement.innerText;
		else{
			var range=this.getRange();
			range.selectNode(editor.doc.body);
			return range.toString();
		}
	}
	
	this.setHTML=function(html){
		if(ie)
		 	this.editelement.innerHTML=html;
		else editor.doc.body.innerHTML=html;
	}
		
	function _updateToolbar()
	{
		if (editor.toolbar)
			editor.toolbar.update();
	}
	
	this.execCmd=function(cmd, param){
		//alert(cmd);
		setFocus();
		
		switch(cmd) {
			case "save":
				_save();
			break;
			case "Paste":	// paste unformatted text. Use Ctrl-V to paste formatted text.
				if (ie){
					var _data=window.clipboardData.getData("text");
					window.clipboardData.setData("Text", _data);
					editor.doc.execCommand(cmd, false, null);
					_updateToolbar();
				}
			break;
   
		    case "Undo":
		    case "Redo":
		    case "RemoveFormat":
		    case "Bold":
			case "Italic":
			case "Underline":
			case "Indent":
			case "Outdent":
			case "JustifyLeft":
			case "JustifyCenter":
			case "JustifyRight":
			case "JustifyFull":
			case "InsertUnorderedList":
			case "InsertOrderedList":
			case "RemoveFormat":
				//alert(cmd);
				editor.doc.execCommand(cmd, false, null);
				_updateToolbar();
			break;
		
			case "Unlink":
				this.removeLink();
				break;
			
			case "FontName":
			case "FontSize":
				//alert(cmd.toLowerCase()+"/"+param);
				editor.doc.execCommand(cmd.toLowerCase(), false, param);
				_updateToolbar()
			break;
			case "FormatBlock":
				if (ie)
					param="<"+param+">";	// IE needs <> around the tags!
				editor.doc.execCommand(cmd.toLowerCase(), false, param);
				_updateToolbar()
			break;

			/* Experimental:
			case "cssclass":
				addCssClass(param);
			break;
			case "cssclass":
				editor.doc.execCommand("FormatBlock", false, "span");
				var range = _createRange(_getSelection());
				if (ie)
					ptag=_getNearestTag(range.parentElement(), "span");
				else ptag=_getNearestTag(range.startContainer, "span");
				alert(range.startContainer);
				if (ptag)
					ptag.className=param;
				setFocus();
			break;
			*/
			
			case "ForeColor":
				//insertForeColor();
				editor.doc.execCommand("ForeColor", false, param);
				break;
			case "BackColor":
				editor.doc.execCommand("BackColor", false, param);
				break;
				
			case "InsertImg":
				insertImg();
				break;
			case "InsertLink":
				insertLink();
				break;
			case "UploadFile":
				uploadFile();
				break;			
			case "InsertTable":
				insertTable();
				break;
			case "TableProperties":
				editTableProperties();
				break;
			case "InsertTableRow":		
				insertTableRow();				
				break;
			case "DeleteTableRow":		
				deleteTableRow();				
				break;
			case "InsertTableCol":
				insertTableCol();				
				break;
			case "DeleteTableCol":		
				deleteTableCol();				
				break;
			case "MergeTableCells":		
				mergeTableCells();
				break;
			case "SplitTableCell":		
				splitTableCell();				
				break;
			
			case "InsertTML":		
				insertTML();				
				break;
			default:
				alert("Unknown Command: " + cmd);
				break;
		}		
	}

	function addCssClass(c){
		//alert("Class " + c);
		var sel=_getSelection();
		//alert(sel.rangeCount);
		for (var i=0; i<sel.rangeCount; i++){
			//var range = _createRange(sel);
			var range=sel.getRangeAt(i);		
			var el=editor.doc.createElement("span");
			el.className=c;
			var n=range.extractContents();
			el.appendChild(n);
			range.deleteContents();
			range.insertNode(el);
		}
		//range.surroundContents(el);
		//range.selectNodeContents(range.endContainer);
		sel.removeAllRanges();
		
		//insertNodeAtSelection(el, true);
	}
	
	this.getImgURL=function(){
    	//setFocus();
		var tag=_getNearestTagFromSelection("IMG");    	
		if (tag)
			return tag.src;
		else return "";
	}	

	this.createImg=function(url, urltype){
		// create img  element	
		var imgTag=_getNearestTagFromSelection("IMG");
		if (!imgTag){
			if (ie){
		    	var range = _createRange(_getSelection());    	
				range.execCommand("insertImage", false, url);
				// find img-tag:
				imgTag=_getNearestTagFromSelection("IMG");
			}
			else{
				imgTag=editor.doc.createElement("img");
				imgTag.src=url;
				insertNodeAtSelection(imgTag);
			}
		}
		else imgTag.src=url;
		if(urltype){
			var c = imgTag.className;
			c = c.replace(/wga-urltype-\w+ */, "");
			imgTag.className = c + (c?" ":"") + "wga-urltype-" + urltype;
		}
		return imgTag;
	}
	
	function insertImg(){
		//alert("cmd: insert image");
		var parameter="height=650,width=720";
	   	parameter=parameter+",screenX=0,left=0,screenY=0,top=0"
	    parameter=parameter+",dependent=0,directories=0"
	    parameter=parameter+",fullscreen=0,location=0,menubar=0"
	    parameter=parameter+",resizable=1,scrollbars=1,status=0,toolbar=0";     
 
		var handle=window.open(dlgBase + "img_win.jsp?action=MSRTF&field=&contentKey="+editor.contentkey+"&dbKey=" + editor.dbkey,
				"dlgImage", parameter);
		handle.focus();	
		window.cmd_insertImage=function(ImageURL, border, align, width, height, isContainer){
			var el_img=editor.createImg(ImageURL, isContainer?"file":"intfile");
			el_img.border=border;
			el_img.align=align;	
			if (editor.toolbar)
				editor.toolbar.update();			
		}
	}
	
	function uploadFile(){
		var parameter="height=600,width=720"
  	      +",screenX=0,left=0,screenY=0,top=0"
 	      +",dependent=0,directories=0"
		  +",fullscreen=0,location=0,menubar=0"
	      +",resizable=0,scrollbars=1,status=0,toolbar=0";

		var handle=window.open(editor.contextPath + "/statictml/" + editor.dbkey + "/uploadImageToContent/" + editor.contentkey, "Upload" , parameter);	  			
		handle.focus();	
	}
		
	function insertForeColor(){
		//alert("cmd: insert forecolor");
		var parameter="height=550,width=720";
	   	parameter=parameter+",screenX=0,left=0,screenY=0,top=0"
	    parameter=parameter+",dependent=0,directories=0"
	    parameter=parameter+",fullscreen=0,location=0,menubar=0"
	    parameter=parameter+",resizable=1,scrollbars=1,status=0,toolbar=0";     

		var handle=window.open(dlgBase + "colorsel.jsp?action=MSRTF&field=&contentKey="+editor.contentkey+"&dbKey=" + editor.dbkey,
				"dlgImage", parameter);
		handle.focus();
		//window.editor="something";
		window.WGABI_selectColor=function(color){
			//alert("cb");
			editor.doc.execCommand("ForeColor", false, color);
		}
	}

	this.getLinkURL=function(){
    	//setFocus();
		var aTag=_getNearestTagFromSelection("A");    	
		if (aTag){
			// inside an A-Tag:
			return aTag.href;
		}
		else return "";
	}
	
	this.createLink=function(url, linktext, urltype){
		//alert(url);
		//setFocus();
		var aTag=_getNearestTagFromSelection("A");    	
		if (!aTag){
	    	var range = _createRange(_getSelection());    	
			if (ie){
				range.execCommand("CreateLink", false, url);
				// find a-tag:
				aTag=_getNearestTagFromSelection("A");
		   	   	if (linktext!=undefined){
					if (aTag && (!aTag.innerHTML || aTag.innerHTML==""))
						aTag.innerText=linktext;
				}
			}
			else{	// Mozilla:
				aTag=editor.doc.createElement("a");
				var contents=range.cloneContents();
				if (linktext!=undefined){
					// Test, if selection is empty (not so easy as expected!!):
			    	if (contents.childNodes.length==0 || (contents.childNodes.length==1 && contents.firstChild.nodeValue=="")){
						// selection is empty: write Linktext into the link
			    		aTag.appendChild(editor.doc.createTextNode(linktext));
					}
				}
				aTag.appendChild(range.extractContents());
				range.insertNode(aTag);									
			}
		}
		aTag.href=url;
		if(urltype){
			var c = aTag.className;
			c = c.replace(/wga-urltype-\w+ */, "");
			aTag.className = c + (c?" ":"") + "wga-urltype-" + urltype;
		}
		
		return aTag;
	}
	
	this.removeLink=function(){
		//console.log("unlink called");
		var aTag=_getNearestTagFromSelection("A");
		if(aTag){
			// the following works in FF and Safari3 and IE6
			// editor.doc.execCommand("unlink") is currently not supportet in Safari
			var parent = aTag.parentNode;
			var children = aTag.childNodes;
			var nodelist = [];
			for(var i=0; i<children.length; i++)
				nodelist.push(children.item(i));
			for(var i=0; i<nodelist.length; i++){
				var node=nodelist[i];
				//console.log(i, node, node.nodeType, node.nodeName, node.NodeValue);
				parent.insertBefore(node, aTag)
			}
			parent.removeChild(aTag);
		}
	}
	
	function insertLink(){
		var parameter="height=580,width=730";
	    parameter=parameter+",screenX=0,left=0,screenY=0,top=0"
	    parameter=parameter+",dependent=0,directories=0"
	    parameter=parameter+",fullscreen=0,location=0,menubar=0"
	    parameter=parameter+",resizable=1,scrollbars=1,status=1,toolbar=0";
    	
    	var qs="";
    	var linktext=escape(getSelectedText());	// Default Linktext
    	var range = _createRange(_getSelection());    	
    	var aTag=_getNearestTagFromSelection("A");    	
		if (aTag){
			// inside an A-Tag:
			if (ie){
				linktext=aTag.innerText;	// use existing linktext instead of selection
			}
			else{
				//range.selectNode(aTag);		// select the complete a-tag (works only in Mozilla)
				linktext=range.toString();
			}
			//alert(linktext);
			qs = "&LinkTitle=" + escape(linktext);
			
			var linktype=aTag.getAttribute("linkType");
			var wgakey=aTag.getAttribute("wgakey");
			
			if(!linktype){
				// new style:
				// link has class="wga-linktype-<linktype>" rel="<wgakey>"
				// find linktype in classname
				var classes=aTag.className.split(" ");
				for(var i=0; i<classes.length; i++){
					var c=classes[i].split("-");
					if(c[0]=="wga" && c[1]=="linktype"){
						linktype=c[2];
						wgakey=aTag.rel;
					}
				}
			}				
			
			if(linktype && linktype != "" ){
		    	qs += "&URLArt=" + linktype;
		    	if(linktype.toLowerCase() == "exturl" ){
		    		qs += "&defaultLinkKey=" + aTag.href;
		    	}
		    }
		    if(wgakey && wgakey != "" ){
		    	qs += "&defaultLinkKey=" + wgakey;
		    }
		    if( aTag.target && aTag.target != "" ){
		    	qs += "&linkTarget=" + aTag.target;
		    }
		} 
		else if (getSelectedText()!="")
    		qs="&LinkTitle=" + linktext;
		
		var handle=window.open(dlgBase + "dlg_link.jsp?contentKey="+editor.contentkey+"&dbKey="+editor.dbkey+qs,
    			"dlgURLLink", parameter);
		handle.focus();	
		window.TheURLLink=function(sLinkUrl, sLinkTitle, sLinkTypeValue, sLinkTarget, sWGAKey){

			aTag=editor.createLink(sLinkUrl, sLinkTitle);
			aTag.setAttribute("linkType", sLinkTypeValue);
			aTag.setAttribute("wgakey", sWGAKey);
			aTag.target = sLinkTarget;			
			
			if (editor.toolbar)
				editor.toolbar.update();						
		}
	}

	this.isInTable=function(){
		if (_getNearestTagFromSelection("TABLE"))
			return true;
		else return false;		
	}
	
	this.setClassName=function(tag, newclass){
		var t_el=_getNearestTagFromSelection(tag.toUpperCase());
		if (t_el)
			t_el.className=newclass;
		else alert("setClassName: Element " + tag + " not found");
	}
	
	this.setTrClassName=function(newclass, applyto){
		if (applyto=="selected")
			this.setClassName("tr", newclass);
		else if(applyto=="all"){
			var el=_getNearestTagFromSelection("TABLE");
			if (!el) return;
			trlist=el.getElementsByTagName("TR");
			for (var i in trlist)
				trlist[i].className=newclass;
		}
	}
	this.setTdClassName=function(newclass, applyto){
		if (applyto=="selected")
			this.setClassName("td", newclass);
		else if(applyto=="row"){
			var el=_getNearestTagFromSelection("TR");
			if (!el) return;
			tdlist=el.getElementsByTagName("TD");
			for (var i in tdlist)
				tdlist[i].className=newclass;
		}
		else if(applyto=="all"){
			var el=_getNearestTagFromSelection("TABLE");
			if (!el) return;
			var tdlist=el.getElementsByTagName("TD");
			for (var j in tdlist)
				tdlist[j].className=newclass;
		}
	}
	
	this.createTable=function(rows, cols, width, align){
		rows=parseInt(rows);
		cols=parseInt(cols);
		if (rows.toString()=="NaN" || cols.toString=="NaN"){
			alert("please enter a number for #rows ans #cols");
			return;
		}
		//alert(rows + "/" + cols);
		var el_table=editor.doc.createElement("table");
		el_table.width=width; 
		el_table.align=align;
		var el_tbody=editor.doc.createElement("tbody");
		el_table.appendChild(el_tbody);
		
		for (r=0; r < rows; r++){
			el_tr=editor.doc.createElement("tr");
			el_tbody.appendChild(el_tr); 			
			for (c=0 ; c < cols; c++ ){
				el_td=editor.doc.createElement("td");
				if (!ie)
					// Mozilla needs a <br>
					el_td.appendChild(editor.doc.createElement("br"));
				el_tr.appendChild(el_td);
			}
		}			
		insertNodeAtSelection(el_table);
		_updateToolbar();
		return el_table;
	}
	
	function insertTableRow(){
		//setFocus();
		if (!editor.isInTable()){
			alert("Please select a table");
			return;
		}

		var tr = _getNearestTagFromSelection("TR")		
		if (!tr) {
			return alert("no tr found");
		}
		var otr = tr.cloneNode(true);
		//clear row
		var tds = otr.getElementsByTagName("td");
		for (var i in tds) {
			var td = tds[i];
			try{
				td.rowspan = 1;
				td.innerHTML = ie ? "" : "<br>";
			}
			catch(e){
				// may happen, if td contains a sub-table. Ignore this.
			}
		}
		tr.parentNode.insertBefore(otr, tr.nextSibling);
		_updateToolbar();
	}

	function deleteTableRow(){
		//alert("deleteTableRow");
		if (!editor.isInTable()){
			alert("Please select a table");
			return;
		}
		
		var tr=_getNearestTagFromSelection("TR");
		var table=_getNearestTagFromSelection("TABLE");
		tr.parentNode.removeChild(tr);
		if (table.rows.length==0){
			// last row: delete the table.
			table.parentNode.removeChild(table);			
		}
		_updateToolbar();
	}

	function insertTableCol(){
		//alert("insertTableCol");
		if (!editor.isInTable()){
			alert("Please select a table");
			return;
		}
		var td=_getNearestTagFromSelection("TD");
		var index = td.cellIndex+1;
		var rows=td.parentNode.parentNode.rows;
		for (i=0; i<rows.length; i++){
			tr=rows[i]
			if (tr.cells.length>=index)
				var new_td=tr.insertCell(index);	
			else
				var new_td=tr.insertCell();
			new_td.setAttribute("valign", "top");
			if (!ie)
				new_td.innerHTML="<br>";
		}
		_updateToolbar();
	}

	function deleteTableCol(){
		var td=_getNearestTagFromSelection("TD");
		if (!td){
			alert("Plese select one single cell");
			return;
		}
		var index= td.cellIndex;
		var rows=td.parentNode.parentNode.rows;
		for (i=0; i<rows.length; i++){
			tr=rows[i];
			if (tr.cells.length<index+1)
				index=tr.cells.length-1;	// take the last cell-index instead
			toBeDeleted_td=tr.cells[index];
			if (toBeDeleted_td.colSpan>1)
				toBeDeleted_td.colSpan=toBeDeleted_td.colSpan-1
			else{
				tr.deleteCell(index);
				if (tr.cells.length==0){
					// last cell: delete the table.
					table=_getNearestTag(tr, "TABLE");
					table.parentNode.removeChild(table);
					break;
				}
			}
		}
		_updateToolbar();
	}

	this.mayMergeTableCells=function (){
		var td=_getNearestTagFromSelection("TD");
		if (!td)
			return false;			// not in a table cell
		var index=td.cellIndex;
		var tr=td.parentNode;
		if (tr.cells[index+1])
			return true;			// cells to the right
		else return false;			// we are in the right cell
	}
	
	function mergeTableCells(){
		var td=_getNearestTagFromSelection("TD");
		if (!td){
			alert("Plese select one single cell");
			return;
		}
		var index= td.cellIndex;
		var tr=td.parentNode;
		if (tr.cells[index+1]){
			td.colSpan = td.colSpan + tr.cells[index+1].colSpan;
			tr.deleteCell(index+1);
			_updateToolbar();
		}
		else
			alert("Please set cursor into a table-cell that has a column to the right");			
	}

	this.maySplitTableCell=function(){
		var td=_getNearestTagFromSelection("TD");
		if (!td)
			return false;			// not in a table cell
		var index= td.cellIndex;
		var tr=td.parentNode;
		if (td && td.colSpan>1) return true;
		else return false;
	}
	
	function splitTableCell(){
		var td=_getNearestTagFromSelection("TD");
		if (!td)
			return false;			// not in a table cell
		var index= td.cellIndex;
		var tr=td.parentNode;
		if (td && td.colSpan>1){
			td.colSpan=td.colSpan-1;
			var new_td=tr.insertCell(index+1);
			new_td.setAttribute("valign", "top");
			if (!ie)
				new_td.innerHTML="<br>";
			_updateToolbar();
		}
		else
			alert("Split not possible in this cell.");
	}

	function insertTML(){
		// create button element			
		var el=editor.doc.createElement("tml");
		//el.unselectable="on";
		el.setAttribute("type", "innerlayout");
		el.style.borderColor="red";
		el.style.borderWidth="1px";
		el.style.borderStyle="solid";
		el.appendChild(editor.doc.createTextNode("TML-Element"));
		//setFocus();				
		insertNodeAtSelection(el);		
	}

	this.insertHTML=function (theHTML){
		var el=editor.doc.createElement("span");
		el.innerHTML=theHTML;
		insertNodeAtSelection(el);		
	}

	function resizeIframe(){
		try{
			var h=editor.doc.height;
			if (editor.iframe.height!=h+4){
				//alert(h);
				editor.iframe.height=h+4;
				editor.iframe.contentWindow.scrollTo(0, 0);
			}
			if (editor.doc.designMode != "on")
				editor.doc.designMode = "on";
			//console.debug("resizeIframe resized: " + h + "/" + editor.iframe.height + "/" + editor.iframe.contentWindow);
		}
		catch(e){
			// try-catch in case of error
			alert("resizeIframe-exception: " + e);
		}
	}

	//+++++++++++++++++++++++++++
	// Constructor
	//+++++++++++++++++++++++++++

	this.id=id;
	this.toolbar=null;
	this.contextPath=context;
	if (contentkey==undefined)
		this.contentkey=myContentKey;
	else this.contentkey=contentkey;
	if (dbkey==undefined)
		this.dbkey=myDbKey;
	else this.dbkey=dbkey;
	
	this.autofocus = (autofocus==undefined)?true:autofocus;
		
	var dlgBase=context+"/bi/editors/";
	
	var ie=document.all;	// probably there is a better solution?
    var ua = navigator.userAgent.toLowerCase();
	var isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1);
    var isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1);

	var editor=this;
	this.viewmode="wysiwyg";
	
	this.orgElement=document.getElementById(id);
	this.unencodedElement=document.getElementById(id + "_unencoded");
	
	/*
	create new DOM elements. The DOM structure looks like this when finished:
	parent element
	|-toolbar						only if used and not in "floating" mode
	|-span element 					hiddden in viewmode "html" and "preview".
	| |-editelement 				<span> in case of IE, <iframe> in case of Mozilla
	|-sourcecode element 			(textarea) - visiable only in viewmode "html"
	|-form							if generated by generateForm()
	|-original element 				identified by the given ID - hidden in modes "wysiwyg" and "html", visable in mode "preview"
	*/
	
	// hide original element
	this.orgElement.style.display="none";
	this.spanElement=document.createElement("span");
	this.orgElement.parentNode.insertBefore(this.spanElement, this.orgElement);
		
	this.sourcecodeElement=this.orgElement.parentNode.insertBefore(document.createElement("textarea"), this.orgElement);
	this.sourcecodeElement.style.display="none";
	this.sourcecodeElement.style.width="100%";
	this.sourcecodeElement.rows="10";
	
	// create editor area
	if (ie){
		this.editelement=document.createElement("span");

		// set id for robot tests
		this.editelement.id = "rtf_" + this.id;
		
		if(width!=undefined)
			this.editelement.style.width=width;
		this.editelement.style.border="dotted black 1px";
		this.editelement.style.padding="2";
		this.editelement.className="WGABI_editor";
		this.editelement.innerHTML=this.unencodedElement.innerHTML;
		this.spanElement.appendChild(this.editelement);
		this.editelement.contentEditable = true;
		if(this.autofocus){
			try{
			this.editelement.focus();
			}
			catch(e){}
		}
		this.doc=document;
		//this.registerEvents(["onfocus", "contextmenu", "onmousedown", "onkeydown"]);
		// context menu not supported in this version
		this.registerEvents(["onfocus", "onmousedown", "onkeydown"]);
	}
	else{	// Code for Mozilla:
		this.iframe=document.createElement("iframe");
		this.iframe.width="100%";
		this.iframe.height="20";
		this.iframe.style.border="dashed black 1px";
		//this.iframe.style.padding="1px";

		this.iframe.scrolling="no"
		this.spanElement.appendChild(this.iframe);
		this.editelement=this.iframe;
		
		// set id for robot tests
		this.editelement.id = "rtf_" + this.id;
		
		function initIframe(){
			if(!editor.iframe)
				alert("iframe not found");
			if(!editor.iframe.contentWindow)
				alert("iframe has not contentWindow");
		
			var doc = editor.iframe.contentWindow.document;
			if(doc==null)
				alert("iframe has no document");
			try{
				doc.designMode = "on";
			}catch(e){
				//alert(e + "\ndesignmode not avaliable");
			}
				
			doc.open();
			var html = "<html>\n";
			html += "<head>\n";
			html += "<base href='" + document.location + "'>";
			html += "<style>td{border:dotted 1px silver;}</style>\n";
			if (head!=undefined){
				html+=head;
			}
			html += "</head>\n";
			html += "<body class=\"rtf\" style=\"margin:1px\">";
			var content="";
			if (editor.unencodedElement.tagName=="TEXTAREA")
				content=editor.unencodedElement.value;
			else content=editor.unencodedElement.innerHTML;
			html += content.replace(/\s/g, "")=="" ? "<br>" : content;
			html += "</body>\n";
			html += "</html>";
			doc.write(html);
			doc.close();
			// enable editable mode for Mozilla
			// important: do this AFTER the content is written to the document
			// designMode is not active im some cases otherweise.

			//doc.designMode = "on";

			// try to copy stylesheets from the original document
			/* removed this section because that's not what you realy whant.			
			var styles=document.getElementsByTagName("style");
			for (i=0; i<styles.length; i++){
				var clone=styles[i].cloneNode(true);
				var head=doc.getElementsByTagName("head")[0];
				head.appendChild(clone);				
			}
			var links=document.getElementsByTagName("link");
			for (i=0; i<links.length; i++){
				var clone=links[i].cloneNode(true);
				var head=doc.getElementsByTagName("head")[0];
				head.appendChild(clone);
			}
			*/
			
			// automaticaly resize iframe height
			function resizeIframe(){

				try{
					var h=editor.doc.documentElement.scrollHeight;		// editor.doc.height;
					
					if (editor.iframe.height!=h){
						editor.iframe.height=h;
						editor.iframe.contentWindow.scrollTo(0, 0);
					}
					if (editor.doc.designMode != "on")
						editor.doc.designMode = "on";
					if(editor.iframe.contentWindow)
						window.setTimeout(resizeIframe, 250);
					//console.debug("resizeIframe timeout: " + h + "/" + editor.iframe.height + "/" + editor.iframe.contentWindow);
				}
				catch(e){
					// try-catch in case of error
				}
			}
			window.setTimeout(resizeIframe, 250);

			if(editor.autofocus)
				editor.iframe.contentWindow.focus();
			editor.doc=doc;
			//editor.registerEvents(["focus", "blur", "contextmenu", "keypress", "mousedown"]);
			// context menu not supported in this version
			editor.registerEvents(["focus", "blur", "keyup", "mouseup"]);
			doc.execCommand('styleWithCSS', false, false);
			_updateToolbar();
		}
		setTimeout(initIframe, 10);
				
	}

	//-------- end Constructor----------------
	
	this.closeEditor=function(){
		this.changeViewMode("preview");		
		if(ie)
			this.unregisterEvents(["onfocus", "onmousedown", "onkeydown"]);
		else this.unregisterEvents(["focus", "blur", "keypress", "mousedown"]);
		if (this.toolbar && this.toolbar.hide)
			this.toolbar.hide(true);
	}
	
	this.getData=this.getRTFHTML;
}


function TextEditor(id){

	var el=document.getElementById(id);
	var original_display=el.style.display;
	el.style.display="none";
	var input_el=document.createElement("input");
	input_el.value=el.innerHTML;
	el.parentNode.insertBefore(input_el, el);

	this.closeEditor=function(){
		el.innerHTML=input_el.value;
		el.parentNode.removeChild(input_el);
		el.style.display=original_display;
	}
	
	this.getData=function(){
		return input_el.value;
	}
	
	this.setData=function(data){
		input_el.value=data;
	}	
	
	this.getRTFHTML=function(){
		return this.getData();
	}
	this.createLink=function(structkey){
		this.setData(structkey);
	}
}

