/*
	CLASS INTERFACES:


	run()

	wysiwygInit()

	wysiwygEditor(replacedTextareaID)
	wysiwygEditor.cleanPaste()
	wysiwygEditor.cleanSource()
	wysiwygEditor.convertSPANs(theSwitch)
	wysiwygEditor.detectPaste(e)
	wysiwygEditor.initEdit()
	wysiwygEditor.insertNewParagraph()
	wysiwygEditor.modifyFormSubmit()
	wysiwygEditor.refreshDisplay()
	wysiwygEditor.switchMode()
	wysiwygEditor.updatewysiwygInput()
	wysiwygEditor.writeDocument()

	wysiwygToolbar()
	wysiwygToolbar.addButton(theID, theClass, theLabel, theAction)
	wysiwygToolbar.addSeperator(theID, theClass)
	wysiwygToolbar.addSelect(theID, theClass, theContentArray, theAction)
	wysiwygToolbar.disable()
	wysiwygToolbar.enable()
	wysiwygToolbar.setState(theState, theStatus)

	wysiwygToolbarAction()

	wysiwygToolbarCheckState(thewysiwygEditor, resubmit)

	wysiwygToolbarMouseover()

	acceptableChildren(theNode)

	changeNodeType(theNode, nodeType)

	replaceNodeWithChildren()

	String.addClass(theClass)
	String.classExists(theClass)
	String.isAcceptedElementName()
	String.isInlineName()
	String.removeClass(theClass)
	String.reverse()
	String.validTags()


WYSIWYG main container:
<div id="ORIG_IDWysiwygContainer" class="wysiwygContainer">

	Toolbar:
	<ul id="ORIG_IDWysiwygToolbar" class="wysiwygToolbar">
	
		Toolbar seperator pattern (one for every seperator):
		<li id="SEPERATOR_ID" class="wysiwygSeperator">
		
			Script anchor:
			<span></span>
		
		End toolbar seperator pattern:
		</li>

		Toolbar button pattern (one for every button):
		<li id="BTN_ID" class="wysiwygEditButton">

			Script anchor:
			<a></a>

		End toolbar button pattern:
		</li>

		Global formatting select:
		<li class="wysiwygEditSelect">

			<select></select>
			
		End global formatting select:
		</li>
	
	End toolbar:
	</ul>
	
	HTML manipulation area:
	<iframe id="ORIG_IDWysiwygIframe" class="wysiwygIframe">
	
	End HTML manipulation area:
	</iframe>
	
	HTML source area:
	<textarea id="ORIG_IDWysiwgTextarea" class="wysiwygEditor">
	
	End HTML source area:
	</textarea>
	
End WYSIWYG main container
</div>
*/

/* CONFIGURATION VARS */

/* Location of stylesheet file for editor content */
var wysiwygStylesheet = "wysiwygContent.css";

/* Items to appear in toolbar. */
var wysiwygToolbarItems = new Array();

wysiwygToolbarItems.push("tb_start");
wysiwygToolbarItems.push("tb_font_bold");
wysiwygToolbarItems.push("tb_font_italic");
wysiwygToolbarItems.push("tb_font_underline");
wysiwygToolbarItems.push("tb_seperator");
wysiwygToolbarItems.push("tb_font_blockformat");
//wysiwygToolbarItems.push("tb_font_forecolor");
wysiwygToolbarItems.push("tb_seperator");
wysiwygToolbarItems.push("tb_editor_undo");
wysiwygToolbarItems.push("tb_editor_redo");
wysiwygToolbarItems.push("tb_seperator");
wysiwygToolbarItems.push("tb_editor_htmlsource");

/* Options on block format select element. Consists of string pairs (option value, option label) */
var wysiwygBlockFormatOptions = new Array();

wysiwygBlockFormatOptions.push("", "- Select formatting -");
wysiwygBlockFormatOptions.push("<p>", "Normal");
wysiwygBlockFormatOptions.push("<h1>", "Heading 1");
wysiwygBlockFormatOptions.push("<h2>", "Heading 2");
wysiwygBlockFormatOptions.push("<h3>", "Heading 3");
wysiwygBlockFormatOptions.push("<h4>", "Heading 4");
wysiwygBlockFormatOptions.push("<h5>", "Heading 5");
wysiwygBlockFormatOptions.push("<h6>", "Heading 6");
wysiwygBlockFormatOptions.push("<pre>", "Preformatted");
wysiwygBlockFormatOptions.push("<address>", "Address");
/*not supported by browser:
wysiwygBlockFormatOptions.push("<code>", "Code");
wysiwygBlockFormatOptions.push("<blockquote>", "Quote");*/


/* Options on forecolor select element. */
//var wysiwygForeColorOptions = new Array();

//wysiwygForeColorOptions.push("", "- Select color -");
//wysiwygForeColorOptions.push("#ff0000","Red");
//wysiwygForeColorOptions.push("#800000","Dark Red");
//wysiwygForeColorOptions.push("#ffff00","Yellow");
//wysiwygForeColorOptions.push("#c0c000","Dark Yellow");
//wysiwygForeColorOptions.push("#0000ff","Blue");
//wysiwygForeColorOptions.push("#000080","Dark Blue");
//wysiwygForeColorOptions.push("#00ff00","Green");
//wysiwygForeColorOptions.push("#008000","Dark Green");
//wysiwygForeColorOptions.push("#ff8000","Orange");
//wysiwygForeColorOptions.push("#c0c0c0","Gray");
//wysiwygForeColorOptions.push("#808080","Dark Gray");
//wysiwygForeColorOptions.push("#000000","Black");

/* If wysiwygInsertParagraphs = true, when content is submitted paragraphs will be
** inserted around text without a parent element. Mozilla does not
** automatically do this, so if this is set to false you will end up with some
** plain text blocks. Uses a double <br /> as a paragraph marker.
*/

var wysiwygInsertParagraphs = true;

/* If wysiwygAutoClean = true, when content is pasted into the WYSIWYG view, it
** will automatically be stripped of Microsoft junk. If wysiwygAutoClean = false,
** the user will be asked whether or not they wish to clean the content.
*/

var wysiwygAutoClean = false;

var wysiwygDebug = false;

//var wysiwygPopupsDir = "popups/";

/* END CONFIGURATION VARS */

/* INLINE STYLES */

var wysiwygStyles = new Array();

wysiwygStyles[0] = new Array();
	wysiwygStyles[0]["name"] = "Bold";
	wysiwygStyles[0]["tag"] = "b";
	wysiwygStyles[0]["css"] = "font-weight: bold";
wysiwygStyles[1] = new Array();
	wysiwygStyles[1]["name"] = "Italic";
	wysiwygStyles[1]["tag"] = "i";
	wysiwygStyles[1]["css"] = "font-style: italic";
wysiwygStyles[2] = new Array();
	wysiwygStyles[2]["name"] = "Underline";
	wysiwygStyles[2]["tag"] = "u";
	wysiwygStyles[2]["css"] = "text-decoration: underline";

/*var tmpISarr;
for (var tmpISindex = 0; tmpISindex < wysiwygForeColorOptions.length; tmpISindex += 2) {
	if (wysiwygForeColorOptions[tmpISindex] != "") {
		tmpISarr = new Array();
		tmpISarr["name"] = wysiwygForeColorOptions[tmpISindex + 1];
		tmpISarr["tag"] = "font color=\"" + wysiwygForeColorOptions[tmpISindex] + "\"";
		tmpISarr["css"] = "color: " + wysiwygForeColorOptions[tmpISindex];
		wysiwygStyles.push(tmpISarr);
	}
}*/

/* END STYLE VARS */






run();




function run()
{
	var oldOnload = window.onload;

	if (typeof(window.onload) != "function")
	{
		window.onload = wysiwygInit;
	}
	else
	{
		window.onload = function()
		{
			oldOnload();
			wysiwygInit();
		}
	}
}




function wysiwygInit() {
	/* Detects if designMode is available, and also if browser is IE or Mozilla (not 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 (theTextarea.className.classExists("wysiwygEditor")) {
				//alert(theTextarea.className);
				if (theTextarea.id == "") {
					theTextarea.id = theTextarea.name;
				}
				
				setTimeout("new wysiwygEditor('" + theTextarea.id + "')", (500 * (i)));
			}
		}
	}
	else
	{
		return false;
	}
	
	return true;
}




function wysiwygEditor(replacedTextareaID)
{
	var self = this;
	
	this.theTextarea = document.getElementById(replacedTextareaID);
	this.theContainer = document.createElement("div");
	this.theIframe = document.createElement("iframe");
	this.theInput = document.createElement("input");
	this.theExtraInput = document.createElement("input");
	this.IE = false;
	this.locked = true;
	this.pasteCache = "";
	this.wysiwyg = true;
	
	if (document.all)
	{
		this.IE = true;
		//alert("You must be running Mozilla FireFox to use the WYSIWYG editor capability.");
		//return false;
	}
	
	if (this.theTextarea.id == null)
	{
		this.theTextarea.id = this.theTextarea.name;
	}
	
	this.theTextarea.style.visibility = "hidden";

	/* Modify DOM objects for editor */
	this.theContainer.id = this.theTextarea.id + "wysiwygContainer";
	this.theContainer.className = "wysiwygContainer";
	
	this.theIframe.id = this.theTextarea.id + "wysiwygIframe";
	this.theIframe.className = "wysiwygIframe";
	
	this.theInput.type = "hidden";
	this.theInput.id = this.theTextarea.id;
	this.theInput.name = this.theTextarea.name;
	this.theInput.value = this.theTextarea.value;

	this.theToolbar = new wysiwygToolbar(this);
	
	/* An extra input to determine if the submitted data is from the normal textarea or from the wysiwygEditor */
	this.theExtraInput.type = "hidden";	
	this.theExtraInput.id = this.theTextarea.id + "wysiwygEditor";
	this.theExtraInput.name = this.theTextarea.name + "wysiwygEditor";
	this.theExtraInput.value = "true";
	
	this.theTextarea.id += "wysiwygTextarea";
	this.theTextarea.name += "wysiwygTextarea";
	
	this.theContainer.appendChild(this.theToolbar.theList);
	this.theContainer.appendChild(this.theIframe);
	this.theContainer.appendChild(this.theInput);
	this.theContainer.appendChild(this.theExtraInput);
	this.theContainer.style.visibility = "hidden";

	this.theInput.wysiwygEditorObject = this;
	
	this.theTextarea.parentNode.replaceChild(this.theContainer, this.theTextarea);

	/* Fill editor with old textarea content */
	this.writeDocument(this.theInput.value);
	
	/* Make editor editable */
	this.initEdit();
	
	/* Attach onsubmit to parent form */
	this.modifyFormSubmit();
	
	return true;
}




/* Clean pasted content */
wysiwygEditor.prototype.cleanPaste = function()
{
	if (wysiwygAutoClean || confirm("Do you wish to clean the HTML source of the content you just pasted?"))
	{
		var matchedHead = "";
		var matchedTail = "";
		if (this.IE) {
			var newContent = this.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML;
		} else {
			var newContent = this.theIframe.contentDocument.getElementsByTagName("body")[0].innerHTML;
		}
		var newContentStart = 0;
		var newContentFinish = 0;
		var newSnippet = "";
		var tempNode = document.createElement("div");

		/* Find start of both strings that matches */
		for (newContentStart = 0; newContent.charAt(newContentStart) == this.pasteCache.charAt(newContentStart); newContentStart++)
		{
			matchedHead += this.pasteCache.charAt(newContentStart);
		}
		
		/* If newContentStart is inside a HTML tag, move to opening brace of tag */
		for (var i = newContentStart; i >= 0; i--)
		{
			if (this.pasteCache.charAt(i) == "<")
			{
				newContentStart = i;
				matchedHead = this.pasteCache.substring(0, newContentStart);
				
				break;
			}
			else if(this.pasteCache.charAt(i) == ">")
			{
				break;
			}
		}

		newContent = newContent.reverse();
		this.pasteCache = this.pasteCache.reverse();

		/* Find end of both strings that matches */
		for (newContentFinish = 0; newContent.charAt(newContentFinish) == this.pasteCache.charAt(newContentFinish); newContentFinish++)
		{
			matchedTail += this.pasteCache.charAt(newContentFinish);
		}

		/* If newContentFinish is inside a HTML tag, move to closing brace of tag */
		for (var i = newContentFinish; i >= 0; i--)
		{
			if (this.pasteCache.charAt(i) == ">")
			{
				newContentFinish = i;
				matchedTail = this.pasteCache.substring(0, newContentFinish);
				
				break;
			}
			else if(this.pasteCache.charAt(i) == "<")
			{
				break;
			}
		}

		matchedTail = matchedTail.reverse();

		/* If there's no difference in pasted content */
		if (newContentStart == newContent.length - newContentFinish)
		{
			return false;
		}

		newContent = newContent.reverse();
		newSnippet = newContent.substring(newContentStart, newContent.length - newContentFinish);
		newSnippet = newSnippet.validTags();

		/* Replace opening bold tags with strong */
		newSnippet = newSnippet.replace(/<b(\s+|>)/g, "<strong$1");
		/* Replace closing bold tags with closing strong */
		newSnippet = newSnippet.replace(/<\/b(\s+|>)/g, "</strong$1");

		/* Replace italic tags with em */
		newSnippet = newSnippet.replace(/<i(\s+|>)/g, "<em$1");
		/* Replace closing italic tags with closing em */
		newSnippet = newSnippet.replace(/<\/i(\s+|>)/g, "</em$1");

		/* Strip out unaccepted attributes */
		newSnippet = newSnippet.replace(/<[^>]*>/g, function(match)
			{
				match = match.replace(/ ([^=]+)="[^"]*"/g, function(match2, attributeName)
					{
						if (attributeName == "alt" || attributeName == "href" || attributeName == "src" || attributeName == "title")
						{
							return match2;
						}

						return "";
					});

				return match;
			}
			);

		tempNode.innerHTML = newSnippet;

		acceptableChildren(tempNode);
		
		this.theInput.value = matchedHead + tempNode.innerHTML + matchedTail;

		/* Final cleanout for MS Word cruft */
		this.theInput.value = this.theInput.value.replace(/<\?xml[^>]*>/g, "");
		this.theInput.value = this.theInput.value.replace(/<[^ >]+:[^>]*>/g, "");
		this.theInput.value = this.theInput.value.replace(/<\/[^ >]+:[^>]*>/g, "");

		this.refreshDisplay();
		
		/* Convert semantics to spans in Mozilla */
		if (!this.IE)
		{
			this.convertSPANs();
		}
	}
	
	return true;
}




/* Clean the HTML code of the content area */
wysiwygEditor.prototype.cleanSource = function()
{
	var theHTML = "";
	
	if (this.wysiwyg)
	{
		if (this.IE) {
			theHTML = this.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML;
		} else {
			theHTML = this.theIframe.contentDocument.getElementsByTagName("body")[0].innerHTML;
		}
	}
	else
	{
		theHTML = this.theTextarea.value;
	}

	theHTML = theHTML.validTags();
	
	/* Remove leading and trailing whitespace */
	theHTML = theHTML.replace(/^\s+/, "");
	theHTML = theHTML.replace(/\s+$/, "");
	
	/* Remove style attribute inside any tag */
	theHTML = theHTML.replace(/ style="[^"]*"/g, "");

	/* Replace improper BRs */
	theHTML = theHTML.replace(/<br>/g, "<br />");
	
	/* Remove BRs right before the end of blocks */
	theHTML = theHTML.replace(/<br \/>\s*<\/(h1|h2|h3|h4|h5|h6|li|p)/g, "</$1");
	
	/* Replace improper IMGs */
	theHTML = theHTML.replace(/(<img [^>]+[^\/])>/g, "$1 />");
	
	/* Remove empty tags */
	theHTML = theHTML.replace(/(<[^\/]>|<[^\/][^>]*[^\/]>)\s*<\/[^>]*>/g, "");
	
	if (this.wysiwyg)
	{
		if (this.IE) {
			this.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML = theHTML;
		} else {
			this.theIframe.contentDocument.getElementsByTagName("body")[0].innerHTML = theHTML;
		}
	}
	else
	{
		this.theTextarea.value = theHTML;
	}
	
	this.theInput.value = theHTML;
	
	return true;
}




wysiwygEditor.prototype.convertSPANs = function(theSwitch)
{
	if (theSwitch)
	{
		/* Replace styled spans with their semantic equivalent */
		if (this.IE) {
			var theSPANs = this.theIframe.contentWindow.document.getElementsByTagName("span");
		} else {
			var theSPANs = this.theIframe.contentDocument.getElementsByTagName("span");
		}
	
		while(theSPANs.length > 0) {
			var theChildren = new Array();
			var theReplacementElement = null;
			var theParentElement = null;
			
			for (var j = 0; j < theSPANs[0].childNodes.length; j++) {
				theChildren.push(theSPANs[0].childNodes[j].cloneNode(true));
			}
			
			/* New format handling */
			var tmpStyle = theSPANs[0].getAttribute("style");
			var foundStyle = false;
			
			for (var theTagsIndex = 0; theTagsIndex < wysiwygStyles.length; theTagsIndex++) {
				if (tmpStyle.indexOf(wysiwygStyles[theTagsIndex]["css"]) != -1) {
					if (!foundStyle) {
						if (this.IE) {
							theReplacementElement = this.theIframe.contentWindow.document.createElement(wysiwygStyles[theTagsIndex]["tag"]);
						} else {
							theReplacementElement = this.theIframe.contentDocument.createElement(wysiwygStyles[theTagsIndex]["tag"]);
						}
						theParentElement = theReplacementElement;
						foundStyle = true;
					} else {
						if (this.IE) {
							theParentElement = this.theIframe.contentWindow.document.createElement(wysiwygStyles[theTagsIndex]["tag"]);
						} else {
							theParentElement = this.theIframe.contentDocument.createElement(wysiwygStyles[theTagsIndex]["tag"]);
						}
						theReplacementElement.appendChild(theParentElement);
					}
				}
			}

			if (!foundStyle) {
				replaceNodeWithChildren(theSPANs[0]);
			}
			/* End new format handling */




			
			if (theReplacementElement != null)
			{
				for (var j = 0; j < theChildren.length; j++)
				{
					theParentElement.appendChild(theChildren[j]);
				}

				theSPANs[0].parentNode.replaceChild(theReplacementElement, theSPANs[0]);
			}
			
			if (this.IE) {
				theSPANs = this.theIframe.contentWindow.document.getElementsByTagName("span");
			} else {
				theSPANs = this.theIframe.contentDocument.getElementsByTagName("span");
			}
		}
	}
	else
	{
		/* Replace tags with styled spans */
		for (var theTagsIndex = 0; theTagsIndex < wysiwygStyles.length; theTagsIndex++) {
			//if (wysiwygDebug) { alert("theTagsIndex => " + theTagsIndex); }
			
			if (this.IE) {
				var theTags = this.theIframe.contentWindow.document.getElementsByTagName(wysiwygStyles[theTagsIndex]["tag"]);
			} else {
				var theTags = this.theIframe.contentDocument.getElementsByTagName(wysiwygStyles[theTagsIndex]["tag"]);
			}
			
			while (theTags.length > 0) {
				var theChildren = new Array();
				
				if (this.IE) {
					var theSpan = this.theIframe.contentWindow.document.createElement("span");
				} else {
					var theSpan = this.theIframe.contentDocument.createElement("span");
				}
				
				theSpan.setAttribute("style",wysiwygStyles[theTagsIndex]["css"] + ";");
				
				for (var j = 0; j < theTags[0].childNodes.length; j++) {
					theChildren.push(theTags[0].childNodes[j].cloneNode(true));
				}
				
				for (var j = 0; j < theChildren.length; j++) {
					theSpan.appendChild(theChildren[j]);
				}
				
				theTags[0].parentNode.replaceChild(theSpan, theTags[0]);
				
				if (this.IE) {
					theTags = this.theIframe.contentWindow.document.getElementsByTagName(wysiwygStyles[theTagsIndex]["tag"]);
				} else {
					theTags = this.theIframe.contentDocument.getElementsByTagName(wysiwygStyles[theTagsIndex]["tag"]);
				}
			}
		}
	}
	
	return true;
}




/* Check for pasted content */
wysiwygEditor.prototype.detectPaste = function(e)
{
	var keyPressed = null;
	var theEvent = null;
	
	if (e) {
		theEvent = e;
	} else {
		theEvent = event;
	}
	
	if (theEvent.ctrlKey && theEvent.keyCode == 86 && this.wysiwyg) {
		var self = this;
		
		if (this.IE) {
			this.pasteCache = this.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML;
		} else {
			this.pasteCache = this.theIframe.contentDocument.getElementsByTagName("body")[0].innerHTML;
		}

		/* Because Mozilla can't access the clipboard directly, must rely on timeout to check pasted
			differences in main content */
		setTimeout(function(){self.cleanPaste(); return true;}, 100);
	}

	return true;
}




/* Enable document editing */
wysiwygEditor.prototype.initEdit = function()
{
	var self = this;
	
	try {
		if (this.IE) {
			this.theIframe.contentWindow.document.designMode = "on";
		} else {
			this.theIframe.contentDocument.designMode = "on";
		}
	} catch (e) {
		/* setTimeout workaround for bug in Mozilla FireFox which prevents you from immediately changing designMode
			on dynamically created iframes */
		setTimeout(function(){self.initEdit()}, 250);
			
		return false;
	}
	
	if (!this.IE) {
		if (wysiwygDebug) { alert("Not IE"); }
		this.convertSPANs(false);
	}
	
	this.theContainer.style.visibility = "visible";
	this.theTextarea.style.visibility = "visible";
	
	if (wysiwygDebug) { alert(typeof document.addEventListener); }

	/* Mozilla event capturing */
	if (typeof document.addEventListener == "function")
	{
		this.theIframe.contentDocument.addEventListener("mouseup", function(){wysiwygToolbarCheckState(self); return true;}, false);
		this.theIframe.contentDocument.addEventListener("keyup", function(){wysiwygToolbarCheckState(self); return true;}, false);
		this.theIframe.contentDocument.addEventListener("keydown", function(e){self.detectPaste(e); return true;}, false);
	}
	/* MSIE event capturing */
	else
	{
		this.theIframe.contentWindow.document.attachEvent("onmouseup", function(){wysiwygToolbarCheckState(self); return true;});
		this.theIframe.contentWindow.document.attachEvent("onkeyup", function(){wysiwygToolbarCheckState(self); return true;});
		this.theIframe.contentWindow.document.attachEvent("onkeydown", function(e){self.detectPaste(e); return true;}, false);
	}
	
	this.locked = false;

	return true;	
}




/* Add elements to a paragraph and inserts the paragraph before a given element in the body */
wysiwygEditor.prototype.insertNewParagraph = function(elementArray, succeedingElement)
{
	if (this.IE) {
		var theBody = this.theIframe.contentWindow.document.getElementsByTagName("body")[0];
		var theParagraph = this.theIframe.contentWindow.document.createElement("p");
	} else {
		var theBody = this.theIframe.contentDocument.getElementsByTagName("body")[0];
		var theParagraph = this.theIframe.contentDocument.createElement("p");
	}
	
	for (var i = 0; i < elementArray.length; i++)
	{
		theParagraph.appendChild(elementArray[i]);
	}
	
	if (typeof(succeedingElement) != "undefined")
	{
		theBody.insertBefore(theParagraph, succeedingElement);
	}
	else
	{
		theBody.appendChild(theParagraph);
	}
	
	return true;
}




/* Add submit listener to parent form */
wysiwygEditor.prototype.modifyFormSubmit = function()
{
	var self = this;
	var theForm = this.theContainer.parentNode;
	var oldOnsubmit = null;
	
	/* Find the parent form element */
	while (theForm.nodeName.toLowerCase() != "form")
	{
		theForm = theForm.parentNode;
	}

	/* Add onsubmit without overwriting existing function calls */
	oldOnsubmit = theForm.onsubmit;

	if (typeof theForm.onsubmit != "function")
	{
		theForm.onsubmit = function()
		{
			return self.updatewysiwygInput();
		}
	}
	else
	{
		theForm.onsubmit = function()
		{
			self.updatewysiwygInput();

			return oldOnsubmit();			
		}
	}

	return true;
}




/* Format the HTML with paragraphs. Any orphaned text is enclosed in a paragraph, double breaks are paragraph markers */
wysiwygEditor.prototype.paragraphise = function()
{
	if (wysiwygInsertParagraphs && this.wysiwyg)
	{
		if (this.IE) {
			var theBody = this.theIframe.contentWindow.document.getElementsByTagName("body")[0];
		} else {
			var theBody = this.theIframe.contentDocument.getElementsByTagName("body")[0];
		}

		/* Remove all text nodes containing just whitespace */
		for (var i = 0; i < theBody.childNodes.length; i++)
		{
			if (theBody.childNodes[i].nodeName.toLowerCase() == "#text" &&
				theBody.childNodes[i].data.search(/^\s*$/) != -1)
			{
				theBody.removeChild(theBody.childNodes[i]);

				i--;
			}
		}

		var removedElements = new Array();

		for (var i = 0; i < theBody.childNodes.length; i++)
		{
			if (theBody.childNodes[i].nodeName.isInlineName())
			{
				removedElements.push(theBody.childNodes[i].cloneNode(true));

				theBody.removeChild(theBody.childNodes[i]);

				i--;
			}
			else if (theBody.childNodes[i].nodeName.toLowerCase() == "br")
			{
				if (i + 1 < theBody.childNodes.length)
				{
					/* If the current break tag is followed by another break tag... */
					if (theBody.childNodes[i + 1].nodeName.toLowerCase() == "br")
					{
						/* Remove consecutive break tags */
						while (i < theBody.childNodes.length && theBody.childNodes[i].nodeName.toLowerCase() == "br")
						{
							theBody.removeChild(theBody.childNodes[i]);
						}

						if (removedElements.length > 0)
						{
							this.insertNewParagraph(removedElements, theBody.childNodes[i]);

							removedElements = new Array();
						}
					}
					/* If the break tag appears before a block element... */
					else if (!theBody.childNodes[i + 1].nodeName.isInlineName())
					{
						theBody.removeChild(theBody.childNodes[i]);
					}
					else if (removedElements.length > 0)
					{
						removedElements.push(theBody.childNodes[i].cloneNode(true));

						theBody.removeChild(theBody.childNodes[i]);
					}
					else
					{
						theBody.removeChild(theBody.childNodes[i]);
					}

					i--;
				}
				else
				{
					theBody.removeChild(theBody.childNodes[i]);
				}
			}
			else if (removedElements.length > 0)
			{
				this.insertNewParagraph(removedElements, theBody.childNodes[i]);

				removedElements = new Array();
			}
		}

		if (removedElements.length > 0)
		{
			this.insertNewParagraph(removedElements);
		}
	}
	
	return true;
}




/* Update hidden input to reflect editor contents, for submission */
wysiwygEditor.prototype.refreshDisplay = function()
{
	if (this.wysiwyg)
	{
		if (this.IE) {
			this.theIframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML	= this.theInput.value;
		} else {
			this.theIframe.contentDocument.getElementsByTagName("body")[0].innerHTML	= this.theInput.value;
		}
	}
	else
	{
		this.theTextarea.value = this.theInput.value;
	}

	return true;
}




/* Switch between WYSIWYG and HTML source */
wysiwygEditor.prototype.switchMode = function()
{
	if (!this.locked)
	{
		this.locked = true;
		
		/* Switch to HTML source */
		if (this.wysiwyg)
		{
			this.updatewysiwygInput();
			this.theTextarea.value = this.theInput.value;	
			this.theContainer.replaceChild(this.theTextarea, this.theIframe);
			this.theToolbar.disable();
			this.wysiwyg = false;
			this.locked = false;
		}
		/* Switch to WYSIWYG */
		else
		{
			this.updatewysiwygInput();
			this.theContainer.replaceChild(this.theIframe, this.theTextarea);
			this.writeDocument(this.theInput.value);
			this.theToolbar.enable();
			this.initEdit();
			this.wysiwyg = true;
		}
	}
			
	return true;
}




/* Update hidden input to reflect editor contents, for submission */
wysiwygEditor.prototype.updatewysiwygInput = function()
{
	if (this.wysiwyg)
	{
		/* Convert spans to semantics in Mozilla */
		if (!this.IE)
		{
			this.convertSPANs(true);
		}
		
		this.paragraphise();
		this.cleanSource();
	} else {
		this.theInput.value = this.theTextarea.value;
	}

	return true;
}




/* Write initial content to editor */
wysiwygEditor.prototype.writeDocument = function(documentContent)
{
	/* HTML template into which the HTML Editor content is inserted */
	var documentTemplate = "\
		<html>\
			<head>\
				<style type=\"text/css\">@import url(\"INSERT:STYLESHEET:END\");</style>\
			</head>\
			<body id=\"iframeBody\">\
				INSERT:CONTENT:END\
			</body>\
		</html>\
	";
	
	/* Insert dynamic variables/content into document */
	documentTemplate = documentTemplate.replace(/INSERT:STYLESHEET:END/, wysiwygStylesheet);
	documentTemplate = documentTemplate.replace(/INSERT:CONTENT:END/, documentContent);
	
	if (this.IE) {
		this.theIframe.contentWindow.document.open();
		this.theIframe.contentWindow.document.write(documentTemplate);
		this.theIframe.contentWindow.document.close();
	} else {
		this.theIframe.contentDocument.open();
		this.theIframe.contentDocument.write(documentTemplate);
		this.theIframe.contentDocument.close();
	}
	
	return true;
}




/* Toolbar items */
function wysiwygToolbar(theEditor)
{
	var self = this;
	
	this.wysiwygEditorObject = theEditor;
	
	/* Create toolbar ul element */
	this.theList = document.createElement("ul");
	this.theList.id = this.wysiwygEditorObject.theInput.id + "wysiwygToolbar";
	this.theList.className = "wysiwygToolbar";
	this.theList.wysiwygToolbarObject = this;

	/* Create toolbar items */
	for (var i = 0; i < wysiwygToolbarItems.length; i++)
	{
		switch (wysiwygToolbarItems[i]) {
			case "tb_start":
				this.addSeperator(this.theList.id + "ToolbarStart", "wysiwygToolbarStart");
				break;
				
			case "tb_seperator":
				this.addSeperator(this.theList.id + "ToolbarSeperator", "wysiwygToolbarSeperator");
				break;
				
				
				
			case "tb_font_bold":
				this.addButton(this.theList.id + "ButtonBold", "wysiwygButtonBold", "Bold", "Bold");
				break;
				
			case "tb_font_italic":
				this.addButton(this.theList.id + "ButtonItalic", "wysiwygButtonItalic", "Italic", "Italic");
				break;

			case "tb_font_underline":
				this.addButton(this.theList.id + "ButtonUnderline", "wysiwygButtonUnderline", "Underline", "Underline");
				break;

			case "tb_editor_htmlsource":
				this.addButton(this.theList.id + "ButtonHTML", "wysiwygButtonHTML", "Toggle HTML Source", "html");
				break;
				
			case "tb_font_blockformat":
				this.addSelect(this.theList.id + "BlockFormatSelectBlock", "wysiwygSelectBlock", wysiwygBlockFormatOptions, "FormatBlock");
				break;
				
			
			case "tb_editor_undo":
				this.addButton(this.theList.id + "ButtonUndo", "wysiwygButtonUndo", "Undo", "undo");
				break;
				
			case "tb_editor_redo":
				this.addButton(this.theList.id + "ButtonRedo", "wysiwygButtonRedo", "Redo", "redo");
				break;
				
			case "tb_font_forecolor":
				//this.addButton(this.theList.id + "ButtonForeColor", "wysiwygButtonForeColor", "ForeColor", "ForeColor");
				this.addSelect(this.theList.id + "ForeColorSelectBlock", "wysiwygSelectBlock", wysiwygForeColorOptions, "ForeColor");
				break;
				
			
			default:
				if (wysiwygDebug) {
					alert("Invalid buttonID: " + wysiwygToolbarItems[i]);
				}
				break;
		}
	}

	return true;
}


/* Add seperator to toolbar */
wysiwygToolbar.prototype.addSeperator = function(theID, theClass)
{
	if (wysiwygDebug) {alert("wysiwygToolbar.addSeperator(\"" + theID + "\", \"" + theClass + "\");");}
	var menuItem = document.createElement("li");
	var theImg = document.createElement("span");
	
	menuItem.id = theID;
	menuItem.className = "wysiwygToolbarSeperator";

	theImg.className = theClass;

	//theImg.appendChild(theText);
	menuItem.appendChild(theImg);
	this.theList.appendChild(menuItem);

	return true;
}


/* Add button to toolbar */
wysiwygToolbar.prototype.addButton = function(theID, theClass, theLabel, theAction)
{
	if (wysiwygDebug) {alert("wysiwygToolbar.addButton(\"" + theID + "\", \"" + theClass + "\", \"" + theLabel + "\", \"" + theAction + "\");");}
	var menuItem = document.createElement("li");
	var theLink = document.createElement("a");
	var theText = document.createTextNode(theLabel);
	
	menuItem.id = theID;
	menuItem.className = "wysiwygEditButton";

	theLink.href = "#";
	theLink.title = theLabel;
	theLink.className = theClass;
	theLink.action = theAction;
	theLink.onclick = wysiwygToolbarAction;
	theLink.onmouseover = wysiwygToolbarMouseover;

	theLink.appendChild(theText);
	menuItem.appendChild(theLink);
	this.theList.appendChild(menuItem);

	return true;
}

/* Add select box to toolbar. theContentArray is an array of string pairs (option value, option label) */
wysiwygToolbar.prototype.addSelect = function(theID, theClass, theContentArray, theAction)
{
	var menuItem = document.createElement("li");
	var theSelect = document.createElement("select");
	
	menuItem.className = "wysiwygEditSelect";
	
	theSelect.id = theID;
	theSelect.name = theID;
	theSelect.className = theClass;
	theSelect.action = theAction;
	theSelect.onchange = wysiwygToolbarAction;

	for (var i = 0; i < theContentArray.length; i += 2)
	{
		var theOption = document.createElement("option");
		var theText = document.createTextNode(theContentArray[i + 1]);
		
		theOption.value = theContentArray[i];

		theOption.appendChild(theText);
		theSelect.appendChild(theOption);
	}
	
	menuItem.appendChild(theSelect);
	this.theList.appendChild(menuItem);

	return true;
}




/* Turn off toolbar items */
wysiwygToolbar.prototype.disable = function()
{
	/* Change class to disable buttons using CSS */
	this.theList.className += " wysiwygSource";

	/* Loop through list */
	for (var i = 0; i < this.theList.childNodes.length; i++)
	{
		var theChild = this.theList.childNodes[i];
		
		if (theChild.nodeName.toLowerCase() == "li" && theChild.className == "wysiwygEditSelect")
		{
			/* Loop through li children to find select */
			for (j = 0; j < theChild.childNodes.length; j++)
			{
				if (theChild.childNodes[j].nodeName.toLowerCase() == "select")
				{
					theChild.childNodes[j].disabled = "disabled";
					
					break;
				}
			}
		}
	}
	
	return true;
}




/* Turn on toolbar items */
wysiwygToolbar.prototype.enable = function()
{
	/* Change class to enable buttons using CSS */
	this.theList.className = this.theList.className.replace(/ wysiwygSource/, "");
	
	/* Loop through lis */
	for (var i = 0; i < this.theList.childNodes.length; i++)
	{
		var theChild = this.theList.childNodes[i];
		
		if (theChild.nodeName.toLowerCase() == "li" && theChild.className == "wysiwygEditSelect")
		{
			/* Loop through li children to find select */
			for (j = 0; j < theChild.childNodes.length; j++)
			{
				if (theChild.childNodes[j].nodeName.toLowerCase() == "select")
				{
					theChild.childNodes[j].disabled = "";
					
					break;
				}
			}
		}
	}
	
	return true;
}




/* Change the status of the selected toolbar item */
wysiwygToolbar.prototype.setState = function(theState, theStatus)
{
	if (theState.indexOf("SelectBlock") == -1)								//theState != "SelectBlock")
	{
		if (wysiwygDebug) {alert(this.theList.id + "Button" + theState);}
		var theButton = document.getElementById(this.theList.id + "Button" + theState);
	
		if (theButton != null)
		{
			if (theStatus == "on")
			{
				theButton.className = theButton.className.addClass("on");
			}
			else
			{
				theButton.className = theButton.className.removeClass("on");
			}
		}
	}
	else
	{
		var theSelect = document.getElementById(this.theList.id + theState);
		
		if (theSelect != null)
		{
			theSelect.value = "";
			theSelect.value = theStatus;
		}
	}
			
	return true;	
}





/* Action taken when toolbar item activated */
function wysiwygToolbarAction()
{
	if (document.all) {
		this.IE = true;
	} else {
		this.IE = false;
	}
	var theToolbar = this.parentNode.parentNode.wysiwygToolbarObject;
	var thewysiwygEditor = theToolbar.wysiwygEditorObject;
	var theIframe = thewysiwygEditor.theIframe;
	var theSelection = "";

	/* If a button other than "HTML source" is clicked while viewing HTML source: ignore */	
	if (!thewysiwygEditor.wysiwyg && this.action != "html")
	{
		return false;
	}

	switch (this.action)
	{
		case "FormatBlock":
			if (this.IE) {
				//alert(this.value);
				theIframe.contentWindow.document.execCommand(this.action, false, this.value);
			} else {
				theIframe.contentDocument.execCommand(this.action, false, this.value);
			}
			
			thewysiwygEditor.theToolbar.setState("BlockFormatSelectBlock", this.value);
			
			break;
			
		case "html":
			thewysiwygEditor.switchMode();
			
			break;
			
		case "ForeColor":
			/*var w = screen.availWidth;
			var h = screen.availHeight;
			var popW = 400, popH = 400;
			var leftPos = (w-popW)/2, topPos = (h-popH)/2;
			var currentColor = dec_to_rgb(theIframe.contentWindow.document.queryCommandValue("ForeColor"));
			window.open(wysiwygPopupsDir + 'colors.htm?col=' + currentColor + '&cmnd=forecolor&wysiwyg=' + theIframe.id,'popup','location=0,status=0,scrollbars=0,width=' + popW + ',height=' + popH + ',top=' + topPos + ',left=' + leftPos);*/
			if (this.IE) {
				theIframe.contentWindow.document.execCommand(this.action, false, this.value);
			} else {
				theIframe.contentDocument.execCommand(this.action, false, this.value);
			}
			
			//thewysiwygEditor.theToolbar.setState("ForeColorSelectBlock", this.value);
			thewysiwygEditor.theToolbar.setState("ForeColorSelectBlock", "");
			break;
		
		default:
			//theIframe.contentWindow.focus();
			
			if (this.IE) {
				theIframe.contentWindow.document.execCommand(this.action, false, null);
			} else {
				theIframe.contentDocument.execCommand(this.action, false, null);
			}
			
			var theAction = this.action.replace(/^./, function(match){return match.toUpperCase();});

			/* Turn off unordered toolbar item if ordered toolbar item was activated */	
			if (this.action == "insertorderedlist")
			{
				theAction = "Ordered";
				thewysiwygEditor.theToolbar.setState("Unordered", "off");
			}
			
			/* Turn off ordered toolbar item if unordered toolbar item was activated */	
			if (this.action == "insertunorderedlist")
			{
				theAction = "Unordered";
				thewysiwygEditor.theToolbar.setState("Ordered", "off");
			}
			
			if (this.IE) {
				var theCommandState = theIframe.contentWindow.document.queryCommandState(this.action, false, null);
			} else {
				var theCommandState = theIframe.contentDocument.queryCommandState(this.action, false, null)
			}
			
			/* If toolbar item was turned on */
			if (theCommandState)
			{
				thewysiwygEditor.theToolbar.setState(theAction, "on");
			}
			else
			{
				thewysiwygEditor.theToolbar.setState(theAction, "off");
			}
	}
	
	if (thewysiwygEditor.wysiwyg == true)
	{
		theIframe.contentWindow.focus();
	}
	else
	{
		thewysiwygEditor.theTextarea.focus();
	}
	
	return false;	
}




/* Check the nesting of the current cursor position/selection */
function wysiwygToolbarCheckState(thewysiwygEditor, resubmit)
{
	if (!resubmit) {
		/* Allow browser to update selection before using the selection */
		setTimeout(function(){wysiwygToolbarCheckState(thewysiwygEditor, true); return true;}, 100);
	}
	
	var theSelection = null;
	var theRange = null;
	var theParentNode = null;
	var theLevel = 0;
	
	/* Turn off all the buttons */
	var menuListItems = thewysiwygEditor.theToolbar.theList.childNodes;
	for (var i = 0; i < menuListItems.length; i++) {
		menuListItems[i].className = menuListItems[i].className.removeClass("on");
	}
	
	/* IE selections */
	if (thewysiwygEditor.theIframe.contentWindow.document.selection) {
		theSelection = thewysiwygEditor.theIframe.contentWindow.document.selection;
		theRange = theSelection.createRange();
		try {
			theParentNode = theRange.parentElement();
		} catch (e) {
			return false;
		}
	}
	/* Mozilla selections */
	else {
		try {
			theSelection = thewysiwygEditor.theIframe.contentWindow.getSelection();
		} catch (e) {
			return false;
		}
		
		theRange = theSelection.getRangeAt(0);
		theParentNode = theRange.commonAncestorContainer;
	}
	
	while (theParentNode.nodeType == 3) {
		theParentNode = theParentNode.parentNode;
	}
	
	
	//thewysiwygEditor.theToolbar.setState("Unordered", "off");
	//thewysiwygEditor.theToolbar.setState("Ordered", "off");
	//thewysiwygEditor.theToolbar.setState("Link", "off");
	thewysiwygEditor.theToolbar.setState("Italic", "off");
	thewysiwygEditor.theToolbar.setState("Underline", "off");
	thewysiwygEditor.theToolbar.setState("Bold", "off");
	
	
	while (theParentNode.nodeName.toLowerCase() != "body") {
		switch (theParentNode.nodeName.toLowerCase()) {
			/* case "a":
				thewysiwygEditor.theToolbar.setState("Link", "on");
				
				break; */
				
			case "i":
				thewysiwygEditor.theToolbar.setState("Italic", "on");
				
				break;

			case "u":
				thewysiwygEditor.theToolbar.setState("Underline", "on");

				break;
				
			/* case "li":
			
				break;
				
			case "ol":
				thewysiwygEditor.theToolbar.setState("Ordered", "on");
				thewysiwygEditor.theToolbar.setState("Unordered", "off");
				
				break; */
				
			case "span":
				var tmpStyle = theParentNode.getAttribute("style");
				for (var theTagsIndex = 0; theTagsIndex < wysiwygStyles.length; theTagsIndex++) {
					if (tmpStyle.indexOf(wysiwygStyles[theTagsIndex]["css"]) != -1) {
						thewysiwygEditor.theToolbar.setState(wysiwygStyles[theTagsIndex]["name"],"on");
					}
				}
				
				/*
				if (tmpStyle.indexOf("font-weight: bold") != -1) {
					thewysiwygEditor.theToolbar.setState("Bold", "on");
				}
				if (tmpStyle.indexOf("font-style: italic") != -1) {
					thewysiwygEditor.theToolbar.setState("Italic", "on");
				}
				if (tmpStyle.indexOf("text-decoration: underline") != -1) {
					thewysiwygEditor.theToolbar.setState("Underline", "on");
				} */
				
				break;
			
			case "b":
				thewysiwygEditor.theToolbar.setState("Bold", "on");
				
				break;
			
			/* case "ul":
				thewysiwygEditor.theToolbar.setState("Unordered", "on");
				thewysiwygEditor.theToolbar.setState("Ordered", "off");
				
				break; */
			
			default:
				thewysiwygEditor.theToolbar.setState("BlockFormatSelectBlock", "<" + theParentNode.nodeName.toLowerCase() + ">");
				/*if (theParentNode.nodeName.toLowerCase() == "font") {
					//alert(theParentNode.nodeName.toLowerCase()+"\n"+
					//theParentNode.getAttribute("color").toLowerCase());
					thewysiwygEditor.theToolbar.setState("ForeColorSelectBlock", theParentNode.getAttribute("color").toLowerCase());
				} else {*/
					thewysiwygEditor.theToolbar.setState("ForeColorSelectBlock", "");
				/*}*/
				break;
		}
		
		theParentNode = theParentNode.parentNode;
		theLevel++;
	}
	
	return true;			
}




/* Turn off browser status display for toolbar items */
function wysiwygToolbarMouseover() {
	window.status = "";
	
	return true;
}




function acceptableChildren(theNode) {
	var theChildren = theNode.childNodes;
	
	for (var i = 0; i < theChildren.length; i++) {
		if (!theChildren[i].nodeName.isAcceptedElementName()) {
			if (!theChildren[i].nodeName.isInlineName()) {
				if (theNode.nodeName.toLowerCase() == "p") {
					acceptableChildren(replaceNodeWithChildren(theNode));
					
					return true;
				}
				
				changeNodeType(theChildren[i], "p");
			} else {
				replaceNodeWithChildren(theChildren[i]);
			}
				
			i = -1;
		}
	}
	
	for (var i = 0; i < theChildren.length; i++) {
		acceptableChildren(theChildren[i]);
	}
	
	return true;
}




/* Change the type of a node, e.g. h3 to p */
function changeNodeType(theNode, nodeType) {
	var theChildren = new Array();
	var theNewNode = document.createElement(nodeType);
	var theParent = theNode.parentNode;
	
	if (theParent != null) {
		for (var i = 0; i < theNode.childNodes.length; i++) {
			theChildren.push(theNode.childNodes[i].cloneNode(true));
		}
		
		for (var i = 0; i < theChildren.length; i++) {
			theNewNode.appendChild(theChildren[i]);
		}
		
		theParent.replaceChild(theNewNode, theNode);
	}
	
	return true;
}




/* Replace a node with its children -- delete the item and move its children up one level in the hierarchy */
function replaceNodeWithChildren(theNode) {
	var theChildren = new Array();
	var theParent = theNode.parentNode;
	
	if (theParent != null) {
		for (var i = 0; i < theNode.childNodes.length; i++) {
			theChildren.push(theNode.childNodes[i].cloneNode(true));
		}
		
		for (var i = 0; i < theChildren.length; i++) {
			theParent.insertBefore(theChildren[i], theNode);
		}
		
		theParent.removeChild(theNode);
		
		return theParent;
	}
	
	return true;
}





/* Delay for x milliseconds (this function is packed so it will be parsed and executed faster, with less lag time */
function pauseThread(x){var date=new Date();var curDate=null;do{curDate=new Date();}while(curDate-date<x);}

function dec_to_rgb(value) {
	var hex_string = "";
	for (var hexpair = 0; hexpair < 3; hexpair++) {
		var myByte = value & 0xFF;				// Get low byte
		value >>= 8;							// Drop low byte
		var nybble2 = myByte & 0x0F;			// Get low 4 bits
		var nybble1 = (myByte >> 4) & 0x0F;		// Get high 4 bits
		hex_string += nybble1.toString(16);		// Convert 4 bits to hex
		hex_string += nybble2.toString(16);		// Convert 4 bits to hex
	}
	return hex_string.toUpperCase();
}




/* Add a class to a string */
String.prototype.addClass = function(theClass) {
	if (this != "") {
		if (!this.classExists(theClass)) {
			return this + " " + theClass;
		}
	} else {
		return theClass;
	}
	
	return this;
}




/* Check if a class exists in a string */
String.prototype.classExists = function(theClass) {
	var regString = "(^| )" + theClass + "\W*";
	var regExpression = new RegExp(regString);
	
	if (regExpression.test(this)) {
		return true;
	}
	
	return false;
}




/* Check if a string is the nodeName of an accepted element */
String.prototype.isAcceptedElementName = function() {
	//var elementList = new Array("#text", "a", "em", "u", "h1", "h2", "h3", "h4", "h5", "h6", "img", "li", "ol", "p", "strong", "ul");
	var elementList = new Array("#text", "a", "b", "i", "u", "h1", "h2", "h3", "h4", "h5", "h6", "img", "li", "ol", "p", "ul");
	var theName = this.toLowerCase();
	
	for (var i = 0; i < elementList.length; i++) {
		if (theName == elementList[i]) {
			return true;
		}
	}
	
	return false;
}




/* Check if a string is the nodeName of an inline element */
String.prototype.isInlineName = function() {
	//var inlineList = new Array("#text", "a", "em", "u", "font", "span", "strong", "u");
	var inlineList = new Array("#text", "a", "b", "i", "u", "font", "span", "u");
	var theName = this.toLowerCase();
	
	for (var i = 0; i < inlineList.length; i++) {
		if (theName == inlineList[i]) {
			return true;
		}
	}
	
	return false;
}




/* Remove a class from a string */
String.prototype.removeClass = function(theClass) {
	var regString = "(^| )" + theClass + "\W*";
	var regExpression = new RegExp(regString);
	
	return this.replace(regExpression, "");
}




/* Reverse a string */
String.prototype.reverse = function() {
	var theString = "";
	
	for (var i = this.length - 1; i >= 0; i--) {
		theString += this.charAt(i);
	}
	
	return theString;
}




/* Make tags valid by converting uppercase element and attribute names to lowercase and quoting attributes */
String.prototype.validTags = function() {
	var theString = this;
	
	/* Replace uppercase element names with lowercase */
	theString = theString.replace(/<[^> ]*/g, function(match){return match.toLowerCase();});
	
	/* Replace uppercase attribute names with lowercase */
	theString = theString.replace(/<[^>]*>/g, function(match)
		{
			match = match.replace(/ [^=]+=/g, function(match2){return match2.toLowerCase();});

			return match;
		});
			
	/* Put quotes around unquoted attributes */
	theString = theString.replace(/<[^>]*>/g, function(match)
		{
			match = match.replace(/( [^=]+=)([^"][^ >]*)/g, "$1\"$2\"");
			
			return match;
		});
		
	return theString;
}












/* Add missing array functions in MSIE 5 */

// Removes the last element from an array and returns the element.
if (!Array.prototype.pop) {
    Array.prototype.pop = function() {
        var last;
        if (this.length) {
            last = this[this.length - 1];
            this.length -= 1;
        }
        return last;
    };
}

// Adds one or more elements to the end of an array and returns new array length.
if (!Array.prototype.push) {
    Array.prototype.push = function() {
        for (var i = 0; i < arguments.length; ++i) {
            this[this.length] = arguments[i];
        }
        return this.length;
    };
}

// Removes the first element from an array and returns the element.
if (!Array.prototype.shift) {
    Array.prototype.shift = function() {
        var first;
        if (this.length) {
            first = this[0];
            for (var i = 0; i < this.length - 1; ++i) {
                this[i] = this[i + 1];
            }
            this.length -= 1;
        }
        return first;
    };
}

// Adds one or more elements to the front of an array and returns new array length.
if (!Array.prototype.unshift) {
    Array.prototype.unshift = function() {
        if (arguments.length) {
            var i, len = arguments.length;
            for (i = this.length + len - 1; i >= len; --i) {
                this[i] = this[i - len];
            }
            for (i = 0; i < len; ++i) {
                this[i] = arguments[i];
            }
        }
        return this.length;
    };
}

// Adds and/or removes elements from an array.
if (!Array.prototype.splice) {
    Array.prototype.splice = function(index, howMany) {
        var elements = [], removed = [], i;
        for (i = 2; i < arguments.length; ++i) {
            elements.push(arguments[i]);
        }
        for (i = index; (i < index + howMany) && (i < this.length); ++i) {
            removed.push(this[i]);
        }
        for (i = index + howMany; i < this.length; ++i) {
            this[i - howMany] = this[i];
        }
        this.length -= removed.length;
        for (i = this.length + elements.length - 1; i >= index + elements.length; --i) {
            this[i] = this[i - elements.length];
        }
        for (i = 0; i < elements.length; ++i) {
            this[index + i] = elements[i];
        }
        return removed;
    };
}
