
// -------------------------------------------------------------------------------------------
//
//
//  PROJECT NAME:	epEditor [Cross browser WYSIWYG editor]
//
//	FILE NAME:		epEditor.js
//
//	DATE:			10/08/06
//
//	VERSION:		1.0.1 [General]
//
//  MODIFIED:		12/09/06	: Class dropdown added - currently IE only
//								: Custon functionality - "Insert box" div wrapper added to heading
//					14/11/06	: Remove link functionality updated and cross browser tested
//					28/11/06	: HTML nesting bugs in remove link functionality resolved
//								: Check for display mode added to submit button
//					29/11/06	: New bug found in link breaking - check needed for Ps nesting in Ps
//					01/03/07	: Link breaking function completely re-written - now uses DOM object manipulation
//					15/03/07	: Link creation and link breaking re-written again to handle nested DOM elements
//								: Clean HTML functions rewritten to handle *all* acceptable HTML elements
//					19/03/07	: Event listeners added to update toolbar buttons with current states
//					03/04/07	: imageClassPrefix value added to deal with image 'align' | 'class' issues
//					20/04/07	: fixImageAttributes method added to strip specified height and width attributes from images
//								  whilst they are still within the actual editor DOM. This resolves an IE bug which returns 0
//								  when accessing an image's width attribute, if previously specified
//					23/04/07	: isInEditor method added to check that a range object is within the editor
//					25/04/07	: Bugs with isInEditor method fixed
//					30/04/07	: Class functionality reworked and made cross borwser compliant
//					20/06/07	: Loading sequence added
//					21/06/07	: Link to css removed from iframe HTML to solve Firefox bug when editor has no content
//					09/07/07	: Toolbar disabled when in source mode
//								: Undo and redo buttons deactivated when stack is empty
//					25/10/07	: Key press listener added to update undo stack on return key press
//					06/11/07	: Fix attributes method now called on paste detection
//					21/08/08	: Editor resizing added - methods adapted from Jonathan Leighton's Textarea Resizer [http://dev.turnipspatch.com/trac/wiki/TextareaResizer]
//					11/09/08	: Browser detection using 'navigator.userAgent' introduced to assist HTML cleaning
//					22/10/08	: 'createImageObj' and 'updateImageObj' functions updated to handle height and width
//					09/01/09	: Custom class array and CSS string moved to external file [epCustomClasses.js]
//
//  AUTHOR:			malcolm elsworth [malcolm@electricputty.co.uk]
//
//  NOTES:			Certain aspects of the epEitor are adapted from widgEditor - created by:
//					Cameron Adams [http://www.themaninblue.com/]
//
//					Universal Paste Detection [UPD]
//  				We initialise a functions which monitors the string length of the content area
//					Changes bigger than 40 chars will invoke the auto clean
//
//
// -------------------------------------------------------------------------------------------






// -------------------------------------------------------------------------------------------
// Init variables
var allInstances = new Array();

var currentInstance;
var currentContainer;
var currentEditor;
var currentSelection;
var currentRange;
var currentRangeValue;
var currentContent;

var currentDOMObj = null;
var currentLinkObj = null;
var currentImageObj = null;

var runMonitor;
var autoCleanActive = true;

var ua = navigator.userAgent.toLowerCase();
var isMoz = ua.indexOf("firefox")!=-1 ? true : false;
var isIE = ua.indexOf("msie")!=-1 ? true : false;
var isSafari = ua.indexOf("safari")!=-1 ? true : false;
var isOpera = ua.indexOf("opera")!=-1 ? true : false;

var toolBarButtons = new Array();








// -------------------------------------------------------------------------------------------
// Config variables
var editorWidth = "99%";
var editorHeight = "250px";
var imgPath = websiteURL + "admin_components/epEditor/images/";



// [-- Developer note --]
// Because of Firefox weirdness we can't link to an external css file when creating the HTML
// for the iFrame, so we'll drop this chunk of CSS in. You can make amendments to the custom
// classes at the bottom of this.
var epEditorStylesheet = "\
	body.epEditorContent {\
		font-family: Trebuchet MS, Verdana, Arial, sans-serif !important;\
		font-size: 0.85em;\
		margin: 0px;\
		padding: 2px;\
		}\
	\
	body.epEditorContent h1,\
	body.epEditorContent h2,\
	body.epEditorContent h3,\
	body.epEditorContent h4,\
	body.epEditorContent h5,\
	body.epEditorContent h6,\
	body.epEditorContent p {\
		margin: 0 0 12px 0;\
		padding: 0;\
		}\
	\
	body.epEditorContent h1 {\
		color: #672726;\
		}\
	\
	body.epEditorContent h2 {\
		color: #863331;\
		}\
	\
	body.epEditorContent h3 {\
		color: #757575;\
		}\
	\
	body.epEditorContent h4 {\
		color: #a2a2a2;\
		}\
	\
	body.epEditorContent p,\
	body.epEditorContent div {\
		line-height: 1.4em !important;\
		}\
	\
	body.epEditorContent img.img_top {\
		display: block;\
		margin-bottom: 6px;\
		}\
	\
	body.epEditorContent img.img_left,\
	body.epEditorContent img.imgPosleft {\
		float: left;\
		margin: 0 6px 6px 0;\
		}\
	\
	body.epEditorContent img.img_right,\
	body.epEditorContent img.imgPosright {\
		float: right;\
		margin: 0 0 6px 6px;\
		}\
	\
	";

epEditorStylesheet = epEditorStylesheet	+ classStyles;


var modifyFormAction = true;
var formID = "frmEpEditor1"
var formControlID = ""

var helpWindowURL = "";
var helpWindowProps = ""

var linkWindowURL = adminURL + "admin/links/link_create.asp"
var linkWindowProps = "width=600, height=400, menubar=0, status=0, toolbar=0, resizable=1, scrollbars=1"
var linkWindowParams;

var altLinkWindowURL = adminURL +  "admin_components/epEditor/epEditorLink.html"
var altLinkWindowProps = "width=400, height=250, menubar=0, status=0, toolbar=0, resizable=1, scrollbars=1"

var imageWindowURL = adminURL +  "admin_components/epEditor/epEditorImage.html"
var imageWindowProps = "width=500, height=450, menubar=0, status=0, toolbar=0, resizable=1, scrollbars=1"
var imageWindowParams;
var imageClassPrefix = "imgPos";


var blockLevelOptions = new Array;
blockLevelOptions[0] = new Array;
blockLevelOptions[0][0] = "<p>";
blockLevelOptions[0][1] = "Normal";

blockLevelOptions[1] = new Array;
blockLevelOptions[1][0] = "<h1>";
blockLevelOptions[1][1] = "Heading 1";

blockLevelOptions[2] = new Array;
blockLevelOptions[2][0] = "<h2>";
blockLevelOptions[2][1] = "Heading 2";

blockLevelOptions[3] = new Array;
blockLevelOptions[3][0] = "<h3>";
blockLevelOptions[3][1] = "Heading 3";

blockLevelOptions[4] = new Array;
blockLevelOptions[4][0] = "<h4>";
blockLevelOptions[4][1] = "Heading 4";

blockLevelOptions[5] = new Array;
blockLevelOptions[5][0] = "<h5>";
blockLevelOptions[5][1] = "Heading 5";

blockLevelOptions[6] = new Array;
blockLevelOptions[6][0] = "<h6>";
blockLevelOptions[6][1] = "Heading 6";


var specialChars = new Array;
specialChars[0] = "&#8211;";
specialChars[1] = "&#8212;";
specialChars[2] = "&#8216;";
specialChars[3] = "&#8217;";
specialChars[4] = "&#8220;";
specialChars[5] = "&#8221;";
specialChars[6] = "&#8364;";
specialChars[7] = "&#8230;";
specialChars[8] = "&pound;";


// -------------------------------------------------------------------------------------------








function epEditor_init() {

	// Variable to count the number of editors on this page
	var ep = 0;

	// Detects if designMode is available (excludes Safari)
	if (typeof(document.designMode) == "string" && (document.all || document.designMode == "off")) {
		var theTextareas = document.getElementsByTagName("textarea");
		for (var i = 0; i < theTextareas.length; i++) {
			var theTextarea = theTextareas[i];
			if (hasClass(theTextarea, "epEditor")) {
				if (theTextarea.id == "") {
					theTextarea.id = theTextarea.name;
				}
				theLoadingDiv = document.createElement("div");
				theLoadingDiv.className = "epLoading";
				theLoadingDiv.id = theTextarea.id + "Loading";
				theLoadingDiv.style.height = (theTextarea.style.height != "") ? theTextarea.style.height : editorHeight;
				theLoadingDiv.style.width = (theTextarea.style.width != "") ? theTextarea.style.width : editorWidth;
				theTextarea.style.display = "none";
				theTextarea.parentNode.insertBefore(theLoadingDiv, theTextarea);

				allInstances[ep] = theTextarea;
				ep = ep + 1;
			}
		}

		// Now that all the editors are in our array loop through it and build each one
		for (var i = 0; i < allInstances.length; i++) {
			setTimeout("new epEditor('" + allInstances[i].id + "')", 500 * (i));
		}
	}
	else return false;

	return true;
};








function epEditor(instance) {

	var self = this;

	this.instanceName = instance

	this.theLoadingDiv = document.getElementById(instance + "Loading");

	this.theTextarea = document.getElementById(instance);
	this.editorHeight = (this.theTextarea.style.height != "") ? this.theTextarea.style.height : editorHeight;
	this.editorWidth = (this.theTextarea.style.width != "") ? this.theTextarea.style.width : editorWidth;
	this.writeHeadings = (hasClass(this.theTextarea, "noHeadings")) ? false : true;
	this.writeClasses = (hasClass(this.theTextarea, "noClasses"))  ? false : true;
	this.writeSymbols = (hasClass(this.theTextarea, "noSymbols")) ? false : true;
	this.writeImage = (hasClass(this.theTextarea, "noImage")) ? false : true;
	if(hasClass(this.theTextarea, "simpleEditor")) {
		this.writeHeadings = false;
		this.writeClasses = false;
		this.writeSymbols = false;
		this.writeImage = false;
		this.writeLink = false;
	}

	// Check to see if we need to use the editor proprietary link window
	if(hasClass(this.theTextarea, "useAltLinkWin")) {
		linkWindowURL = altLinkWindowURL;
		linkWindowProps = altLinkWindowProps;
	}

	this.content = this.theTextarea.value

	this.theContainer = document.createElement("div");
	this.theContainer.editor = this;

	this.theForm = this.theTextarea.parentNode;
	while (this.theForm.nodeName.toLowerCase() != "form") {
		this.theForm = this.theForm.parentNode;
	}

	this.theContainer.id = instance + "epEditorContainer";
	this.theContainer.className = "epEditorContainer";
	this.buildEditor();
	this.theContainer.style.width = this.editorWidth;
	this.theContainer.style.visibility = "hidden";

	this.theTextarea.id += "epEditorTextarea";
	this.theTextarea.name += "epEditorTextarea";

	this.theTextarea.parentNode.removeChild(this.theLoadingDiv)
	this.theTextarea.parentNode.replaceChild(this.theContainer, this.theTextarea);

	this.theIFrame = document.getElementById(instance + "epEditorIFrame");

	this.theInput = document.getElementById(instance);
	this.theInput.epEditorObject = this;

	this.theDisplayMode = "normal";

	this.theHandle = document.getElementById(instance + "epEditorHandle");
	this.theHandle.middle = Math.ceil(findHeight(this.theHandle) / 2);
	this.theHandle.isResizing = false;
	this.theHandle.minHeight = 200;

	this.undoStack = new Array();
	this.redoStack = new Array();
	this.undoCounter = 0;
	this.redoCounter = 0;
	this.deActivateButton("btnUndo");
	this.deActivateButton("btnRedo");

	// Fill editor with old textarea content
	this.writeDocument(this.content);

	// Make editor editable
	this.initEdit();

	// Attach onsubmit to parent form
	if(modifyFormAction) this.modifyFormSubmit();

	return true;
};








epEditor.prototype.modifyFormSubmit = function() {
	var self = this;
	var oldOnsubmit = null;

	// Add onsubmit without overwriting existing function calls
	oldOnsubmit = this.theForm.onsubmit;

	if (typeof this.theForm.onsubmit != "function") {
		this.theForm.onsubmit = function() {
			return self.updateHiddenInput();
		}
	} else {
		this.theForm.onsubmit = function() {
			self.updateHiddenInput();
			return oldOnsubmit();
		}
	}
	return true;
};







epEditor.prototype.buildEditor = function() {
	var instance = this.instanceName;
	var self = this;
	var editorStr = "";
	editorStr += '<div class="clearfix epToolbar" id="' + instance + '_toolbar">';
	if(this.writeHeadings) editorStr += self.buildDropDown("selectHeading", "Select heading size", blockLevelOptions, "setHeadingStyle(\'" + instance + "\');")
	editorStr += self.buildButton("btnUndo","icon_undo.gif", "Undo", "undoLastChange(\'" + instance + "\');", 24, 24);
	editorStr += self.buildButton("btnRedo","icon_redo.gif", "Redo", "redoLastChange(\'" + instance + "\');", 24, 24);
	editorStr += '<img class="epDivider" src="' + imgPath + 'divider.gif" alt="" height="24" width="4" />';
	editorStr += self.buildButton("btnMakeItalic","icon_italic.gif", "Italic", "executeToolBarCommand(\'" + instance + "\', \'Italic\', \'\');", 24, 24);
	editorStr += self.buildButton("btnMakeStrong","icon_bold.gif", "Bold", "executeToolBarCommand(\'" + instance + "\', \'Bold\', \'\');", 24, 24);
	editorStr += self.buildButton("btnInsertUnorderedList","icon_ulist.gif", "Unordered list", "executeToolBarCommand(\'" + instance + "\', \'insertunorderedlist\', \'\');", 24, 24);
	editorStr += self.buildButton("btnInsertOrderedList","icon_olist.gif", "Ordered list", "executeToolBarCommand(\'" + instance + "\', \'insertorderedlist\', \'\');", 24, 24);
	if (this.writeImage) editorStr += self.buildButton("btnInsertImage","icon_image.gif", "Image", "insertImage(\'" + instance + "\');", 24, 24);
	editorStr += self.buildButton("btnInsertLink","icon_link.gif", "Link", "insertLink(\'" + instance + "\');", 24, 24);
	editorStr += self.buildButton("btnRemoveLink","icon_unlink.gif", "Unlink", "removeLink(\'" + instance + "\');", 24, 24);
	editorStr += '<img class="epDivider" src="' + imgPath + 'divider.gif" alt="" height="24" width="4" />';
	if(this.writeSymbols) editorStr += self.buildDropDown("selectSpecialChar", "Select character", specialChars, "insertSpecialCharacter(\'" + instance + "\');")
	if(this.writeClasses) editorStr += self.buildDropDown("selectClass", "Select class", classNames, "setClassAttribute(\'" + instance + "\');")
	if(helpWindowURL.length) editorStr += buildButton(instance, "btnLaunchHelp","icon_help.gif", "Help", "launchHelp();", 24, 24);
	editorStr += '</div>';
	editorStr += '<iframe class="epEditorContent" id="' + instance + 'epEditorIFrame" width="100%" height="' + this.editorHeight + '" scrolling="auto"></iframe>';
	editorStr += '<div class="clearfix">';
	editorStr += '<input type="hidden" name="' + instance + formControlID + '" id="' + instance + formControlID + '" value="" />';
	editorStr += self.buildButton("btnSourceMode","icon_html.gif", "Switch to HTML mode", "toggleMode(\'" + instance + "\');", 37, 16);
	//editorStr += '<input type="text" id="' + instance + '_test" name="' + instance + '_test" value="" />';
	editorStr += '<div id="' + instance + 'epEditorHandle" class="resizer"></div>';
	editorStr += '</div>';

	this.theContainer.innerHTML = editorStr;
	return true;
};


epEditor.prototype.buildButton = function(id, image, title, onclickAction, width, height) {
	buttonStr = '<img id="' + this.instanceName + "_" + id + '" class="btn" src="' + imgPath + image + '" width="' + width + '" height="' + height + '" title="' + title + '" alt="' + title + '" onclick="' + onclickAction + '" onmouseover="setButtonState(\'' + this.instanceName + '\', this, \'over\');" onmouseout="setButtonState(\'' + this.instanceName + '\', this, \'out\');" onmousedown="setButtonState(\'' + this.instanceName + '\', this, \'down\');" onmouseup="setButtonState(\'' + this.instanceName + '\', this, \'up\');" />';
	return buttonStr;
};


epEditor.prototype.buildDropDown = function(selectName, selectLabel, arrayName, onChangeAction) {
	var classDDStr = "";
	if (arrayName.length != 0) {
		classDDStr += '<select id="' + this.instanceName + "_" + selectName +'" onchange="' + onChangeAction + '">';
		classDDStr += '<option value="">' + selectLabel + '</option>';
		for (var c = 0; c < arrayName.length; c++) {
			if(isArray(arrayName[c])) {
				classDDStr += '<option value="' + arrayName[c][0] + '">' + arrayName[c][1] + '</option>';
			} else {
				classDDStr += '<option value="' + arrayName[c] + '">' + arrayName[c] + '</option>';
			}
		}
		classDDStr += '</select>';
		classDDStr += '<img class="epDivider" src="' + imgPath + 'divider.gif" alt="" height="24" width="4" />';
	}
	return classDDStr;
};


epEditor.prototype.deActivateButton = function(theButtonName) {
	var theButton = document.getElementById(this.instanceName + "_" + theButtonName);
	if (theButton.src.indexOf("_dis.gif") == -1) {
		theButton.src = theButton.src.replace(".gif", "_dis.gif");
		theButton.className = "btnDis";
		theButton.oldonclick = theButton.onclick;
		theButton.onclick = "";
		theButton.oldonmouseover = theButton.onmouseover;
		theButton.onmouseover = "";
		theButton.oldonmouseout = theButton.onmouseout;
		theButton.onmouseout = "";
		theButton.oldonmousedown = theButton.onmousedown;
		theButton.onmousedown = "";
		theButton.oldonmouseup = theButton.onmouseup;
		theButton.onmouseup = "";
	}
	return true;
};


epEditor.prototype.activateButton = function(theButtonName) {
	var theButton = document.getElementById(this.instanceName + "_" + theButtonName);
	if (theButton.src.indexOf("_dis.gif") != -1) {
		theButton.src = theButton.src.replace(new RegExp("_dis\\b"), "");
		theButton.className = "btn";
		theButton.onclick = theButton.oldonclick;
		theButton.onmouseover = theButton.oldonmouseover;
		theButton.onmouseout = theButton.oldonmouseout;
		theButton.onmousedown = theButton.oldonmousedown;
		theButton.onmouseup = theButton.oldonmouseup;
	}
	return true;
};








epEditor.prototype.writeDocument = function(editorContent) {

	// HTML template into which the HTML Editor content is inserted
	var documentTemplate = "\
		<html>\
			<head>\
				<style>\
					INSERT:STYLESHEET:END\
				</style>\
			</head>\
			<body class=\"epEditorContent\" bgcolor=\"#ffffff\">\
				INSERT:CONTENT:END\
			</body>\
		</html>\
	";

	// Insert dynamic variables/content into document
	documentTemplate = documentTemplate.replace(/INSERT:STYLESHEET:END/, epEditorStylesheet);
	editorContent = editorContent.replace("<![CDATA[", "");
	editorContent = editorContent.replace("]]>", "");
	documentTemplate = documentTemplate.replace(/INSERT:CONTENT:END/, editorContent);

	this.theIFrame.contentWindow.document.open();
	this.theIFrame.contentWindow.document.write(documentTemplate);
	this.theIFrame.contentWindow.document.close();

	return true;
};








epEditor.prototype.initEdit = function() {

	var self = this;

	try {
		this.theIFrame.contentWindow.document.designMode = "on";
	}
	catch (e) {
		setTimeout(function(){self.initEdit()}, 250);
	}

	this.theContainer.style.visibility = "visible";

	// Add event capturing - Mozilla stylee
	if (typeof document.addEventListener == "function") {
		this.theIFrame.contentWindow.document.addEventListener("mouseup", function(){checkToolbarState(self); return true;}, false);
		this.theIFrame.contentWindow.document.addEventListener("keyup", function(){checkToolbarState(self); return true;}, false);
		this.theIFrame.contentWindow.document.addEventListener("keydown", function(e){self.monitorKeyPress(e); return true;}, false);
	}
	// or in an IE fashion
	else {
		this.theIFrame.contentWindow.document.attachEvent("onmouseup", function(){checkToolbarState(self); return true;});
		this.theIFrame.contentWindow.document.attachEvent("onkeyup", function(){checkToolbarState(self); return true;});
		this.theIFrame.contentWindow.document.attachEvent("onkeydown", function(e){self.monitorKeyPress(e); return true;}, false);
	}
	// Add the mouse down event to the handle
	this.theHandle.onmousedown = function(e) { self.activateHandle(e); };

	// Initialize the UPD function - this will check the current content length every quarter second
	setTimeout(function(){self.initUPD()}, 250);

	return true;
};








//  --------------------------------------------------------------
//  Initiate Universal Paste Detection [UPD] - see notes above
epEditor.prototype.initUPD = function() {

	var self = this;
	var editorObject = this.theIFrame.contentWindow.document.body;
	var instance = this.instanceName;

	// Make sure the editor object has loaded correctly
	if(typeof editorObject == "object") {
		this.currentContentLength = getCurrentEditorContent(instance).length;
		this.runMonitor = setInterval(function(){self.monitorContentLength()}, 250);
	} else {
		setTimeout(function(){self.initUPD()}, 250);
	}
};







epEditor.prototype.monitorContentLength = function() {

	var self = this;
	var instance = this.instanceName;

	var tempCurrentContent = getCurrentEditorContent(instance);
	var tempCurrentContentLength = tempCurrentContent.length;
	var tempContentDifference = tempCurrentContentLength - this.currentContentLength;

	if (tempContentDifference > 40) {
		if (autoCleanActive == true) {

			// Stop the UPD for this instance
			clearInterval(this.runMonitor);

			// Clean the editor content
			fixImageAttributes(getCurrentEditorObject(instance));
			setCurrentEditorContent(instance, cleanHTML(getCurrentEditorContent(instance)));

			// Restart the UPD after a short break
			setTimeout(function(){self.initUPD()}, 250);
		}
	}
	this.currentContentLength = tempCurrentContentLength;
};

function restartAutoClean() {
	autoCleanActive = true;
};







epEditor.prototype.activateHandle = function(e) {
	var self = this;
	this.theHandle.isResizing = true;
	this.theHandle.onmousedown = null;
	this.theHandle.onmouseup = function(e) { self.deActivateHandle(e); };
	window.document.onmouseup = function(e) { self.deActivateHandle(e); };
	window.document.onmousemove = function(e) { self.resizeEditor(e); }
};







epEditor.prototype.deActivateHandle = function(e) {
	var self = this;
	this.theHandle.isResizing = false;
	this.theHandle.onmouseup = null;
	this.theHandle.onmousedown = function(e) { self.activateHandle(e); };
	window.document.onmousemove = null;
	window.document.onmouseup = null;
};







epEditor.prototype.resizeEditor = function(e) {
	var self = this;
	if (!e) var e = window.event;
	e.cancelBubble = true;
	var selection = document.selection;
	if (selection)
		selection.clear();

	if (this.theHandle.isResizing) {
		var newHeight = parseInt(findHeight(this.theIFrame, true)) + pageY(e) - findPosY(this.theHandle) - this.theHandle.middle;
		if (newHeight < this.theHandle.minHeight) {
			self.deActivateHandle(e);
		} else {
			this.theIFrame.style.height = newHeight + 'px';
		}
	}
};








function checkToolbarState(theEpEditor, resubmit) {
	if (!resubmit) {
		// Allow browser to update selection before using the selection
		setTimeout(function(){checkToolbarState(theEpEditor, true); return true;}, 500);
	}
	var theParentNode = null;
	var theLevel = 0;
	var instance = theEpEditor.instanceName;

	// Turn off all the buttons and reset all dropdowns
	var currentContainer = document.getElementById(instance + "epEditorContainer");
	var buttons = currentContainer.getElementsByTagName("img");
	var dropdowns = currentContainer.getElementsByTagName("select");
	for (var i = 0; i < buttons.length; i++) {
		buttons[i].className = buttons[i].className.replace(new RegExp(" over\\b"), "");
		buttons[i].className = buttons[i].className.replace(new RegExp(" down\\b"), "");
	}
	for (var i = 0; i < dropdowns.length; i++) {
		dropdowns[i].value = "";
	}
	if(document.all) {
		currentRange = getCurrentRange(instance);
		try {
			theParentNode = currentRange.parentElement();
		}
		catch(e) {
			return false;
		}
	} else {
		try {
			currentSelection = getCurrentSelection(instance);
			currentRange = currentSelection.getRangeAt(0);
			theParentNode = currentRange.commonAncestorContainer;
		}
		catch(e){
			return false;
		}
	}
	while (theParentNode.nodeType == 3) {
		theParentNode = theParentNode.parentNode;
	}
	while (theParentNode.nodeName.toLowerCase() != "body") {
		if (theParentNode.className != "") {
			setDropDownValue(instance, "selectClass", theParentNode.className);
		}
		switch (theParentNode.nodeName.toLowerCase()) {
			case "a":
				setButtonState(instance, "btnInsertLink", "down");
				break;

			case "em":
				setButtonState(instance, "btnMakeItalic", "down");
				break;

			case "li":
				break;

			case "ol":
				setButtonState(instance, "btnInsertOrderedList", "down");
				setButtonState(instance, "btnInsertUnorderedList", "up");
				break;

			case "span":
				if (theParentNode.getAttribute("style") == "font-weight: bold;") {
					setButtonState(instance, "btnMakeStrong", "down");
				}
				else if (theParentNode.getAttribute("style") == "font-style: italic;") {
					setButtonState(instance, "btnMakeItalic", "down");
				}
				else if (theParentNode.getAttribute("style") == "font-weight: bold; font-style: italic;") {
					setButtonState(instance, "btnMakeStrong", "down");
					setButtonState(instance, "btnMakeItalic", "down");
				}
				else if (theParentNode.getAttribute("style") == "font-style: italic; font-weight: bold;") {
					setButtonState(instance, "btnMakeStrong", "down");
					setButtonState(instance, "btnMakeItalic", "down");
				}
				break;

			case "strong":
				setButtonState(instance, "btnMakeStrong", "down");
				break;

			case "ul":
				setButtonState(instance, "btnInsertOrderedList", "up");
				setButtonState(instance, "btnInsertUnorderedList", "down");
				break;

			default:
				if(theParentNode.nodeName.toLowerCase().indexOf("h") != -1) {
					setDropDownValue(instance, "selectHeading", "<" + theParentNode.nodeName.toLowerCase() + ">");
				}
				break;
		}
		theParentNode = theParentNode.parentNode;
		theLevel++;
	}
	return true;
};








epEditor.prototype.monitorKeyPress = function(e) {
	var self = this;
	var theEvent = null;
	currentContent = getCurrentEditorContent(this.instanceName);
	if (e) { theEvent = e;
	} else { theEvent = event; }
	// If the return key has been pressed
	if (theEvent.keyCode == 13) {

		// If this is Firefox call the CheckMozParagraphs function
		if(isMoz) self.checkMozParagraphs();

		// Update the undo stack
		updateUndoStack(this.instanceName, currentContent);
	}
};







epEditor.prototype.checkMozParagraphs = function() {
	// Work in progress
};








function setHeadingStyle(instance) {
	var theEditor = document.getElementById(instance).epEditorObject;

	// Make sure we are not in HTML mode
	if(theEditor.theDisplayMode == "normal") {

		// Return the value of the selected heading
		var selectedOption = document.getElementById(instance + "_selectHeading").selectedIndex;

		// Switch *off* the auto clean
		autoCleanActive = false;

		// Ignore the first value, this is always a label
		if (selectedOption != 0) {
			var headingStyle = document.getElementById(instance + "_selectHeading").options[selectedOption].value;
			executeToolBarCommand(instance, "formatblock", headingStyle);
			document.getElementById(instance + "_selectHeading").selectedIndex = 0;
		}

		// Switch *on* the auto clean
		setTimeout("restartAutoClean();", 100);
	}
	return true;
};








function insertSpecialCharacter(instance) {
	var theEditor = document.getElementById(instance).epEditorObject;

	// Make sure we are not in HTML mode
	if(theEditor.theDisplayMode == "normal") {

		// Store the current content for the undo stack
		currentContent = getCurrentEditorContent(instance);
		currentRange = getCurrentRange(instance);
		currentInstance = instance;

		if (isInEditor(currentRange)) {

			// Return the value of the selected special character
			var selectedOption = document.getElementById(instance + "_selectSpecialChar").selectedIndex;

			// Ignore the first value, this is always a label
			if (selectedOption != 0) {
				var specialChar = document.getElementById(instance + "_selectSpecialChar").options[selectedOption].value;
				insertHTML(specialChar);
			}

			// Update the undoStack
			updateUndoStack(instance, currentContent);
		}
	}

	document.getElementById(instance + "_selectSpecialChar").selectedIndex = 0;
	return true;
};








function setClassAttribute(instance) {
	var theEditor = document.getElementById(instance).epEditorObject;

	// Make sure we are not in HTML mode
	if(theEditor.theDisplayMode == "normal") {

		// Store the current content for the undo stack
		currentContent = getCurrentEditorContent(instance);

		// Return the value of the selected class
		var selectedOption = document.getElementById(instance + "_selectClass").selectedIndex;

		// Switch *off* the auto clean
		autoCleanActive = false;

		// Ignore the first value, this is always a label
		if (selectedOption != 0) {

			var selectedClass = document.getElementById(instance + "_selectClass").options[selectedOption].value;
			currentRange = getCurrentRange(instance);
			currentRangeValue = getRangeValue(currentRange);

			if(currentRangeValue != "" && isInEditor(currentRange)) {
				rangeParent = getRangeParent(currentRange);

				if(rangeParent.nodeName.toLowerCase() == "body") {
					var editorObj = getCurrentEditorObject(instance);
					editorObj.innerHTML = '<p class="' + selectedClass + '">' + currentContent + '</p>';
				} else {
					rangeParent.removeAttribute('class');
					rangeParent.removeAttribute('className');
					rangeParent.removeAttribute('style');
					if (selectedClass != "None") rangeParent.className = selectedClass;
				}
			}
		}

		// Switch *on* the auto clean
		setTimeout("restartAutoClean();", 100);

		// Update the undoStack
		updateUndoStack(instance, currentContent);
	}
	return true;
};








function executeToolBarCommand(instance, command, option) {
	var theEditor = document.getElementById(instance).epEditorObject;

	// Make sure we are not in HTML mode
	if(theEditor.theDisplayMode == "normal") {

		// Store the current content for the undo stack
		currentContent = getCurrentEditorContent(instance);
		currentEditor = document.getElementById(instance + "epEditorIFrame").contentWindow;

		try {
			currentEditor.focus();
			currentEditor.document.execCommand(command, false, option);
			currentEditor.focus();
		}
		catch (e) { }

		// Update the undoStack
		updateUndoStack(instance, currentContent);
	}
	return true;
};








function insertImage(instance) {

	var iSrc;
	var iAlt;
	var iClass;
	var launchWin = false;
	var theEditor = document.getElementById(instance).epEditorObject;

	// Make sure we are not in HTML mode
	if(theEditor.theDisplayMode == "normal") {

		currentRange = getCurrentRange(instance);
		currentRangeValue = getRangeValue(currentRange);
		currentInstance = instance;

		if(document.all) {
			if(currentSelection.type.toLowerCase() == "control") {
				currentDOMObj = currentRange.item(0);
			} else {
				currentDOMObj = null;
			}
		} else {
			if (typeof currentRange == "object") {
				currentDOMObj = getRangeParent(currentRange);
			}
		}

		if((currentDOMObj != null) && (currentDOMObj.nodeName.toLowerCase() == "img")) {
			currentImageObj = currentDOMObj;
			iSrc = currentImageObj.src;
			iAlt = currentImageObj.alt;
			iClass = currentImageObj.className.replace(imageClassPrefix, "");
			imageWindowParams = "?iSrc=" + encodeURLText(iSrc) + "&iAlt=" + encodeURLText(iAlt) + "&iClass=" + encodeURLText(iClass);
			launchWin = true;
		} else {
			launchWin = isInEditor(currentRange);
			imageWindowParams = "?iSrc=null&iAlt=null&iClass=null";
		}

		if(launchWin) {
			var imageWindow = window.open(imageWindowURL + imageWindowParams, "imageManager", imageWindowProps);
			if (imageWindow.blur) imageWindow.focus();
		}
		currentDOMObj = null;
	}
};








function createImageObj(imageSrc, imageAlt, imageClass, imageWidth, imageHeight) {

	var imageTag = "";

	imageTag += '<img src="' + imageSrc + '" alt="' + imageAlt + '"';
	if(imageClass.length > 0) imageTag += ' class="' + imageClassPrefix + imageClass + '"';
	if(imageWidth.length > 0) imageTag += ' width="' + imageWidth + '"';
	if(imageHeight.length > 0) imageTag += ' height="' + imageHeight + '"';
	imageTag += ' />';

	insertHTML(imageTag);
};








function updateImageObj(imageSrc, imageAlt, imageClass, imageWidth, imageHeight) {

	// Switch *off* the auto clean
	autoCleanActive = false;

	// Store the current content for the undo stack
	currentContent = getCurrentEditorContent(currentInstance);

	currentImageObj.src = imageSrc;
	currentImageObj.alt = imageAlt;

	if (imageClass.length > 0) {
		currentImageObj.className = imageClassPrefix + imageClass;
	} else {
		currentImageObj.removeAttribute('className');
		currentImageObj.removeAttribute('class');
	}

	if (imageWidth.length > 0) {
		currentImageObj.width = imageWidth;
	} else {
		currentImageObj.removeAttribute('width');
	}

	if (imageHeight.length > 0) {
		currentImageObj.height = imageHeight;
	} else {
		currentImageObj.removeAttribute('height');
	}

	currentImageObj = null;

	// Switch *on* the auto clean
	setTimeout("restartAutoClean();", 100);

	// Update the undoStack
	updateUndoStack(currentInstance, currentContent);
};








function insertLink(instance) {

	var lHref;
	var lTarget;
	var lRel;
	var theEditor = document.getElementById(instance).epEditorObject;

	// Make sure we are not in HTML mode
	if(theEditor.theDisplayMode == "normal") {

		currentRange = getCurrentRange(instance);
		currentRangeValue = getRangeValue(currentRange);
		currentInstance = instance;

		if (currentRangeValue != "") {

			// Reset the object holders
			currentLinkObj = null;
			currentDOMObj = null;

			rangeParent = getRangeParent(currentRange);
			var strToMatch = removeAllFormatting(currentRangeValue.toString());

			if(rangeParent.nodeName.toLowerCase() == "a") {
				lHref = rangeParent.href;
				lTarget = rangeParent.target;
				lRel = rangeParent.rel;
				currentLinkObj = rangeParent;
			} else {
				returnDOMObj(rangeParent, "a", strToMatch, 1);

				// Just in case a block level element got nested within the link
				// go up one level and try again, if this fails - give up
				if(currentDOMObj == null) {
					rangeGrandParent = rangeParent.parentNode;
					if(rangeGrandParent.nodeName.toLowerCase() == "a") {
						lHref = rangeGrandParent.href;
						lTarget = rangeGrandParent.target;
						lRel = rangeGrandParent.rel;
						currentLinkObj = rangeGrandParent;
					}
				}

				if(currentDOMObj != null) {
					lHref = currentDOMObj.href;
					lTarget = currentDOMObj.target;
					lRel = currentDOMObj.rel;
					currentLinkObj = currentDOMObj;
				}
			}

			if(currentLinkObj != null) {
				linkWindowParams = "?lHref=" + encodeURLText(lHref) + "&lTarget=" + encodeURLText(lTarget) + "&lRel=" + encodeURLText(lRel) + "&srcField=" + instance + "&insertLinkInto=editor";
			}
			else {
				linkWindowParams = "?lHref=null&lTarget=null&lRel=null&srcField=" + instance + "&insertLinkInto=editor";
			}

			var linkWindow = window.open(linkWindowURL + linkWindowParams, "linkManager", linkWindowProps);
			if (linkWindow.blur) linkWindow.focus();
		}
	}
};








function removeLink(instance) {
	var theEditor = document.getElementById(instance).epEditorObject;

	// Make sure we are not in HTML mode
	if(theEditor.theDisplayMode == "normal") {

		// Store the current content for the undo stack
		currentContent = getCurrentEditorContent(instance);
		currentInstance = instance;

		currentRange = getCurrentRange(instance);
		currentRangeValue = getRangeValue(currentRange);

		if (currentRangeValue != "") {

			// Reset the object holders
			currentLinkObj = null;
			currentDOMObj = null;

			rangeParent = getRangeParent(currentRange);
			var strToMatch = removeAllFormatting(currentRangeValue.toString());

			if(rangeParent.nodeName.toLowerCase() == "a") {
				currentDOMObj = rangeParent;
			} else {
				returnDOMObj(rangeParent, "a", strToMatch, 1);

				// Just in case a block level element got nested within the link
				// go up one level and try again, if this fails - give up
				if(currentDOMObj == null) {
					rangeGrandParent = rangeParent.parentNode;
					if(rangeGrandParent.nodeName.toLowerCase() == "a") {
						currentDOMObj = rangeGrandParent;
					}
				}
			}

			// If we have a currentLinkObj, get rid of it
			if(currentDOMObj != null) {
				currentLinkObj = currentDOMObj;

				if(currentLinkObj.childNodes.length > 1) {
					replaceNodeWithChildren(currentLinkObj);
				} else {
					currentLinkObj.parentNode.replaceChild(currentLinkObj.childNodes[0], currentLinkObj);
				}
			}

			// Reset the object holders
			currentLinkObj = null;
			currentDOMObj = null;

			// Update the undoStack
			updateUndoStack(instance, currentContent);
		}
	}
};








function updateLinkObj(linkURL, linkTarget) {

	// Switch *off* the auto clean
	autoCleanActive = false;

	// Store the current content for the undo stack
	currentContent = getCurrentEditorContent(currentInstance);

	currentLinkObj.href = linkURL;

	if(linkTarget == "_blank") {
		currentLinkObj.target = linkTarget;
	} else {
		currentLinkObj.removeAttribute("target");
	}
	currentLinkObj = null;

	// Switch *on* the auto clean
	setTimeout("restartAutoClean();", 100);

	// Update the undoStack
	updateUndoStack(currentInstance, currentContent);
};








function createLinkObj(linkURL, linkTarget) {

	// Switch *off* the auto clean
	autoCleanActive = false;

	// Store the current content for the undo stack
	currentContent = getCurrentEditorContent(currentInstance);

	// Store the selected text, minus any formatting, so we can find the new link object later
	var linkTextToMatch = removeAllFormatting(currentRangeValue.toString());

	// Create the link object
	currentEditor = document.getElementById(currentInstance + "epEditorIFrame").contentWindow;
	currentEditor.focus();
	currentEditor.document.execCommand('CreateLink', false, linkURL);

	// If the link target is set, we need to add this attribute to the link object we have just created
	if(linkTarget == "_blank") {

		// Reset the currentDOMObj variable
		currentDOMObj = null;

		// Retrieve the new link object
		rangeParent = getRangeParent(currentRange);

		// Search the DOM for our new link
		if(rangeParent.nodeName.toLowerCase() == "a") {
			currentDOMObj = rangeParent;
		} else {
			returnDOMObj(rangeParent, "a", linkTextToMatch, 1);
		}

		// If we have found it, update the target attribute
		if(currentDOMObj != null) {
			currentDOMObj.target = linkTarget;
		}
	}

	// Switch *on* the auto clean
	setTimeout("restartAutoClean();", 100);

	// Update the undoStack
	updateUndoStack(currentInstance, currentContent);
};








function returnDOMObj(rParentObject, rNodename, rInnerHTML, rDepth) {
	var loopChar = LoopChar[rDepth - 1];
	for (loopChar=0; loopChar<rParentObject.childNodes.length; loopChar++) {
		var currentNode = rParentObject.childNodes[loopChar];
		var currentNodeName = currentNode.nodeName.toLowerCase();
		if(currentNodeName == rNodename) {
			if(rInnerHTML.indexOf(removeAllFormatting(currentNode.innerHTML)) != -1) {
				currentDOMObj = currentNode;
				return;
			}
		}
		if (currentNode.childNodes.length > 0) {
			returnDOMObj(currentNode, rNodename, rInnerHTML, rDepth + 1);
		}
	}
};








function insertHTML(html) {

	// Switch *off* the auto clean
	autoCleanActive = false;

	// Store the current content for the undo stack
	currentContent = getCurrentEditorContent(currentInstance);

	currentEditor = document.getElementById(currentInstance + "epEditorIFrame").contentWindow;
	currentEditor.focus();

	if (document.all) {
		currentRange.pasteHTML(html);
		currentRange.collapse(false);
		currentRange.select();
	} else {
		currentEditor.document.execCommand('insertHTML', false, html);
	}

	// Switch *on* the auto clean
	setTimeout("restartAutoClean();", 100);

	// Update the undoStack
	updateUndoStack(currentInstance, currentContent);
};








function toggleMode(instance) {

	var theEditor = document.getElementById(instance).epEditorObject;

	// Get the current content in the editor
	var currentContent = getCurrentEditorContent(instance);

	// Define the hidden field object for this editor instance
	var hiddenField = document.getElementById(instance + formControlID);

	// Define the toolbar for this instance of the editor
	var theToolbar = document.getElementById(instance + "_toolbar");

	// Update the hidden field with the current content
	updateHiddenField(hiddenField,currentContent);

	// If we are switching to HTML view
	if(theEditor.theDisplayMode == "normal") {

		// Switch *off* the auto clean
		autoCleanActive = false;

		if (isIE) {
			var HTMLsource = lowerCaseAndAttributeQuote(hiddenField.value);
			frames[instance + "epEditorIFrame"].document.body.innerText = HTMLsource;
		} else {
			var editorContent = document.getElementById(instance + "epEditorIFrame").contentWindow.document;
			var currentDOMObj = editorContent.createTextNode(currentContent);
			editorContent.body.innerHTML = "";
			editorContent.body.appendChild(currentDOMObj);
		}

		disableToolbar(theToolbar);
		theEditor.theDisplayMode = "html";
		document.getElementById(instance + "_btnSourceMode").src = imgPath + "icon_editor.gif";
		document.getElementById(instance + "_btnSourceMode").alt = "Switch to editor mode";
		document.getElementById(instance + "_btnSourceMode").title = "Switch to editor mode";
	} else {

		if (isIE) {
			var output = escape(frames[instance + "epEditorIFrame"].document.body.innerText);
			output = output.replace("%3CP%3E%0D%0A%3CHR%3E", "%3CHR%3E");
			output = output.replace("%3CHR%3E%0D%0A%3C/P%3E", "%3CHR%3E");
			frames[instance + "epEditorIFrame"].document.body.innerHTML = unescape(output);
		} else {
			var editorContent = document.getElementById(instance + "epEditorIFrame").contentWindow.document;
			var htmlSrc = editorContent.body.ownerDocument.createRange();
			htmlSrc.selectNodeContents(editorContent.body);
			editorContent.body.innerHTML = htmlSrc.toString();
		}

		enableToolbar(theToolbar);
		theEditor.theDisplayMode = "normal";
		document.getElementById(instance + "_btnSourceMode").src = imgPath + "icon_html.gif";
		document.getElementById(instance + "_btnSourceMode").alt = "Switch to HTML mode";
		document.getElementById(instance + "_btnSourceMode").title = "Switch to HTML mode";

		// Switch *on* the auto clean
		setTimeout("restartAutoClean();", 100);
	}
	return;
};









function disableToolbar(theToolbar) {
	for (var i=0; i<theToolbar.childNodes.length; i++) {
		var theChild = theToolbar.childNodes[i];
		var theReplacement;
		if (theChild.nodeName.toLowerCase() == "select") {
			theChild.disabled = "disabled";
		} else {
			if (theChild.nodeName.toLowerCase() == "img" && theChild.className.indexOf("btn") != -1) {
				toolBarButtons.push(theChild);
				theReplacement = document.createElement("img")
				if (theChild.src.indexOf("_dis") != -1) {
					theReplacement.src = theChild.src;
				} else {
					theReplacement.src = theChild.src.replace(".gif", "_dis.gif");
				}
				theReplacement.className = "btnDis";
				theToolbar.replaceChild(theReplacement, theChild);
			}
		}
	}
};









function enableToolbar(theToolbar) {
	var theIndex = 0;
	for (var i=0; i<theToolbar.childNodes.length; i++) {
		var theChild = theToolbar.childNodes[i];
		if (theChild.nodeName.toLowerCase() == "select") {
			theChild.disabled = "";
		} else {
			if (theChild.nodeName.toLowerCase() == "img" && theChild.className.indexOf("btn") != -1) {
				theToolbar.replaceChild(toolBarButtons[theIndex], theChild);
				theIndex = theIndex + 1;
			}
		}
	}
	toolBarButtons = new Array();
};








function getCurrentEditorContent(instance) {
	return getCurrentEditorObject(instance).innerHTML;
};

function getCurrentEditorObject(instance) {
	return document.getElementById(instance + "epEditorIFrame").contentWindow.document.body;
};








function setCurrentEditorContent(instance, newContent) {
	document.getElementById(instance + "epEditorIFrame").contentWindow.document.body.innerHTML = newContent;

	// Define the hidden field object for this editor instance
	var hiddenField = document.getElementById(instance + formControlID);

	// Update the hidden field with the current content
	updateHiddenField(hiddenField,newContent);

	return true;
};








function getCurrentSelection(instance) {
	var thisSelection = "";
	try {
		if (document.all) {
			currentEditor = frames[instance + "epEditorIFrame"];
			currentEditor.focus();
			thisSelection = currentEditor.document.selection;
		} else {
			currentEditor = document.getElementById(instance + "epEditorIFrame").contentWindow;
			currentEditor.focus();
			thisSelection = currentEditor.getSelection();
		}
	}
	catch(e) { }
	return thisSelection;
};








function getCurrentRange(instance) {
	currentContent = getCurrentEditorContent(instance);
	var thisRange = "";
	currentSelection = getCurrentSelection(instance);
	try {
		if (document.all) {
			if (currentSelection != null) {
				thisRange = currentSelection.createRange();
			}
		} else {
			thisRange = currentSelection.getRangeAt(currentSelection.rangeCount - 1);
		}
	}
	catch(e) { }
	return thisRange;
};








function getRangeValue(rangeObj) {
	var thisRangeValue = ""
	var start = false;
	if (rangeObj) {
		if (document.all) {
			if (currentSelection.type.toLowerCase() != "control") thisRangeValue = rangeObj.htmlText;
		} else {
			thisRangeParent = GetMozRangeParentElement(rangeObj);
			for (var nc = 0; nc < thisRangeParent.childNodes.length; nc++) {

				if (thisRangeParent.childNodes[nc] == rangeObj.startContainer) {
					start = true;
				}

				if (start == true) {
					thisRangeValue += thisRangeParent.childNodes[nc];
				}

				if (thisRangeParent.childNodes[nc] == rangeObj.endContainer) {
					start = false;
				}
			}
			thisRangeValue = rangeObj;
		}
	}
	return thisRangeValue;
};








function getRangeParent(rangeObj) {
	var thisRangeParent;
	if(document.all) {
		thisRangeParent = currentRange.parentElement();
	} else {
		thisRangeParent = GetMozRangeParentElement(currentRange);
	}
	return thisRangeParent;
};








function isInEditor(rangeObj) {
	if(typeof rangeObj != "object") {
		return false;
	} else {
		var parentObj = getRangeParent(rangeObj);
		while (parentObj.nodeName.toLowerCase() != "body") {
			parentObj = parentObj.parentNode;
		}
		if(parentObj.className == "epEditorContent") {
			return true;
		} else {
			return false;
		}
	}
};








function GetMozRangeParentElement(rangeObj) {

	var so = rangeObj.startOffset;
	var eo = rangeObj.endOffset;
	var sc = rangeObj.startContainer;
	var ec = rangeObj.endContainer;

	if(so==eo && sc==ec) {

		if(sc.nodeType==3)
			return sc.parentNode;

		return sc;
	}

	if(eo-so==1 && sc==ec)
		return sc.childNodes[so];

	// we get down here if our selection spans more than one element
	var arr1=[];
	for(var snode=sc; snode!=null; snode=snode.parentNode)
			arr1[arr1.length] = snode;

	arr1.reverse();

	var arr2=[];
	for(var enode=ec; enode!=null; enode=enode.parentNode)
			arr2[arr2.length]=enode;

	arr2.reverse();

	var pn = null;
	var len = Math.min(arr1.length, arr2.length);

	for(var i=0;i<len;i++) {

		if(arr1[i]==arr2[i])
			pn=arr1[i];

		else
			break;
	}
	if(pn.nodeType==3)
			pn=pn.parentNode;

	return pn;
};








function updateHiddenField(hiddenField,currentContent) {
	hiddenField.value = currentContent;
	return true;
};








function updateEditorDisplay(instance) {
	if(document.all) {
		frames[instance + "epEditorIFrame"].document.body.innerHTML = getCurrentEditorContent(instance);
	} else {
		document.getElementById(instance + "epEditorIFrame").contentWindow.document.body.innerHTML = getCurrentEditorContent(instance);
	}
	return;
};








function saveCurrentEditorContent(instance) {
	runSaveSequence(instance)
	document.getElementById(formID).submit();
	return true;
};








epEditor.prototype.updateHiddenInput = function() {
	runSaveSequence(this.instanceName)
	return true;
};








function runSaveSequence(instance) {
	var theEditor = document.getElementById(instance).epEditorObject;

	// If we are source mode switch to normal before we save the content
	if(theEditor.theDisplayMode == "html") toggleMode(instance);

	// Due to general IE wierdness when parses the DOM of a object made from the editor innerHTML
	// we now parse it directly in the editor object - this way we are dealing with the actual objects and not copies
	if(document.all) {
		fixImageAttributes(getCurrentEditorObject(instance));
	}

	// Collect the current content from the editor
	var finalContent = getCurrentEditorContent(instance);

	// Clean the current content
	finalContent = cleanHTML(finalContent);

	// Define the hidden field object for this editor instance
	var hiddenField = document.getElementById(instance + formControlID);

	// Update the hidden field with the cleaned final content
	updateHiddenField(hiddenField,finalContent);

};








function launchHelp() {
	window.open(helpWindowURL, 'help window', helpWindowProps);
	return false;
};








function setButtonState(instance, button, state) {
	var buttonObj;
	if(typeof button == "object") {
		buttonObj = button;
	} else {
		buttonObj = document.getElementById(instance + "_" + button);
	}
	switch (state) {
		case "over":
			buttonObj.className = buttonObj.className += " over";
			break;
		case "out":
			buttonObj.className = buttonObj.className.replace(new RegExp(" over\\b"), "");
			break;
		case "down":
			buttonObj.className = buttonObj.className += " down";
			break;
		case "up":
			buttonObj.className = buttonObj.className.replace(new RegExp(" down\\b"), "");
			break;
	}
	return true;
};


function setDropDownValue(instance, dID, dValue) {
	var theSelect = document.getElementById(instance + "_" + dID);

	if (theSelect != null){
		theSelect.value = "";
		theSelect.value = dValue;
	}
	return true;
};








// FUNCTION TYPE: Builds undo stack
function updateUndoStack(instance, HTMLstring) {
	var theEditor = document.getElementById(instance + "epEditorContainer").editor;
	theEditor.redoStack.length = 0;
	theEditor.redoCounter = 0;

	if (theEditor.undoCounter == 9) {
		for (var u=0; u<9; u++) {
			theEditor.undoStack[u] = theEditor.undoStack[u+1];
		}
		theEditor.undoStack[9] = HTMLstring;
	} else {
		theEditor.undoStack[theEditor.undoCounter] = HTMLstring;
		theEditor.undoCounter = theEditor.undoCounter + 1;
	}
	theEditor.deActivateButton("btnRedo");
	theEditor.activateButton("btnUndo");
	//document.getElementById(instance + "_test").value = "UNDO: " + theEditor.undoCounter + " - REDO: " + theEditor.redoCounter;
	return true;
};

function undoLastChange(instance) {
	var theEditor = document.getElementById(instance + "epEditorContainer").editor;
	if (theEditor.undoCounter > 0) {

		theEditor.redoStack[theEditor.redoCounter] = getCurrentEditorContent(instance);
		theEditor.redoCounter = theEditor.redoCounter + 1;

		if (theEditor.undoCounter == 9) {
			var activeItem = theEditor.undoCounter;
		} else {
			var activeItem = theEditor.undoCounter-1;
		}

		setCurrentEditorContent(instance, theEditor.undoStack[activeItem]);
		theEditor.undoStack.length = theEditor.undoStack.length - 1;
		theEditor.undoCounter = theEditor.undoCounter - 1;
	}
	theEditor.activateButton("btnRedo");
	if (theEditor.undoCounter == 0) {
		theEditor.deActivateButton("btnUndo");
	}
	//document.getElementById(instance + "_test").value = "UNDO: " + theEditor.undoCounter + " - REDO: " + theEditor.redoCounter;
	return true;
};

function redoLastChange(instance) {
	var theEditor = document.getElementById(instance + "epEditorContainer").editor;
	if (theEditor.redoCounter > 0) {

		theEditor.undoStack[theEditor.undoCounter] = getCurrentEditorContent(instance);
		theEditor.undoCounter = theEditor.undoCounter + 1;

		if (theEditor.redoCounter == 9) {
			var activeItem = theEditor.redoCounter;
		} else {
			var activeItem = theEditor.redoCounter-1;
		}

		setCurrentEditorContent(instance, theEditor.redoStack[activeItem]);
		theEditor.redoStack.length = theEditor.redoStack.length - 1;
		theEditor.redoCounter = theEditor.redoCounter - 1;
	}
	if (theEditor.undoCounter > 0) {
		theEditor.activateButton("btnUndo");
	}
	if (theEditor.redoCounter == 0) {
		theEditor.deActivateButton("btnRedo");
	}
	//document.getElementById(instance + "_test").value = "UNDO: " + theEditor.undoCounter + " - REDO: " + theEditor.redoCounter;
	return true;
};








// Activate the on load event
addLoadEvent(epEditor_init);


