//-------------------------------------------------------------------------------------------
// Copyright (C) Marja Ribbers-de Vroed, Webware Systems (marja@webwaresystems.nl)
//
// This online HTML editor only works with IE5.5+ and browsers based on Mozilla 1.3+
// (Mozilla 1.3+ supports the Midas API for rich text editing)
//-------------------------------------------------------------------------------------------

// browser name
var g_sUA = navigator.userAgent.toLowerCase();
var g_bIE = ((g_sUA.indexOf("msie") != -1) && !window.opera && (g_sUA.indexOf("webtv") == -1))? true : false;
var g_bGecko = (g_sUA.indexOf('gecko') != -1) ? true : false;

//check to see if designMode mode is available
var g_bRTE = (document.getElementById && document.designMode);
//for testing standard textarea, uncomment the following line
//g_bRTE = false;

var g_bAbsoluteReferences = false, g_sCurrentEditor = "", g_aDlgArgs;

// Pointers
var dlgInsertSymbol, dlgInsertTable, dlgInsertLink, dlgInsertImage, dlgInsertSmiley, dlgInsertCB, dlgInsertUserField, dlgInsertConfigVar, dlgFindReplace, dlgSelectColor, dlgPasteWord;

function wsLoadEditorContent(p_sFieldName, p_sTextArea, p_sStylesheet) {
    // Load the content into the editor
    var l_sField = p_sTextArea;
    var l_oField = document.getElementById(l_sField);
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	l_oIframe.wsLoaded = false;
	l_oIframe.wsContentField = l_sField;
    }
    wsEditInitialize(p_sFieldName, false, p_sStylesheet);
    //
    wsAttachEvent(window, 'unload', wsCloseDialogs);
}

function wsEditInitialize(p_sFieldName,p_iAutoSave,p_sStylesheet) {
    //Initialize the editor with an empty document
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	var l_sField = l_oIframe.wsContentField;
	var l_oField = document.getElementById(l_sField);
	var l_oFieldTable = MM_findObj(p_sFieldName);
	if (l_oField && l_oFieldTable) {
	    if (g_bRTE) {
		var l_oRTE = l_oIframe.contentWindow.document;
		l_oFieldTable.style.display = "block";
		l_oField.style.display = "none";
		var l_sHtml = l_oField.value, l_sCssCode, l_bRTE, l_sIEemu;
		l_sHtml = wsEncodeForumStyle(l_sHtml);
		//write html based on browser type
		if (g_bIE) {
		    try {
			var l_sRoot = p_sFieldName + "_hiddenSiteRoot";
			var l_oRoot = MM_findObj(p_sFieldName + "_hiddenSiteRoot");
			if (p_sStylesheet) {
			    l_sCssCode = "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + p_sStylesheet + "\"></link>";
			}
			else {
			    // no CSS file specified
			    l_sCssCode = "";
			}
			var l_sEditorCode = "<html><head>" + l_sCssCode;
			l_sEditorCode += "</head><body>" + l_sHtml + "</body></html>";           
			l_bRTE = true;
			l_sEditorCode = wsEditCleanGeckoIE(l_sEditorCode, "i|b", "em|strong");
			l_oRTE.open();
			l_oRTE.write(l_sEditorCode);
			l_oRTE.close();
			l_oRTE.designMode = "On";
			l_oIframe.wsLoaded = true;
		    }
		    catch (e) {
			alert("IE error writing editor content!");
		    }
		}
		else if (g_bGecko) {
		    try {
			wsAttachEvent(window, "load", function () {
			    //
			    var oIframe = wsEditGetIframe(p_sFieldName);
			    var oRTE = oIframe.contentWindow.document;
			    oIframe.contentDocument.designMode = "on";
			    try {
				oRTE.execCommand('styleWithCSS',false,false);
			    }
			    catch (e) {
				oRTE.execCommand('useCSS',false,true);
			    }
			});
			try{
			    l_sHtml = wsEditCleanGeckoIE(l_sHtml, "em|strong", "i|b");
			    l_oRTE.body.innerHTML = l_sHtml;
			    l_oIframe.wsLoaded = true;
			    // attach a keyboard handler for gecko browsers to make keyboard shortcuts work
			    l_oRTE.addEventListener("keypress", wsGeckoKeyPress, true);
			    l_oRTE.addEventListener("focus", function (){wsCloseDialogs();}, false);
			}
			catch (e) {
// 			alert(g_sErrorEditorContent);
			}
		    }
		    catch (e) {
			// gecko may take some time to enable design mode. Keep looping until able to set.
			if(g_bGecko){
			    setTimeout("wsEditInitialize('" + p_sFieldName + "'," + p_iAutoSave + ",'" + p_sStylesheet + "')", 200);
			}
			else{
			    return false;
			}
		    }
		}
		l_oIframe.contentWindow.document.editMode = "HTML";
		if (p_iAutoSave) {
		    l_oIframe.contentWindow.document.autosave = p_iAutoSave;
		}
		l_oIframe.contentWindow.editorLoaded = true;
		l_oIframe.contentWindow.document.ShowBorders = false;
		window.status = g_sModeWYSIWYG;
		for (l_iIndex = 0; l_iIndex < document.forms.length; l_iIndex++) {
		    wsAttachEvent(document.forms[l_iIndex], 'submit', function() { wsEditSave(p_sFieldName); wsCloseDialogs()});
		}
		wsAttachEvent(window, 'submit', function () {
		    // set readonly on form submit
		    var oIframe = wsEditGetIframe(p_sFieldName);
		    oIframe.contentDocument.designMode = "off";
		}
		    )
		    }
	    else {
		l_oFieldTable.style.display = "none";
		l_oField.style.display = "block";
	    }
	}
    }
}

function wsEditCleanUpHTML(p_sHtml) {
    // Remove all invalid, unwanted stuff from inserted HTML code
//     alert('wsEditCleanUpHTML');
    var l_sTmp = "";
    while (l_sTmp != p_sHtml) { // recursive, because cleaning may have caused new garbage
	l_sTmp = p_sHtml;
	p_sHtml = wsEditCleanGeckoIE(p_sHtml, "i|b", "em|strong")
	p_sHtml = wsEditCleanUpTags(p_sHtml);
//	p_sHtml = wsEditEnsureAttrQuotes(p_sHtml);
	p_sHtml = wsEditCleanUpTagAttributes(p_sHtml);
	if (g_bXHTML) {p_sHtml = wsEditXHTMLCloseTags(p_sHtml);}
	p_sHtml = wsEditCleanUpMicrosoftGarbage(p_sHtml);
	if (!g_bAbsoluteReferences) {
	    p_sHtml = wsEditReplaceAbsLocalLinks(p_sHtml);
	    p_sHtml = wsEditReplaceAbsImgLinks(p_sHtml);
	}
	else {
	    p_sHtml = wsEditReplaceRelLocalLinks(p_sHtml);
	    p_sHtml = wsEditReplaceRelImgLinks(p_sHtml);
	}
	p_sHtml = wsPreserveInternalAnchors(p_sHtml);
	p_sHtml = wsEditCleanUpOtherGarbage(p_sHtml);
	p_sHtml = wsEditCleanUpEmptyTags(p_sHtml);
	p_sHtml = wsEditPreventEmptyTableCells(p_sHtml);
// 	p_sHtml = wsEditSetTableBorderOn(p_sHtml);
//	p_sHtml = wsEditRemovePTags(p_sHtml);
	p_sHtml = wsEditRemoveCBWrappingPTags(p_sHtml);
    }
    return p_sHtml;
}

function wsEditCleanGeckoIE(p_sHtml, p_sTags, p_sReplace) {
    // IE and Gecko handle some things somewhat different. Make
    // sure they understand each other's code
    var l_sHtml = p_sHtml;
    var l_aTags = p_sTags.split("|"), l_sTag;;
    var l_aReplace = p_sReplace.split("|"), l_sReplace;
    if (l_aTags.length != l_aReplace.length) {
	alert("!!!");
	return;
    }
    var l_oRegExp, l_sPattern;
    for (var i=0; i<l_aTags.length; i++) {
	l_sTag = l_aTags[i];
	l_sReplace = l_aReplace[i];
	l_sPattern = "(<\/?)" + l_sTag + "(\s*>)|(<\/?)" + l_sTag + "(\s+[^>]*>)";
	l_sReplace = "$1" + l_sReplace + "$2";
	l_oRegExp = new RegExp(l_sPattern, "gi");
	l_sHtml = l_sHtml.replace(l_oRegExp,l_sReplace);
    }
    return l_sHtml;
}

function wsEditCleanUpTags(p_sHtml) {
    // Keep only wanted/valid tags (= valid HTML)
    var l_sTags = "p|h1|h2|h3|h4|h5|h6|addr|pre|div|span|br|strong|em|u|i|b|ul|ol|li|a|img|blockquote|table|tr|th|td|hr|sub|sup|strike|form|fieldset|legend|input|textarea|label";
    if (g_bTextFormatting) {
	l_sTags += "|font";
    }
    var l_sPattern = "(<\/?(" + l_sTags + ")[^>]*>)|(<\/?[^>]*>)";
    var l_sReplace = "$1";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    // force all tags to lowercase
    var l_aTags = l_sTags.split("|"), l_sTag;
    for (var i=0; i<l_aTags.length; i++) {
	l_sTag = l_aTags[i];
	//
	l_sPattern = "(<\/?)" + l_sTag + "(\s*>)|(<\/?)" + l_sTag + "(\s+[^>]*>)";
	l_sReplace = "$1" + l_sTag.toLowerCase() + "$2";
	l_oRegExp = new RegExp(l_sPattern, "gi");
	p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    }
    return p_sHtml;
}

function wsEditEnsureAttrQuotes(p_sHtml) {
    // Make sure all tag attribute values are wrapped in quotes
    var l_sPattern = "(=)([^\" \t>]+)";
    var l_sReplace = "$1\"$2\"";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    return p_sHtml;
}

function wsEditCleanUpTagAttributes(p_sHtml) {
    // Keep only wanted/valid tag attributes (= valid HTML)
    // For each tag: define which attributes to keep (based on HTML 4.01 Transitional specs)
    // Note: I'm not allowing *all* attributes allowed in the specs, but only a relevant subset for my purpose.
    //       Add any attributes that you need to be allowed.
    var l_aTagsAttr 	= new Array();
/*
  l_aTagsAttr[0] 	= new Array("em|strong|blockquote",		"id|class|title");
  l_aTagsAttr[1] 	= new Array("p|h1|h2|h3|h4|h5|h6|div|span",	"id|class|title|align");
  l_aTagsAttr[2] 	= new Array("br", 	"id|class|style|title|clear");
  l_aTagsAttr[3] 	= new Array("ul|ol|li", "id|class|style|title");
  l_aTagsAttr[4] 	= new Array("table",	"id|class|style|title|align|width|border|bordercolor|cellspacing|cellpadding");
  l_aTagsAttr[5] 	= new Array("tr", 	"id|class|style|title|align|valign");
  l_aTagsAttr[6] 	= new Array("th|td",	"id|class|style|title|align|valign|width|rowspan|colspan");
  l_aTagsAttr[7] 	= new Array("a",        "id|class|style|title|name|href|target|tabindex|accesskey|onfocus|onblur|onclick|onmouseover|onmouseout");
  l_aTagsAttr[8] 	= new Array("img", 	"id|class|style|title|src|alt|longdesc|name|align|height|width|usemap|hspace|vspace|border");
  l_aTagsAttr[9] 	= new Array("hr", 	"id|class|style|title|align|width");
*/
    l_aTagsAttr[0] 	= new Array("p|h1|h2|h3|h4|h5|h6|addr|pre",	"class|style|align");
    l_aTagsAttr[1] 	= new Array("table",	"class|style|align|width|border|bordercolor|cellspacing|cellpadding");
    l_aTagsAttr[2] 	= new Array("tr", 	"class|style|align|valign");
    l_aTagsAttr[3] 	= new Array("th|td",	"class|style|align|valign|width|rowspan|colspan");
    l_aTagsAttr[4] 	= new Array("a",        "class|style|href|name|target|tabindex|accesskey|onfocus|onblur|onclick|onmouseover|onmouseout");
    l_aTagsAttr[5] 	= new Array("img", 	"class|style|title|src|alt|longdesc|name|align|height|width|usemap|hspace|vspace|border");
    l_aTagsAttr[6] 	= new Array("hr", 	"class|style|align|width");
    l_aTagsAttr[7] 	= new Array("ul|ol|li|span", "class|style");
    l_aTagsAttr[8] 	= new Array("b|strong|i|em", "");
    if (g_bTextFormatting) {
	l_aTagsAttr[9] 	= new Array("font",     "class|style|size|face|color");
    }
    // now scan HTML and clean up
    for (var i=0; i<l_aTagsAttr.length; i++) {
	var l_sTags = l_aTagsAttr[i][0];
	var l_sAttributesToKeep = l_aTagsAttr[i][1];
	var l_aTags = l_sTags.split("|");
	for (var j=0; j< l_aTags.length; j++) {
	    var l_sTag = l_aTags[j];
	    p_sHtml = wsEditCleanUpAttributes(p_sHtml, l_sTag, l_sAttributesToKeep);
	}
    }
    return p_sHtml;
}  

function wsEditCleanUpAttributes(p_sHtml, p_sTag, p_AttributesToKeep) {
    // Remove all invalid/unwanted attributes from tags (= clean, valid code)
    var l_sPattern = "<" + p_sTag + "\s*>|<" + p_sTag + "\s+[^>]*>";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    var l_iMatch = p_sHtml.search(l_oRegExp);
    var l_sNewHTML = "";
    while (l_iMatch >= 0) {
	var l_aTagFound = p_sHtml.match(l_oRegExp);
	var l_sTagFound = l_aTagFound[0]; // Handle the 1st tag we found
	var l_iTagLength = l_sTagFound.length;
	var l_iSliceLeft = l_iMatch + l_iTagLength;
	var l_aAttr = p_AttributesToKeep.split("|");
	var l_aKeep = new Array();
	var l_iKeepIndex = 0;
	for (var i=0; i<l_aAttr.length; i++) { // Define pattern for current property
	    var l_sPropPattern = "[ \t]" + l_aAttr[i] + "=(\"[^\"]*\"|[^ >]+[ >])";  // attr="value" or attr=value
	    var l_oRegExp2 = new RegExp(l_sPropPattern, "gi");
	    var l_aPropFound = l_sTagFound.match(l_oRegExp2);
	    if (l_aPropFound) { // Found the property we were looking for
		// Save valid property for re-building the tag
		l_aKeep[l_iKeepIndex] = l_aPropFound[0];
		l_iKeepIndex++;
		// Strip this property part out of the tag we're handling
		l_sTagFound = l_sTagFound.replace(l_oRegExp2, " ");
	    }
	}
	// Re-build tag, but only with valid attribute this time
	var l_sNewTag = "<" + p_sTag.toLowerCase(); 
	for (i=0; i<l_aKeep.length; i++) {
	    // Make sure attribute name is lowercase
	    var l_aAttrPairs = new Array();
	    var l_iIndex = l_aKeep[i].indexOf("=");
	    l_aAttrPairs[0] = l_aKeep[i].substring(0, l_iIndex);
	    l_aAttrPairs[1] = l_aKeep[i].substring(l_iIndex+1);
	    var l_sAttr = l_aAttrPairs[0].toLowerCase();
	    var l_bEnsureQuote = false;
	    l_sNewTag += l_sAttr + "=";
	    // ensure quotes around attribute value
	    if (l_aAttrPairs[1].substring(0,1) != '"') {
		l_bEnsureQuote = true;
		l_sNewTag += '"';
	    }
	    l_aAttrPairs[1] = wsTagTrim(l_aAttrPairs[1]);
	    l_sNewTag += l_aAttrPairs[1];
	    if (l_aAttrPairs.length > 2) {
		for (var i=2; i<l_aAttrPairs.length; i++) {
		    l_sNewTag += "=" + l_aAttrPairs[i];
		}
	    }
	    if (l_bEnsureQuote) {
		var l_iLength = l_sNewTag.length;
		if (l_sNewTag.substring(l_iLength-1) == ">") {
		    l_sNewTag = l_sNewTag.substring(0,l_iLength-1);
		}
		l_sNewTag += '"';
	    }
	}
	if (l_sNewTag.substring(l_sNewTag.length-1) != ">") {
	    l_sNewTag += ">";
	}
	// Build modified HTML string
	l_sNewHTML = l_sNewHTML + p_sHtml.substring(0,l_iMatch);
	// Replace original tag with new one
	l_sNewHTML = l_sNewHTML + l_sNewTag;
	// Continue with rest of original HTML string
	p_sHtml = p_sHtml.substring(l_iSliceLeft,p_sHtml.length);
	l_iMatch = p_sHtml.search(l_oRegExp);
    }
    // Make sure we don't loose bits of the original HTML string
    l_sNewHTML += p_sHtml;
    return l_sNewHTML;
}

function wsEditCleanUpWordExtra(p_sFieldName) {
    //Save the content of the iframe inside an hidden field
//    alert('wsEditCleanUpWordExtra');
    if (g_bRTE) {
	var l_oIframe = wsEditGetIframe(p_sFieldName);
	if (l_oIframe) {
	    
	    var l_sMode = l_oIframe.contentWindow.document.editMode;
	    var l_sField = l_oIframe.wsContentField;
	    var l_oField = document.getElementById(l_sField);
	    if (l_oField && l_sMode == "HTML") {
		var l_sHtml = l_oIframe.contentWindow.document.body.innerHTML;
		l_sHtml = wsEditCleanUpHTML(l_sHtml);
		// in addition, clear some more Microsoft Office specific garbage
		l_sHtml = wsEditCleanUpTagAttributesMicrosoft(l_sHtml);
		l_oField.value = l_sHtml;
		l_oIframe.contentWindow.document.body.innerHTML = "";
		l_oIframe.contentWindow.document.body.innerHTML = l_sHtml;
	    }
	}
    }
}

function wsEditCleanUpOtherGarbage(p_sHtml) {
    // Remove as much garbage as possible, so define what is considered to be garbage
    var l_aPatterns = new Array(), l_sHtml = p_sHtml;
    // Remove redundant spaces before closing bracket of all tags (= clean code)
    l_aPatterns[0] = new Array("[ \t]*>", ">");
    // Change MS things like <p:transition ...> into <p ...>
    l_aPatterns[1] = new Array("(<\/?(div|p|h1|h2|h3|h4|h5|h6|span)):[^ \t>]*([ \t]*[^>]*>)","$1$3");
    l_aPatterns[2] = new Array("<table><br>", "<table>");
    l_aPatterns[3] = new Array("<tbody><br>", "<tbody>");
    l_aPatterns[4] = new Array("<tr><br>", "<tr>");
    l_aPatterns[5] = new Array("</td><br>", "</td>");
    l_aPatterns[6] = new Array("</tr><br>", "</tr>");
    l_aPatterns[7] = new Array("</tbody><br>", "</tbody>");
    l_aPatterns[8] = new Array("<p><br>", "<p>");
    l_aPatterns[9] = new Array("<br></p>", "</p>");
    l_aPatterns[10] = new Array("<p><table>", "<table>");
    l_aPatterns[11] = new Array("</table></p>", "</table>");
    l_aPatterns[12] = new Array("&nbsp([^;])", "&nbsp;$1");
    // Actually remove the garbage
    for (var i=0; i<l_aPatterns.length; i++) {
	var l_sPattern = l_aPatterns[i][0];
	var l_sReplace = l_aPatterns[i][1];
	var l_oRegExp = new RegExp(l_sPattern, "gi");
	l_sHtml = l_sHtml.replace(l_oRegExp,l_sReplace);
    }
    // remove some misc. stuff
    l_sHtml = l_sHtml.replace(/(<p>)<span>([^<]*)<\/span>(<\/p>)/gi,"$1$2$3");
    return l_sHtml;
}

function wsEditCleanUpEmptyTags(p_sHtml) {
    // Remove empty tags like <p></p> (= clean code)
    var l_sTmpHTML = p_sHtml;
    // Define which tags need to be removed if empty
    var l_sTags = "a|span|b|i|u|p|h1|h2|h3|h4|h5|h6|div|em|strong|blockquote|font";
    var l_aTags = l_sTags.split("|");
    for (var i=0; i<l_aTags.length; i++) {
	var l_sPattern = "<" + l_aTags[i] + "[^>]*>[ \t]*<\/" + l_aTags[i] + ">";
	var l_oRegExp = new RegExp(l_sPattern, "gi");
	p_sHtml = p_sHtml.replace(l_oRegExp,"");
    }
    if (l_sTmpHTML != p_sHtml) { // recursive, because removing empty tags may in turn may have made other tags empty
	p_sHtml = wsEditCleanUpEmptyTags(p_sHtml);
    }
    return p_sHtml;
}

function wsEditReplaceAbsLocalLinks(p_sHtml) {
    // replace absolute links within own website by root relative links
    var p_sHost = g_sHttpHost.replace(".", "\.");
    var l_sPattern = "(href=\")http[s]?:\/\/" + g_sHttpHost + "(\/+)";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    var l_iMatch = p_sHtml.search(l_oRegExp);
    if (l_iMatch >= 0) {
	var l_sReplace = "$1$2";
	p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    }
    return p_sHtml;
}

function wsEditReplaceAbsImgLinks(p_sHtml) {
    // replace absolute image links within own website by root relative links
    var l_sPattern = "(src=\")http[s]?:\/\/[^\/]+";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    var l_iMatch = p_sHtml.search(l_oRegExp);
    if (l_iMatch >= 0) {
	var l_sReplace = "$1";
	p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    }
    return p_sHtml;
}

function wsEditReplaceRelLocalLinks(p_sHtml) {
    // replace root relative links with absolute links to own website
    var p_sHost = g_sHttpHost.replace(".", "\.");
    var l_sPattern = "(href=\"?[^#])(\/[^\/]+)";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    var l_iMatch = p_sHtml.search(l_oRegExp);
    if (l_iMatch >= 0) {
	var l_sReplace = "$1" +"http://" + g_sHttpHost + "$2";
	p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    }
    return p_sHtml;
}

function wsEditReplaceRelImgLinks(p_sHtml) {
    // replace root relative image links with absolute image links to own website
    var l_sPattern = "(src=\")(\/[^\/]+)";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    var l_iMatch = p_sHtml.search(l_oRegExp);
    if (l_iMatch >= 0) {
	var l_sReplace = "$1" +"http://" + g_sHttpHost + "$2";
	p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    }
    return p_sHtml;
}

function wsEditXHTMLCloseTags(p_sHtml) {
    // Close tags the XHTML way, eg. <hr/>
    var l_sTags = "br|hr|img";
    var l_aTags = l_sTags.split("|");
    for (var i=0; i<l_aTags.length; i++) {
	var l_sPattern = "(<" + l_aTags[i] + "[^>]*)(>)";
	var l_sReplace = "$1 /$2"
	    var l_oRegExp = new RegExp(l_sPattern, "gi");
	p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    }
    return p_sHtml;
}

function wsEditRemoveCBWrappingPTags(p_sHtml) {
    // remove <p></p> from things like <p>{{cb:...}}</p>
    var l_sPattern = "<p>[ \t]*({{cb:.*}})[ \t]*<\/p>";
    var l_sReplace = "$1";
    try {
	var l_oRegExp = new RegExp(l_sPattern, "gi");
	p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    }
    catch (e) {}
    return p_sHtml;   
}

function wsEditRemovePTags(p_sHtml) {
    // remove <p>
    var l_sPattern = "<p[^>]*>";
    var l_sReplace = "";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    // replace </p> with <br>
    l_sPattern = "<\/p[^>]*>";
    l_sReplace = (g_bXHTML) ? "<br />" : "<br>";
    l_oRegExp = new RegExp(l_sPattern, "gi");
    p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    return p_sHtml;
}

function wsEditPreventEmptyTableCells(p_sHtml) {
    // prevent empty table cells like <td ...></td>
    var l_sPattern = "(<td[^>]*>)\s*(</td)";
    var l_sReplace = "$1&nbsp;$2";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    return p_sHtml;
}

function wsEditSetTableBorderOn(p_sHtml) {
    var l_sPattern = "(<table [^>]*border=\"?)0(\"?[^>]*>)";
    var l_sReplace = "$11$2";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    return p_sHtml;
}

/* Editor functions */
function wsEditGetIframe(p_sFieldName) {
    // 
    var l_sIframeID = p_sFieldName + "_wsEditIframe";
    var l_oIframe = document.getElementById(l_sIframeID);
    return l_oIframe;
}

// function wsEditReload(p_sFieldName, p_sTextArea, p_iAutoSave, p_sStylesheet) {
//     //Check if the editor is initialized and restart it (for IE 5.0)
//     var l_oIframe = wsEditGetIframe(p_sFieldName);
//     l_oIframe.wsContentField = p_sTextArea;
//     if (l_oIframe.contentWindow.editorLoaded == null || l_oIframe.contentWindow.editorLoaded == false) {
// 	wsEditInitialize(p_sFieldName, p_iAutoSave, p_sStylesheet);}
// }

function wsEditFormat(p_sFieldName, p_sAction, p_sOption) {
    //Execute the edit commands
    wsCloseDialogs();
//     var l_oRange = wsGetRange(p_sFieldName);
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	l_oIframe.contentWindow.focus();
	var l_oRTE = l_oIframe.contentWindow.document;
	if (p_sAction == "FormatBlock" || p_sAction == "FontName" || p_sAction == "FontSize") { // headings, etc.
	    var l_oSelect = document.getElementById(p_sOption);
	    var l_iSelected = l_oSelect.selectedIndex;
	    // First one is always a label
	    if (l_iSelected != 0) {
		var l_sValue = l_oSelect.options[l_iSelected].value;
	    }
	    else {
		var l_sValue = "";
	    }
	    l_oRTE.execCommand(p_sAction, false, l_sValue);
	    l_oSelect.selectedIndex = 0;
	}
	else {
	    try{
		var l_sAction = p_sAction.toLowerCase();
		if (l_sAction == "hilitecolor") {l_sAction = "backcolor";}
		l_oRTE.execCommand(l_sAction, false, p_sOption);
		if (l_sAction == 'paste') {
		    wsEditCleanUpWordExtra(p_sFieldName);
		}
	    }
	    catch(e) {
		switch(p_sAction){
		case 'cut': keyboard = 'x'; break;
		case 'copy': keyboard = 'c'; break;
		case 'paste': keyboard = 'v'; wsEditCleanUpWordExtra(p_sFieldName); break;
		}
		alert(g_sErrorNoExecPermission + '\n' + g_sPleaseUseKeybordsShortcut);
	    }
	}
	wsEditAutoSave(p_sFieldName);
	l_oIframe.contentWindow.focus();
    }
    return false;
}

function wsEditCSSClass(p_sFieldName,p_sClassName){
    //Wrap a span tag with CSS class around current selection
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	var l_oRange = wsGetRange(p_sFieldName);
	var l_sCurrentText, l_sHtml;
	// get currently selected text
	l_sCurrentText = wsGetHTMLOfSelection(p_sFieldName, l_oRange)
	    // wrap it in a SPAN tag
	    l_sHtml = "<span class=\"" + p_sClassName + "\">" + l_sCurrentText + "</span>";
	var l_oTag = wsGetSelectionParentElement(p_sFieldName);
	if (p_sClassName){
	    if (l_oTag) {
		if (l_oTag.tagName.toLowerCase() != "span"){
		    // insert new text
		    wsEditInsertHTML(p_sFieldName, l_sHtml);
		}
		//Just set the class attribute
		else {
		    l_oTag.setAttribute("className",p_sClassName,0);
		}
	    }
	    else {
		// insert new text
		wsEditInsertHTML(p_sFieldName, l_sHtml);
	    }
	}
	else {
	    //Else remove the span tag
	    if (l_oTag) {
		if (l_oTag.tagName.toLowerCase() == "span"){
		    l_oTag.outerHTML = l_oTag.innerHTML;
		}
	    }
	}
    }
}

function wsEditFormatChange(p_sFieldName, p_sStyle, p_sValue) {
    //
    var l_oRange = wsGetRange(p_sFieldName);
    var l_sCurrentText, l_sHtml, l_sOuterHtml, l_sInnerHtml;
    // get currently selected text
    l_sCurrentText = wsGetHTMLOfSelection(p_sFieldName, l_oRange)
    var l_sStyle;
    switch (p_sStyle.toLowerCase()) {
    case 'fontsize': l_sStyle = "font-size"; break;
    case 'fontfamily': l_sStyle = "font-family"; break;
    case 'color': l_sStyle = "color"; break;
    case 'backgroundcolor': l_sStyle = "background-color"; break;
    }
    var l_oTag = wsGetSelectionParentElement(p_sFieldName);
    if (p_sValue != "") {
	l_sHtml = "<span style=\"" + l_sStyle + ":" + p_sValue + ";\">" + l_sCurrentText + "</span>";
	if (l_oTag) {
	    l_sOuterHtml = wsGetOuterHTML(l_oTag);
	    l_sInnerHtml = wsGetInnerHTML(l_oTag);
	    if (l_sOuterHtml.toLowerCase() == l_sCurrentText.toLowerCase() || l_sInnerHtml.toLowerCase() == l_sCurrentText.toLowerCase()) {
		//Just set the value for this style attribute
		l_oTag.style[p_sStyle] = p_sValue;
	    }
	    else {
		// insert new text
		wsEditInsertHTML(p_sFieldName, l_sHtml);
		l_oTag = wsGetSelectionParentElement(p_sFieldName);
	    }
	    wsEraseTagStyleForChildren(l_oTag, p_sStyle)
	}
	else {
	    // insert new text
	    wsEditInsertHTML(p_sFieldName, l_sHtml);
	    l_oTag = wsGetSelectionParentElement(p_sFieldName);
	    wsEraseTagStyleForChildren(l_oTag, p_sStyle)
	}
    }
    else {
	//Else remove the style setting
	if (l_oTag) {
	    l_sOuterHtml = wsGetOuterHTML(l_oTag);
	    l_sInnerHtml = wsGetInnerHTML(l_oTag);
	    if (l_sOuterHtml.toLowerCase() == l_sCurrentText.toLowerCase() || l_sInnerHtml.toLowerCase() == l_sCurrentText.toLowerCase()) {
		l_oTag.style[p_sStyle] = "";
 	    }
	    wsEraseTagStyleForChildren(l_oTag, p_sStyle)
	}
    }
}

function wsEraseTagStyleForChildren(p_oTag, p_sStyle) {
    //
    var l_iIndex, l_oTag;
    if (p_oTag.hasChildNodes()) {
	for (l_iIndex=0; l_iIndex < p_oTag.childNodes.length; l_iIndex++) {
	    l_oTag = p_oTag.childNodes[l_iIndex];
	    if (l_oTag.nodeType != 3) {
		l_oTag.style[p_sStyle] = "";
// 		l_oTag.style.removeProperty(p_sStyle);
		wsEraseTagStyleForChildren(l_oTag, p_sStyle);
	    }
	}
    }
}

function trim(s) {
  while (s.substring(0,1) == ' ') {
    s = s.substring(1,s.length);
  }
  while (s.substring(s.length-1,s.length) == ' ') {
    s = s.substring(0,s.length-1);
  }
  return s;
}

function wsGetHTMLOfSelection(p_sFieldName, p_oRange) {
    if (document.selection && document.selection.createRange) {
	var l_oDiv = document.createElement('div'), l_sString;
	l_sString = p_oRange.htmlText.replace(/\n/g,'');
//	l_sString = l_sString.replace(/\s+/g,' ');
	return trim(l_sString);
    }
    else if (window.getSelection) {
	var l_oSel = wsGetSelection(p_sFieldName);
	if (l_oSel.rangeCount > 0) {
	    var clonedSelection = p_oRange.cloneContents();
	    var l_oDiv = document.createElement('div');
	    l_oDiv.appendChild(clonedSelection);
	    return l_oDiv.innerHTML;
	}
	else {
	    return '';
	}
    }
    else {
	return '';
    }
}

function wsEditAutoSave(p_sFieldName) {
    //Check if autosave is enabled and act as needed
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe && l_oIframe.contentWindow.document.autosave) {
	wsEditSave(p_sFieldName);}
}

function wsEditSave(p_sFieldName) {
    //Save the content of the iframe inside an hidden field
//     alert('wsEditSave: ' + p_sFieldName);
    if (g_bRTE) {
	var l_oIframe = wsEditGetIframe(p_sFieldName);
	if (l_oIframe) {
	    var l_sMode = l_oIframe.contentWindow.document.editMode;
//     var l_sField = p_sFieldName + "_wsContent";
	    var l_sField = l_oIframe.wsContentField;
	    var l_oField = document.getElementById(l_sField);
	    if (l_oField && l_sMode == "HTML") {
		var l_sHtml = l_oIframe.contentWindow.document.body.innerHTML;
		l_sHtml = wsEditCleanUpHTML(l_sHtml);
		l_sHtml = wsDecodeForumStyle(l_sHtml);
		l_oField.value = l_sHtml;
		l_oIframe.contentWindow.document.body.innerHTML = "";
		l_oIframe.contentWindow.document.body.innerHTML = l_sHtml;
	    }
//     wsSetFocus(p_sFieldName);
	}
    }
}

function wsEditOpen(p_sFieldName, p_bSave) {
    // Start from scratch with empty editor
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	l_oIframe.contentWindow.document.body.innerHTML = "";
	if (p_bSave) {
	    wsEditAutoSave(p_sFieldName);
	}
    }
}

function wsEditMakeLink(p_sFieldName) {
    //Wrap an HTML link around the current selection
    var l_oProtocolField = document.getElementById(p_sFieldName + "_wsEditProtocol");
    var l_oUrlField = document.getElementById(p_sFieldName + "_wsEditUrl");
    if (l_oUrlField.value) {
	var l_sURL = l_oProtocolField.value + l_oUrlField.value;
	wsEditFormat(p_sFieldName,"CreateLink",l_sURL);}
    else {
	alert(g_sAlertEmptyLinks);
    }
    wsSetFocus(p_sFieldName) ;
}

function wsPreserveInternalAnchors(p_sHtml) {
    // 
    var l_sPattern = "(<a\s+[^<>]*\s+href\s*=\s*\"?)http[s]?:\/\/[^#]+\/wsadmin\/[^#]+wsaction=[^#](#[^<>]+>)";
    var l_oRegExp = new RegExp(l_sPattern, "gi");
    var l_iMatch = p_sHtml.search(l_oRegExp);
    if (l_iMatch >= 0) {
	var l_sReplace = "$1$2";
	p_sHtml = p_sHtml.replace(l_oRegExp,l_sReplace);
    }
    return p_sHtml;
}

function wsEditSwapMode(p_sFieldName) {
    //Swap between WYSIWYG mode and HTML mode
    var l_oBtnSwap = document.getElementById(p_sFieldName + "_wsEditSwapView");
    var l_oBtnSubmit = MM_findObj("Submit");
    if (!l_oBtnSubmit) {
	l_oBtnSubmit = MM_findObj("btnSubmit");
    }
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	var l_sEditMode = l_oIframe.contentWindow.document.editMode;
	if (l_sEditMode == "HTML"){ // HTML code view
	    if (g_bIE) {
		var l_sHtml = l_oIframe.contentWindow.document.body.innerHTML;
		// replace absolute references to current page with relative links
		l_sHtml = wsPreserveInternalAnchors(l_sHtml);
		l_oIframe.contentWindow.document.body.innerText = l_sHtml;
	    }
	    else {
		var l_sHtml = document.createTextNode(l_oIframe.contentWindow.document.body.innerHTML);
		l_oIframe.contentWindow.document.body.innerHTML = "";
		l_oIframe.contentWindow.document.body.appendChild(l_sHtml);
	    }
// 	l_oIframe.contentWindow.document.body.style.fontFamily = "monospace";
// 	l_oIframe.contentWindow.document.body.style.fontSize = "10pt";
	    l_oIframe.contentWindow.document.editMode = "Text";
	    if (l_oBtnSwap) {
		l_oBtnSwap.value = g_sModeWYSIWYGgo;
	    }
	    var l_oToolbar = document.getElementById(p_sFieldName + "_toolbar1");
	    if (l_oToolbar) {
		l_oToolbar.className = "wsEditToolbarNone";
	    }
	    l_oToolbar = document.getElementById(p_sFieldName + "_toolbar2");
	    if (l_oToolbar) {
		l_oToolbar.className = "wsEditToolbarNone";
	    }
	    if (l_oBtnSubmit) {
		l_oBtnSubmit.disabled = true;
	    }
	    window.status = g_sModeHTML;
	}
	else { // WYSIWYG view
	    if (g_bIE) {
		var l_sHtml = l_oIframe.contentWindow.document.body.innerText;
		l_oIframe.contentWindow.document.body.innerHTML = l_sHtml;    
	    }
	    else {
		var l_sHtml = l_oIframe.contentWindow.document.body.ownerDocument.createRange();
		l_sHtml.selectNodeContents(l_oIframe.contentWindow.document.body);
		l_oIframe.contentWindow.document.body.innerHTML = l_sHtml.toString();
	    }
// 	l_oIframe.contentWindow.document.body.style.fontFamily = "";
// 	l_oIframe.contentWindow.document.body.style.fontSize = "";
	    l_oIframe.contentWindow.document.editMode = "HTML";
	    if (l_oBtnSwap) {
		l_oBtnSwap.value = g_sModeHTMLgo;
	    }
	    var l_oToolbar = document.getElementById(p_sFieldName + "_toolbar1");
	    if (l_oToolbar) {
		l_oToolbar.className = "toolbar";
	    }
	    l_oToolbar = document.getElementById(p_sFieldName + "_toolbar2");
	    if (l_oToolbar) {
		l_oToolbar.className = "toolbar";
	    }
	    if (l_oBtnSubmit) {
		l_oBtnSubmit.disabled = false;}
	    window.status = g_sModeWYSIWYG;
	}
	wsSetFocus(p_sFieldName) ;
    }
}

function wsGetSelectionParentElement(p_sFieldName) {
    // 
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	// make sure we have proper focus
	l_oIframe.contentWindow.focus();
	var l_oSel = wsGetSelection(p_sFieldName);
	var l_oRange = wsGetRange(p_sFieldName);
	var l_oTag;
	if (g_bIE) {
	    switch (l_oSel.type) {
	    case "Text":
	    case "None":
		// It seems that even for selection of type "None",
		// there _is_ a parent element and it's value is not
		// only correct, but very important to us
		l_oTag = l_oRange.parentElement(); break;
	    case "Control":
		l_oTag = l_oRange.item(0); break;
	    default:
		l_oTag = l_oIframe.contentWindow.document.body; break;
	    }
	    return l_oTag;
	}
	else try {
	    l_oTag = l_oRange.commonAncestorContainer;
	    if (!l_oRange.collapsed && l_oRange.startContainer == l_oRange.endContainer &&
		l_oRange.startOffset - l_oRange.endOffset <= 1 && l_oRange.startContainer.hasChildNodes()) {
		l_oTag = l_oRange.startContainer.childNodes[l_oRange.startOffset];
	    }
	    while (l_oTag.nodeType == 3) {
		l_oTag = l_oTag.parentNode;
	    }
	    return l_oTag;
	}
	catch (e) { return null; }
    }
}

function wsEditInsertLink(p_sFieldName, p_bInsert) {
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	// Disabled in View Source mode
	var l_sEditMode = l_oIframe.contentWindow.document.editMode;
	if (l_sEditMode != "HTML") {return;}
	// Pick up the current selection.
	var l_oSel = wsGetSelection(p_sFieldName);
	var l_oRange = wsGetRange(p_sFieldName);
	var l_sLinkText = '';
	if (g_bIE) {
	    l_sLinkText = l_oRange.htmlText;
	}
	else {
	    l_sLinkText = l_oRange.toString();
	}
	if (l_sLinkText && l_sLinkText.length > 0) {
	    l_sLinkText = wsStripHTML(l_sLinkText);
	}
	if (g_bIE && l_sLinkText == "") {
	    alert(g_sAlertMakeSelectionFirst);
	    return;				
	}
	if (!l_sLinkText || l_sLinkText == "undefined") {
	    l_sLinkText = "";
	}
	var l_oTag;
	l_oTag = wsGetSelectionParentElement(p_sFieldName);
	if (l_oTag && l_oTag.tagName != "A" && l_oTag.parentNode.tagName == "A") {
	    l_oTag = l_oTag.parentNode;
	}
	// Is this aready a link?
	var l_sURL = "", l_sTarget = "", l_bLink = false, l_sOnClick = "";
	if (l_oTag && l_oTag.tagName == "A") { // this is a link
	    if (!p_bInsert) { // If removing the link, then replace all with
		wsSetOuterHTML(l_oTag, l_oTag.innerHTML);
		return;
	    }
	    // possibly changing the link information
	    l_bLink = true; l_sURL = (l_oTag.href) ? l_oTag.href : ""; l_sTarget = (l_oTag.target) ? l_oTag.target : ""; l_sOnClick = (l_oTag.onclick) ? l_oTag.onclick : "";
	}
	//
	document.wsFieldName = p_sFieldName;
	// run the dialog that implements this type of element
	var l_oSiteRoot = MM_findObj(p_sFieldName + "_hiddenSiteRoot");
	var l_sDialogURL = l_oSiteRoot.value + "wsadmin/WebwareEditor/wsDlgLink.asp?editor=" + p_sFieldName + "&url=" + escape(l_sURL) + "&target=" + l_sTarget + "&onclick=" + escape(l_sOnClick);
	var l_sDialogAttr = "scrollbars=yes,resizable=yes,width=550,height=420";
	wsEditorPopupLink(p_sFieldName, l_sDialogURL,'wsDialog',l_sDialogAttr);
	wsSetFormText("0", l_sLinkText);
    }
}

function wsEditCreateLink(p_sFieldName, p_sLinkInfo, p_sURL, p_sBlank, p_sPopup) {
    //
    var l_oIframe = wsEditGetIframe(p_sFieldName), l_sHtml;
    if (l_oIframe) {
	// Disabled in View Source mode
	var l_sEditMode = l_oIframe.contentWindow.document.editMode;
	if (l_sEditMode != "HTML") {return;}
	// Pick up the current selection.
	l_oTag = wsGetSelectionParentElement(p_sFieldName);
	if (l_oTag && l_oTag.tagName != "A" && l_oTag.parentNode.tagName == "A") {
	    l_oTag = l_oTag.parentNode;
	}
	if (l_oTag.tagName == "IMG") {
	    wsEditFormat(p_sFieldName,"CreateLink",p_sURL);
	    wsEditCreateLink(p_sFieldName, p_sLinkInfo, p_sURL);
	    return;
	}
	else {
	    if (l_oTag.tagName == "A") {
		l_sHtml = l_oTag.innerHTML;
		l_sHtml = p_sLinkInfo + l_sHtml + "</a>";
		wsSetOuterHTML(l_oTag, l_sHtml);
	    }
	    else {
		var l_oRange = wsGetRange(p_sFieldName);
		var l_sLinkText = '';
		if (g_bIE) {
		    l_sLinkText = l_oRange.htmlText;
		}
		else {
		    l_sLinkText = l_oRange.toString();
		}
		if (l_sLinkText && l_sLinkText.length > 0) {
		    l_sLinkText = wsStripHTML(l_sLinkText);
		}
		l_sHtml = p_sLinkInfo + l_sLinkText + "</a>";
		wsEditInsertHTML(p_sFieldName, l_sHtml);
	    }
	}	    
	wsEditAutoSave(p_sFieldName);
	wsSetFocus(p_sFieldName) ; 
    }
}

function wsEditSelectedImage(p_sFieldName) {
    // 
    var l_oImg = null, l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	// Disabled in View Source mode
	var l_sEditMode = l_oIframe.contentWindow.document.editMode;
	if (l_sEditMode != "HTML") {return;}
	// Pick up the current selection.
	var l_oSel = wsGetSelection(p_sFieldName);
	if (l_oSel.type != "None") {
// 	    var l_oRange = wsGetRange(p_sFieldName);
	    var l_oTag = wsGetSelectionParentElement(p_sFieldName);
	    if (l_oTag.tagName == "IMG") { 
		l_oImg = l_oTag;
	    }
	}
    }
    return l_oImg;
}

function wsEditSelectedTable(p_sFieldName) {
    // 
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	// Disabled in View Source mode
	var l_sEditMode = l_oIframe.contentWindow.document.editMode;
	if (l_sEditMode != "HTML") {return;}
	// Pick up the current selection.
	var l_oSel = wsGetSelection(p_sFieldName);
//  	var l_oRange = wsGetRange(p_sFieldName);
	var l_oTag = wsGetSelectionParentElement(p_sFieldName);
	if (!l_oTag) {
	    // cursor is not in a table
	    return null;
	}
	while (l_oTag.tagName != "TABLE" && l_oTag.tagName != "HTML") {
	    l_oTag = l_oTag.parentNode;
	}
	if (l_oTag.tagName == "HTML") {
	    // cursor is not in a table
	    return null;
	}
    }
    return l_oTag;
}

function wsAddOrRemoveCol(p_oTable, p_iColIndex, p_sAction, p_bAfter) {
    // add or remove a column
    if (!p_oTable.childNodes.length) {return;}
    var l_iTableCols = p_oTable.rows[ p_oTable.rows.length-1].cells.length;
    for (var i = 0; i < p_oTable.childNodes.length; i++) {
	if (p_oTable.childNodes[i].tagName == "TR") {
	    var l_oRow = p_oTable.childNodes[i];
            if (p_sAction == "add") {
		var l_iWhere = p_bAfter ? p_iColIndex : p_iColIndex-1;
		var l_oCell = l_oRow.insertCell(l_iWhere);
		l_oCell.innerHTML = "&nbsp;";
            }
	    else {
		var l_oCell = l_oRow.childNodes[p_iColIndex];
		if (l_oCell) {		    
		    // don't delete too many cells because or a rowspan setting
		    if (l_oCell.rowSpan > 1) {
			i += (l_oCell.rowSpan - 1);
		    }
		    l_oCell.removeNode(true);
		}
            }
	}
	else {
            // keep looking for a "TR"
            wsAddOrRemoveCol(p_oTable.childNodes[i], p_iColIndex, p_sAction, p_bAfter); 
	}
    }
}

function wsAddOrRemoveRow(p_oTable, p_iRowIndex, p_sAction, p_bAfter) {
    // add or remove the row at the cell index
    if (!p_oTable.childNodes.length) {return;}
    if (p_sAction == "add") {
	var l_iCols = p_oTable.rows[p_oTable.rows.length-1].cells.length;
	var l_iIndex = p_bAfter ? p_iRowIndex : p_iRowIndex-1;
	var l_oRow = p_oTable.insertRow(l_iIndex);
	l_oRow.valign = "top";
	for (var i=0; i<l_iCols; i++) {
	    var l_oCell = l_oRow.insertCell(i);
	    l_oCell.innerHTML = "&nbsp;";
	}
    }
    else {
	if (p_oTable.rows.length > 1) {
	    p_oTable.deleteRow(p_iRowIndex);
	}
    }
}

function wsEditTableRowCol(p_sFieldName, p_sType, p_sAction, p_bAfter) {
    // 
    var l_oTable = wsEditSelectedTable(p_sFieldName);
    if (l_oTable) {
	// we're in a table
	var l_oIframe = wsEditGetIframe(p_sFieldName);
	if (l_oIframe) {
	    // Pick up the current selection.
	    var l_oTag = wsGetSelectionParentElement(p_sFieldName), l_iIndex;
	    if (l_oTag) {
		if (!l_oTag.tagName) { // needed for Gecko
		    l_oTag = l_oTag.parentNode;
		}
		while (l_oTag.tagName.toLowerCase() != p_sType.toLowerCase()) {
		    l_oTag = l_oTag.parentNode;
		}
		if (p_sType.toLowerCase() == "td") {
		    l_iIndex = (p_sAction == "add") ? l_oTag.cellIndex+1 : l_oTag.cellIndex;
		    wsAddOrRemoveCol(l_oTable, l_iIndex,  p_sAction, p_bAfter);
		}
		else {
		    l_iIndex = (p_sAction == "add") ? l_oTag.rowIndex+1 : l_oTag.rowIndex;
		    wsAddOrRemoveRow(l_oTable, l_iIndex,  p_sAction, p_bAfter);
		}
		wsEditAutoSave(p_sFieldName);
		wsSetFocus(p_sFieldName);
	    }
	}
    }
}

function wsEditInsertHTML(p_sFieldName, p_sHTML) {
    //
    if (p_sHTML.length > 0) {
	wsSetFocus(p_sFieldName) ;
	var l_sIframeID = p_sFieldName + "_wsEditIframe";
	var l_oIframe = wsEditGetIframe(p_sFieldName);
	if (l_oIframe) {
	    // Disabled in View Source mode
	    var l_sEditMode = l_oIframe.contentWindow.document.editMode;
	    if (l_sEditMode != "HTML") {return;}
	    // make sure we have proper focus
	    l_oIframe.contentWindow.focus();
	    if (document.all) {
		l_oIframe.contentWindow.focus();
		var l_oRange = wsGetRange(p_sFieldName);
		if (l_oRange.item) {
		    l_oRange.item(0).outerHTML = p_sHTML;
		}
		else {
		    l_oRange.pasteHTML(p_sHTML);
		}
		l_oRange.collapse(false);
		l_oRange.select();
	    }
	    else {
		l_oIframe.contentWindow.document.execCommand('insertHTML', false, p_sHTML);
	    }
	    wsEditAutoSave(p_sFieldName);
	    var l_oContent = l_oIframe.contentWindow;
	    if (l_oContent) { l_oContent.focus(); }
	}
    }
    return false;
}

function wsPageQuery(p_sQuery) {
    if (p_sQuery.length > 1) {
	this.p_sQuery = p_sQuery.substring(1, p_sQuery.length);}
    else {
	this.p_sQuery = null;}
    this.keyValuePairs = new Array();
    if (p_sQuery) {
	for(var i=0; i < this.p_sQuery.split("&").length; i++) {
	    this.keyValuePairs[i] = this.p_sQuery.split("&")[i];
	}
    }
    this.getKeyValuePairs = function() {
	return this.keyValuePairs;}
	this.getValue = function(s) {
	    for(var j=0; j < this.keyValuePairs.length; j++) {
		if(this.keyValuePairs[j].split("=")[0] == s)
		    return this.keyValuePairs[j].split("=")[1];
	    }
	    return false;
	}
	this.getParameters = function() {
	    var l_aArray = new Array(this.getLength());
	    for(var j=0; j < this.keyValuePairs.length; j++) {
		l_aArray[j] = this.keyValuePairs[j].split("=")[0];
	    }
	    return l_aArray;
	}
	this.getLength = function() { return this.keyValuePairs.length; } 
	}

function wsQueryString(p_sKey){
    var l_oPage = new wsPageQuery(window.location.search);
    var l_sValue = l_oPage.getValue(p_sKey);
    if (!l_sValue) {
	return false;
    }
    return unescape(l_sValue); 
}

function wsCancel() {
    window.returnValue = null;
    window.close();
}

function wsBuildTagAttr(sName, sValue) {
    if (!sValue || sValue == "") return "";
    return ' ' + sName + '="' + sValue + '"';
}

function wsFileFromPath(p_sPath) {
    var l_sPath = p_sPath;
    if (p_sPath.lastIndexOf("/") != -1) {
	var l_iStart = p_sPath.lastIndexOf("/") + 1, l_iEnd = p_sPath.length;
	l_sPath = p_sPath.substring(l_iStart,l_iEnd);
    }
    else if (p_sPath.lastIndexOf("\\") != -1) {
	var l_iStart = p_sPath.lastIndexOf("\\") + 1, l_iEnd = p_sPath.length;
	l_sPath = p_sPath.substring(l_iStart,l_iEnd);
    }
    return l_sPath;
}

function wsRaiseButton(e) {
    var el = window.event.srcElement;
    className = el.className;
    if (className == 'wsImg' || className == 'wsImgDn') {
	el.className = 'wsImgUp';
    }
}

function wsNormalButton(e) {
    var el = window.event.srcElement;
    className = el.className;
    if (className == 'wsImgUp' || className == 'wsImgDn') {
	el.className = 'wsImg';
    }
}

function wsLowerButton(e) {
    var el = window.event.srcElement;
    className = el.className;
    if (className == 'wsImg' || className == 'wsImgUp') {
	el.className = 'wsImgDn';
    }
}

function wsEditHover(p_sFieldName,p_bDo) {
    // Handles mouse hovering over toolbar buttons
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	// Disabled in View Source mode
	var l_sEditMode = l_oIframe.contentWindow.document.editMode;
	if (l_sEditMode != "HTML") {return;}
	if (document.all) {
	    var l_oEl = window.event.srcElement;
	    if (l_oEl && !l_oEl.disabled && l_oEl.nodeName == "IMG" && l_oEl.parentNode.className != "wsSep") {
		if (p_bDo) {
		    l_oEl.className = "wsImgUp";
		} else {
		    l_oEl.className = l_oEl.defaultState ? l_oEl.defaultState : "wsImg";
		}
	    }	
	}
    }
}

function wsEditPress(p_sFieldName,p_bDo) {
    // Handles mouse clicks on toolbar buttons
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	// Disabled in View Source mode
	var l_sEditMode = l_oIframe.contentWindow.document.editMode;
	if (l_sEditMode != "HTML") {return;}
	if (document.all) {
	    var l_oEl = window.event.srcElement;
	    if (l_oEl && !l_oEl.disabled && l_oEl.nodeName == "IMG" && l_oEl.parentNode.className != "wsSep") {
		if (p_bDo) {
		    l_oEl.className = "wsImgDn";
		} else {
		    l_oEl.className = l_oEl.className == "wsImgDn" ? "wsImgUp" : l_oEl.defaultState ? l_oEl.defaultState : "wsImg";
		}
	    }
	}
    }
}

function wsSetEditorVisibility(p_sFieldName, p_bVisible) {
    var l_oEditor = document.getElementById(p_sFieldName);
    if (l_oEditor) {
	if (p_bVisible) {
	    l_oEditor.className = "wsEdit";
	}
	else {
	    l_oEditor.className = "wsEditNone";
	}
    }
}

function MM_openBrWindow(theURL,winName,features) { //v2.0
    window.open(theURL,winName,features);
}

function flvFPW1(){//v1.45
// Copyright 2002-2004, Marja Ribbers-de Vroed, Webware Systems (www.webwaresystems.nl/dreamweaver/)
    var v1=arguments,v2=v1[2].split(","),v3=(v1.length>3)?v1[3]:false,v4=(v1.length>4)?parseInt(v1[4]):0,v5=(v1.length>5)?parseInt(v1[5]):0,v6,v7=0,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17;v11=new Array("width,left,"+v4,"height,top,"+v5);for (i=0;i<v11.length;i++){v12=v11[i].split(",");v17=parseInt(v12[2]);if (v17>1||v1[2].indexOf("%")>-1){v13=eval("screen."+v12[0]);for (v6=0;v6<v2.length;v6++){v10=v2[v6].split("=");if (v10[0]==v12[0]){v14=parseInt(v10[1]);if (v10[1].indexOf("%")>-1){v14=(v14/100)*v13;v2[v6]=v12[0]+"="+v14;}}if (v10[0]==v12[1]){v16=parseInt(v10[1]);v15=v6;}}if (v17==2){v16=(v13-v14)/2;v15=v2.length;}else if (v17==3){v16=v13-v14-v16;}v2[v15]=v12[1]+"="+v16;}}document.MM_returnValue=false;v8=v2.join(",");v9=window.open(v1[0],v1[1],v8);if (v9&&v3){v9.focus();}if (v9) {return v9;}else{alert("Het openen van een nieuw window is niet gelukt.\nWaarschijnlijk blokkeert een 'popup blocker'-programma dit nieuwe window.\n\nProbeer het eventueel nog eens met de 'Ctrl'-toets ingedrukt.");}}

function wsPopupLink(){// v1.2
// Copyright 2002, Marja Ribbers (Webware Solutions.nl)
    var v1=arguments,v2=window.open(v1[0],v1[1],v1[2]), v3=(v1.length>3)?v1[3]:false;if (v3){v2.focus();}document.MM_returnValue=false;}

function wsTagTrim(inputString) {
    // Removes leading and trailing spaces from the passed string. Also removes
    // consecutive spaces and replaces it with one space. If something besides
    // a string is passed in (null, custom object, etc.) then return the input.
    if (typeof inputString != "string") { return inputString; }
    var retValue = inputString;
    var ch = retValue.substring(0, 1);
    while (ch == " ") { // Check for spaces at the beginning of the string
	retValue = retValue.substring(1, retValue.length);
	ch = retValue.substring(0, 1);
    }
    ch = retValue.substring(retValue.length-1, retValue.length);
    while (ch == " ") { // Check for spaces at the end of the string
	retValue = retValue.substring(0, retValue.length-1);
	ch = retValue.substring(retValue.length-1, retValue.length);
    }
    while (retValue.indexOf("  ") != -1) { // Note that there are two spaces in the string - look for multiple spaces within the string
	retValue = retValue.substring(0, retValue.indexOf("  ")) + retValue.substring(retValue.indexOf("  ")+1, retValue.length); // Again, there are two spaces in each of the strings
    }
    return retValue; // Return the trimmed string back to the user
} // Ends the "trim" function

function wsProcessCB(p_sID, p_sKeyType, p_sFieldName) {
    if (p_sKeyType == "id") {
	var l_sHtml = "{{cb:id=" + p_sID + "}}";
    }
    else {
	var l_sHtml = "{{cb:name=" + p_sID + "}}";
    }
    wsEditInsertHTML(p_sFieldName, l_sHtml); 
}

function wsSetFocus(p_sFieldName) {
    var l_sIframeID = p_sFieldName + "_wsEditIframe";
    if (document.all) {
	var l_oIframe = window.frames[l_sIframeID];
    }
    else {
	var l_oIframe = document.getElementById(l_sIframeID);
    }
    if (l_oIframe) {
	var l_oContent = l_oIframe.contentWindow;
	if (l_oContent) {
	    l_oContent.focus() ;
	}
    }
}

function wsShowTableBorders(p_sFieldName) {
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	var l_oContent = l_oIframe.contentWindow.document;
	var l_aTables = l_oContent.getElementsByTagName("TABLE");
	var i, j;
	if (l_oContent.ShowBorders) {
	    for (i=0; i<l_aTables.length; i++) { 
		if (l_aTables[i].border == 0) {
		    l_aTables[i].runtimeStyle.borderWidth = "";
		    l_aTables[i].runtimeStyle.borderColor = "";
		    l_aTables[i].runtimeStyle.borderStyle = "";
		    l_aTables[i].runtimeStyle.borderCollapse = "";
		    for (j=0; j<l_aTables[i].getElementsByTagName("TD").length; j++) {
			l_aTables[i].getElementsByTagName("TD")[j].runtimeStyle.borderWidth = "";
			l_aTables[i].getElementsByTagName("TD")[j].runtimeStyle.borderColor = "";
			l_aTables[i].getElementsByTagName("TD")[j].runtimeStyle.borderStyle = "";					
		    }
		} 
	    }		
	}
	else {
	    for (i=0; i<l_aTables.length; i++) { 
		if (l_aTables[i].border == 0) {
		    l_aTables[i].runtimeStyle.borderWidth = 1; 
		    l_aTables[i].runtimeStyle.borderColor = "#BCBCBC"; 
		    l_aTables[i].runtimeStyle.borderStyle = "dotted";
		    l_aTables[i].runtimeStyle.borderCollapse = "separate";
// 		l_aTables[i].runtimeStyle.borderCollapse = "collapse";
		    for (j=0; j<l_aTables[i].getElementsByTagName("TD").length; j++) {
			l_aTables[i].getElementsByTagName("TD")[j].runtimeStyle.border = "#BCBCBC 1 dotted"; 
		    } 
		}
	    }
	}
	l_oContent.ShowBorders = !l_oContent.ShowBorders;
    }
//     wsSetFocus(p_sFieldName);
}	

function wsShowDetails(p_sFieldName) {
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	var l_oContent = l_oIframe.contentWindow.document;
	l_oContent.ShowDetails = !l_oContent.ShowDetails ;
	wsSetFocus(p_sFieldName) ;
    }
}

function wsGetClipboardHTML(p_sFieldName) {
    // temporarily paste cliboard data to hidden DIV
//     var l_sDiv = "divTemp" + p_sFieldName
//     var l_oDiv = document.getElementById(l_sDiv);
//     l_oDiv.innerHTML = "" ;
//     var l_oTextRange = document.body.createTextRange() ;
//     l_oTextRange.moveToElementText(l_oDiv) ;
//     l_oTextRange.execCommand("Paste") ;
//     // return the HTML formatted content of the temporary DIV
//     var l_sClipboardData = l_oDiv.innerHTML ;
//     l_oDiv.innerHTML = "" ;

    var l_sClipboardData = getClipboard();
    return l_sClipboardData ;
}

function getClipboard() {
    if (window.clipboardData) {

	// the IE-manier
	return(window.clipboardData.getData('Text'));

	// waarschijnlijk niet de beste manier om Moz/NS te detecteren;
	// het is mij echter onbekend vanaf welke versie dit precies werkt:
    }
    else if (window.netscape) { 
	try{
	    // dit is belangrijk maar staat nergens duidelijk vermeld:
	    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');

	    // maak een interface naar het clipboard
	    var clip = Components.classes['@mozilla.org/widget/clipboard;1'].createInstance(Components.interfaces.nsIClipboard);
	    if (!clip) return;

	    // maak een transferable
	    var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable);
	    if (!trans) return;

	    // specificeer wat voor soort data we op willen halen; text in dit geval
	    trans.addDataFlavor('text/unicode');

	    // haal de data op
	    clip.getData(trans,clip.kGlobalClipboard);

	    // om de data uit de transferable te halen hebben we 2 nieuwe objecten nodig om het in op te slaan
	    var str = new Object();
	    var len = new Object();

	    // haal de data en datalengte op in de nieuwe objecten; hier vang ik errors op als type-conversion niet lukt
	    try { trans.getTransferData('text/unicode',str,len); }
	    catch(error) { return; }

	    // Als het data object iets bevat converteer het naar een string object

	    if (str) {
		// deze werkte bij mij alleen in NS7
		if (Components.interfaces.nsISupportsWString) str=str.value.QueryInterface(Components.interfaces.nsISupportsWString);
		// en deze alleen in Mozilla 1.2
		else if (Components.interfaces.nsISupportsString) str=str.value.QueryInterface(Components.interfaces.nsISupportsString);
		else str = null;
	    }

	    // haal de text op uit het data segment; de lengte is de helft van de lengte zoals opgehaald uit de transferable
	    if (str) return(str.data.substring(0,len.value / 2));

	}
        catch (e) {
	    alert(g_sErrorNoExecPermission);
	}
    }
    return "";
}

function wsPasteFromWord(p_sFieldName) {
    var l_sHtml = wsGetClipboardHTML(p_sFieldName);
    l_sHtml = wsEditCleanUpMicrosoftGarbage(l_sHtml);
    l_sHtml = wsEditCleanUpTagAttributesMicrosoft(l_sHtml);
    wsEditInsertHTML(p_sFieldName, l_sHtml) ;
    wsEditAutoSave(p_sFieldName);
}

function wsGetSelection(p_sFieldName) {
    // 
    var l_oSel;
    var l_oIframe = wsEditGetIframe(p_sFieldName);
    if (l_oIframe) {
	// make sure we have proper focus
	l_oIframe.contentWindow.focus();
	if (document.all){
	    l_oSel = l_oIframe.contentWindow.document.selection;
	}
	else {
	    l_oSel = l_oIframe.contentWindow.getSelection();
	}
    }
    return l_oSel;    
}

function wsGetRange(p_sFieldName) {
    //function to store range of current selection
    var l_oSel, l_oRange, l_oIframe;
    l_oSel = wsGetSelection(p_sFieldName);
    if (!l_oSel) {
	return null;
    }
    if (document.all){
	return l_oSel.createRange();
// 	var l_sIframeID = p_sFieldName + "_wsEditIframe";
// 	l_oIframe = window.frames[l_sIframeID];
// 	if (l_oIframe) {
// 	    l_oSel = l_oIframe.document.selection;
// 	    if (l_oSel != null) {
// 		l_oRange = l_oSel.createRange();
// 	    }
// 	    l_oRange.select();
// 	}
    }
    else {
	return l_oSel.getRangeAt(l_oSel.rangeCount - 1).cloneRange();
// 	l_oIframe = wsEditGetIframe(p_sFieldName);
// 	if (l_oIframe) {
// 	    l_oSel = l_oIframe.contentWindow.getSelection();
// 	    l_oRange = l_oSel.getRangeAt(l_oSel.rangeCount - 1).cloneRange();
// 	}
    }
    return l_oRange;
}

function wsCloseDialogs() {
    if (dlgInsertSymbol) {try {dlgInsertSymbol.close()} catch(e) {}; dlgInsertSymbol = null;}
    if (dlgInsertTable) {try {dlgInsertTable.close()} catch(e) {}; dlgInsertTable = null;}
    if (dlgInsertLink) {try {dlgInsertLink.close()} catch(e) {}; dlgInsertLink = null;}
    if (dlgInsertImage) {try {dlgInsertImage.close()} catch(e) {}; dlgInsertImage = null;}
    if (dlgInsertSmiley) {try {dlgInsertSmiley.close()} catch(e) {}; dlgInsertSmiley = null;}
    if (dlgInsertUserField) {try {dlgInsertUserField.close()} catch(e) {}; dlgInsertUserField = null;}
    if (dlgInsertConfigVar) {try {dlgInsertConfigVar.close()} catch(e) {}; dlgInsertConfigVar = null;}
    if (dlgInsertCB) {try {dlgInsertCB.close()} catch(e) {}; dlgInsertCB = null;}
    if (dlgFindReplace) {try {dlgFindReplace.close()} catch(e) {}; dlgFindReplace = null;}
    if (dlgSelectColor) {try {dlgSelectColor.close()} catch(e) {}; dlgSelectColor = null;}
    if (dlgPasteWord) {try {dlgPasteWord.close()} catch(e) {}; dlgPasteWord = null;}
}

function wsEditorPopupSymbol(p_sFieldName, p_sURL, p_sName, p_sAttr) {
    // 
    g_sCurrentEditor = p_sFieldName;
    wsGetRange(p_sFieldName);
    dlgInsertSymbol = flvFPW1(p_sURL, p_sName, p_sAttr, 1,2,2); // centered
}

function wsEditorPopupTable(p_sFieldName, p_sURL, p_sName, p_sAttr) {
    // 
    g_sCurrentEditor = p_sFieldName;
    wsGetRange(p_sFieldName);
    dlgInsertTable = flvFPW1(p_sURL, p_sName, p_sAttr, 1,2,2); // centered
}

function wsEditorPopupLink(p_sFieldName, p_sURL, p_sName, p_sAttr) {
    //
    g_sCurrentEditor = p_sFieldName;
    wsGetRange(p_sFieldName);
    dlgInsertLink = flvFPW1(p_sURL, p_sName, p_sAttr, 1,2,2); // centered
}

function wsEditorPopupImage(p_sFieldName, p_sURL, p_sName, p_sAttr) {
    // 
    g_sCurrentEditor = p_sFieldName;
    wsGetRange(p_sFieldName);
    dlgInsertImage = flvFPW1(p_sURL, p_sName, p_sAttr, 1,2,2); // centered
}

function wsEditorPopupSmiley(p_sFieldName, p_sURL, p_sName, p_sAttr) {
    // 
    g_sCurrentEditor = p_sFieldName;
    wsGetRange(p_sFieldName);
    dlgInsertSmiley = flvFPW1(p_sURL, p_sName, p_sAttr, 1,2,2); // centered
}

function wsEditorPopupCB(p_sFieldName, p_sURL, p_sName, p_sAttr) {
    // 
    g_sCurrentEditor = p_sFieldName;
    wsGetRange(p_sFieldName);
    dlgInsertCB = flvFPW1(p_sURL, p_sName, p_sAttr, 1,2,2); // centered
}

function wsEditorPopupColorPalette(p_sFieldName, p_sURL, p_sName, p_sAttr) {
    // 
    g_sCurrentEditor = p_sFieldName;
    wsGetRange(p_sFieldName);
    dlgSelectColor = flvFPW1(p_sURL, p_sName, p_sAttr, 1,2,2); // centered
}

function wsEditorPopupPasteWord(p_sFieldName, p_sURL, p_sName, p_sAttr) {
    // 
    g_sCurrentEditor = p_sFieldName;
    wsGetRange(p_sFieldName);
    dlgPasteWord = flvFPW1(p_sURL, p_sName, p_sAttr, 1,2,2); // centered
}

function wsEditorPopupUserField(p_sFieldName, p_sURL, p_sName, p_sAttr) {
    // 
    g_sCurrentEditor = p_sFieldName;
    wsGetRange(p_sFieldName);
    dlgInsertUserField = flvFPW1(p_sURL, p_sName, p_sAttr, 1,2,2); // centered    
}

function wsEditorPopupConfigVar(p_sFieldName, p_sURL, p_sName, p_sAttr) {
    // 
    g_sCurrentEditor = p_sFieldName;
    wsGetRange(p_sFieldName);
    dlgInsertConfigVar = flvFPW1(p_sURL, p_sName, p_sAttr, 1,2,2); // centered    
}

function wsSetFormText(p_iPopup, p_sContent) {
    //set link text value in dialog windows
    try {
	switch (p_iPopup){
	case "0": dlgInsertLink.wsSetLinkText(p_sContent); break;
	case "1": dlgFindReplace.document.getElementById("searchText").value = p_sContent; break;
	    //default: break;
	}
    }
    catch (e) {
	//may take some time to create dialog window.
	//Keep looping until able to set.
	setTimeout("wsSetFormText('"+p_iPopup+"','" + p_sContent + "');", 10);
    }
}
    
function wsGeckoKeyPress(p_oEvent) {
    // function to add bold, italic, and underline shortcut commands to gecko RTEs
    var l_sRTE = p_oEvent.target.id;
    if (p_oEvent.ctrlKey) {
	var l_sKey = String.fromCharCode(p_oEvent.charCode).toLowerCase();
	var l_sCmd = '';
	switch (l_sKey) {
	case 'b': l_sCmd = "bold"; break;
	case 'i': l_sCmd = "italic"; break;
	case 'u': l_sCmd = "underline"; break;
	}
	if (l_sCmd) {
	    wsEditFormat(l_sRTE, l_sCmd, null);
	    // stop the event bubble
	    p_oEvent.preventDefault();
	    p_oEvent.stopPropagation();
	}
    }
}

function wsStripHTML(p_sString) {
    //strip all html
    var l_sOutput = p_sString.replace(/(<([^>]+)>)/ig,"");
    //replace carriage returns and line feeds
    l_sOutput = l_sOutput.replace(/\r\n/g," ");
    l_sOutput = l_sOutput.replace(/\n/g," ");
    l_sOutput = l_sOutput.replace(/\r/g," ");
    l_sOutput = wsTagTrim(l_sOutput);
    return l_sOutput;
}

function wsGetOuterHTML(p_oTag) {
    // 
    if (p_oTag.outerHTML) {
	return p_oTag.outerHTML;
    }
    else {
	return getOuterHTML(p_oTag);
    }
}

function wsGetInnerHTML(p_oTag) {
    // 
    if (p_oTag.innerHTML) {
	return p_oTag.innerHTML;
    }
    else {
	return getInnerHTML(p_oTag);
    }
}

function getInnerHTML(p_oTag) {
    var str = "";
    for (var i=0; i<p_oTag.childNodes.length; i++)
	str += getOuterHTML(p_oTag.childNodes.item(i));
	    return str;
}

function getOuterHTML(p_oTag) {
    var str = "";
	
    switch (p_oTag.nodeType) {
    case 1: // ELEMENT_NODE
	str += "<" + p_oTag.nodeName;
	for (var i=0; i<p_oTag.attributes.length; i++) {
	    if (p_oTag.attributes.item(i).nodeValue != null) {
		str += " "
		    str += p_oTag.attributes.item(i).nodeName;
		str += "=\"";
		str += p_oTag.attributes.item(i).nodeValue;
		str += "\"";
	    }
	}

	if (p_oTag.childNodes.length == 0 && leafElems[p_oTag.nodeName])
	    str += ">";
	else {
	    str += ">";
	    str += getInnerHTML(p_oTag);
	    str += "<" + p_oTag.nodeName + ">"
		}
	break;
				
    case 3:	//TEXT_NODE
	str += p_oTag.nodeValue;
	break;
			
    case 4: // CDATA_SECTION_NODE
	str += "<![CDATA[" + p_oTag.nodeValue + "]]>";
	break;
					
    case 5: // ENTITY_REFERENCE_NODE
	str += "&" + p_oTag.nodeName + ";"
	    break;

    case 8: // COMMENT_NODE
	str += "<!--" + p_oTag.nodeValue + "-->"
	    break;
    }

    return str;
}

var _leafElems = ["IMG", "HR", "BR", "INPUT"];
var leafElems = {};
for (var i=0; i<_leafElems.length; i++)
    leafElems[_leafElems[i]] = true;

function wsCanHaveChildren(p_oTag) {
    // 
    switch (p_oTag.tagName) {
    case "AREA":
    case "BASE":
    case "BASEFONT":
    case "COL":
    case "FRAME":
    case "HR":
    case "IMG":
    case "BR":
    case "INPUT":
    case "ISINDEX":
    case "LINK":
    case "META":
    case "PARAM":
	return false;
    }
    return true;    
}

function wsSetOuterHTML(p_oTag, p_sHTML) {
    //
    if (p_oTag.outerHTML) {
	p_oTag.outerHTML = p_sHTML;
    }
    else {
    	var l_oRange = p_oTag.ownerDocument.createRange();
	l_oRange.setStartBefore(p_oTag);
	var l_oDF = l_oRange.createContextualFragment(p_sHTML);
	p_oTag.parentNode.replaceChild(l_oDF, p_oTag);
	return p_sHTML;
    }
}

// function wsRTEDesignModeOnGeneral() {
//     // 
//     if (g_bGecko) {
// 	var l_aIframes = document.getElementsByTagName("iframe"), l_sIFrame;
// 	for (var i = 0; i < l_aIframes.length; i++) {
// 	    l_sIFrame = l_aIframes[i].id;
// 	    if (l_sIFrame.indexOf('_wsEditIframe') > 0 && !l_aIframes[i].wsLoaded) {
// 		// editor is not fully loaded yet, try again in a moment
// 		setTimeout("wsIframeDesignModeOn('" + l_sIFrame + "')", 200);
// 	    }
// 	    else {
// 		if (l_aIframes[i].contentDocument) {
// 		    l_aIframes[i].contentDocument.designMode = "on";
// 		}
// 	    }
// 	}
//     }
// }

function wsRTEDesignModeOnGeneral() {
    // 
    if (g_bGecko) {
	var l_aIframes = document.getElementsByTagName("iframe"), l_sIFrame;
	for (var i = 0; i < l_aIframes.length; i++) {
	    l_sIFrame = l_aIframes[i].id;
	    if (l_sIFrame.indexOf('_wsEditIframe') > 0) {
		if (!l_aIframes[i].wsLoaded) {
		    // editor is not fully loaded yet, try again in a moment
		    setTimeout("wsIframeDesignModeOn('" + l_sIFrame + "')", 200);
		}
		else {
		    if (l_aIframes[i].contentDocument) {
			l_aIframes[i].contentDocument.designMode = "on";
		    }
		}
	    }
	}
    }
}

function wsRTEDesignModeOn(p_oTab) {
    // called when switching tabs in tab control:
    // reset designMode for editor on tab to "on", otherwise it is
    // readonly in Gecko browsers
    if (g_bGecko) {
	if (p_oTab) {
	    var l_aIframes = p_oTab.tabPage.getElementsByTagName("iframe"), l_sIFrame;
	}
	else {
	    // sometimes we need to force the designmode to 'on' when we're
	    // not using tabs as well
	    var l_aIframes = document.getElementsByTagName("iframe"), l_sIFrame;
	}
	for (var i = 0; i < l_aIframes.length; i++) {
	    l_sIFrame = l_aIframes[i].id;
	    if (l_sIFrame.indexOf('_wsEditIframe') > 0) {
		if (!l_aIframes[i].wsLoaded) {
		    // editor is not fully loaded yet, try again in a moment
		    setTimeout("wsIframeDesignModeOn('" + l_sIFrame + "')", 200);
		}
		else {
		    if (l_aIframes[i].contentDocument) {
			l_aIframes[i].contentDocument.designMode = "on";
		    }
		}		  
	    }
	}
    }       
}

function wsIframeDesignModeOn(p_sIframe) {
    // 
    try {
	var l_oIframe = document.getElementById(p_sIframe);
	if (l_oIframe) {
	    if (!l_oIframe.wsLoaded) {
		// still not loaded, try again in a moment
		setTimeout("wsIframeDesignModeOn('" + p_sIframe + "')", 200);	
	    }
	    else {
		if (l_oIframe.contentDocument) {
		    l_oIframe.contentDocument.designMode = "on";
		}
	    }
	}
    }
    catch (e) {
    }
}

function wsSaveEditors(p_sEditors) {
    //
    if (p_sEditors.length > 0) {
	var l_aEditors = p_sEditors.split(",");
	for (var l_iIndex = 0; l_iIndex < l_aEditors.length; l_iIndex++) {
	    wsEditSave(l_aEditors[l_iIndex]);
	}
    }
}
function wsEncodeForumStyle(p_sString) {
    // 
    var l_sString = p_sString;
    // remove newlines and carriage returns
    l_sString = l_sString.replace(/\n/gi,"");
    l_sString = l_sString.replace(/\r/gi,"");
    // remove invalid HTML
    l_sString = l_sString.replace(/<p><div/gi,"<div");
    l_sString = l_sString.replace(/<\/div><\/p>/gi,"</div>");
    // encode forum style
    l_sString = l_sString.replace(/<div style=[\'\"]margin\-left\:.*15px;?[\'\"]><strong>quote:<\/strong><hr width=[\'\"]100%[\'\"]>/gi,"[quote]");
    l_sString = l_sString.replace(/<hr width=[\'\"]100%[\'\"]><\/div>/gi,"[/quote]");
    return l_sString;
}

function wsDecodeForumStyle(p_sString) {
    // 
    var l_sString = p_sString;
    // remove newlines and carriage returns
    l_sString = l_sString.replace(/\n/gi,"");
    l_sString = l_sString.replace(/\r/gi,"");
    // remove invalid forum coding
    l_sString = l_sString.replace(/<p>\[quote\]/gi,"[quote]");
    l_sString = l_sString.replace(/\[\/quote\]<\/p>/gi,"[/quote]");
    // decode forum style
    l_sString = l_sString.replace(/\[quote\]/gi,"<div style='margin-left: 15px;'><strong>quote:</strong><hr width='100%'>");
    l_sString = l_sString.replace(/\[\/quote\]/gi,"<hr width='100%'></div>");
    return l_sString;
}

function wsEditCleanUpMicrosoftGarbage(p_sHtml) {
    // Lets try and strip out as much Word garbage as we can
    var l_sHtml = p_sHtml;
    l_sHtml = l_sHtml.replace(/<o:p>\s*<\/o:p>/g,"<br>"); 
    l_sHtml = l_sHtml.replace(/<o:p>.*?<\/o:p>/g,"&nbsp;<br>"); 
   // Remove mso-xxx styles. 
   l_sHtml = l_sHtml.replace(/\s*mso-[^:]+:[^;"]+;?/gi,""); 
    l_sHtml = l_sHtml.replace(/ class=\"?Mso([A-Za-z]+)?\"?/g, "");
   // Remove margin styles - does not affect indented text 
   l_sHtml = l_sHtml.replace(/\s*MARGIN: 0cm 0cm 0pt\s*;/gi,""); 
   l_sHtml = l_sHtml.replace(/\s*MARGIN: 0cm 0cm 0pt\s*"/gi,"\""); 
   l_sHtml = l_sHtml.replace(/\s*TEXT-INDENT: 0cm\s*;/gi,""); 
   l_sHtml = l_sHtml.replace(/\s*TEXT-INDENT: 0cm\s*"/gi,"\""); 
   l_sHtml = l_sHtml.replace(/\s*TEXT-ALIGN: [^\s;]+;?"/gi,"\""); 
   l_sHtml = l_sHtml.replace(/\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi,"\""); 
   l_sHtml = l_sHtml.replace(/\s*FONT-VARIANT: [^\s;]+;?"/gi,"\""); 
   l_sHtml = l_sHtml.replace(/\s*tab-stops:[^;"]*;?/gi,""); 
   l_sHtml = l_sHtml.replace(/\s*tab-stops:[^"]*/gi,""); 
    // Delete class=Normal
    l_sHtml = l_sHtml.replace(/ class=\"?Normal([A-Za-z]+)?\"?/g, "");
//     // Delete Class attributes
//     l_sHtml = l_sHtml.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, '<$1$3');
//     // Delete Style attributes
//     l_sHtml = l_sHtml.replace(/<(\w[^>]*) style='([^']*)'([^>]*)/gi, '<$1$3');
    // Delete Lang attributes
    l_sHtml = l_sHtml.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, '<$1$3');
    // Delete XML elements and declarations
    l_sHtml = l_sHtml.replace(/<\\?\?xml[^>]*>/gi, '');
    // Delete Tags with XML namespace declarations: <o:p></o:p>
    l_sHtml = l_sHtml.replace(/<\/?\w+:[^>]*>/gi, '');
    return l_sHtml;   
}

function wsEditCleanUpTagAttributesMicrosoft(p_sHtml) {
    // Somewhat more rigorous cleaning explicitly for Word cleanup
    // Keep only wanted/valid tag attributes (= valid HTML)
    // For each tag: define which attributes to keep (based on HTML 4.01 Transitional specs)
    // Note: I'm not allowing *all* attributes allowed in the specs, but only a relevant subset for my purpose.
    //       Add any attributes that you need to be allowed.
    var l_aTagsAttr 	= new Array();
    l_aTagsAttr[0] 	= new Array("p|h1|h2|h3|h4|h5|h6|addr|pre",	"align");
    l_aTagsAttr[1] 	= new Array("table",	"align|width|border|bordercolor|cellspacing|cellpadding");
    l_aTagsAttr[2] 	= new Array("tr", 	"align|valign");
    l_aTagsAttr[3] 	= new Array("th|td",	"align|valign|width|rowspan|colspan");
    l_aTagsAttr[4] 	= new Array("a",        "href|name|target|tabindex|accesskey|onfocus|onblur|onclick|onmouseover|onmouseout");
    l_aTagsAttr[5] 	= new Array("img", 	"title|src|alt|longdesc|name|align|height|width|usemap|hspace|vspace|border");
    l_aTagsAttr[6] 	= new Array("hr", 	"align|width");
    l_aTagsAttr[7] 	= new Array("ul|ol|li|span", "");
    l_aTagsAttr[8] 	= new Array("b|strong|i|em", "");
    if (g_bTextFormatting) {
	l_aTagsAttr[9] 	= new Array("font",     "style|size|face|color");
    }
    // now scan HTML and clean up
    for (var i=0; i<l_aTagsAttr.length; i++) {
	var l_sTags = l_aTagsAttr[i][0];
	var l_sAttributesToKeep = l_aTagsAttr[i][1];
	var l_aTags = l_sTags.split("|");
	for (var j=0; j< l_aTags.length; j++) {
	    var l_sTag = l_aTags[j];
	    p_sHtml = wsEditCleanUpAttributes(p_sHtml, l_sTag, l_sAttributesToKeep);
	}
    }
    //Delete all SPAN tags
    p_sHtml = p_sHtml.replace(/<\/?SPAN[^>]*>/gi, '');
    return p_sHtml;
}  

function wsHTMLEncode(p_sString) {
    p_sString = p_sString.replace(/&/g, "&amp;") ;
    p_sString = p_sString.replace(/"/g, "&quot;") ;
    p_sString = p_sString.replace(/</g, "&lt;") ;
    p_sString = p_sString.replace(/>/g, "&gt;") ;
    p_sString = p_sString.replace(/'/g, "&#146;") ;
    return p_sString ;
}

