/********************************************************************

 * openWYSIWYG v1.47 Copyright (c) 2006 openWebWare.com 

 * Contact us at devs@openwebware.com

 * This copyright notice MUST stay intact for use.

 *

 * $Id: wysiwyg.js,v 1.22 2007/09/08 21:45:57 xhaggi Exp $

 * $Revision: 1.22 $

 *

 * An open source WYSIWYG editor for use in web based applications.

 * For full source code and docs, visit http://www.openwebware.com

 *

 * This library is free software; you can redistribute it and/or modify 

 * it under the terms of the GNU Lesser General Public License as published 

 * by the Free Software Foundation; either version 2.1 of the License, or 

 * (at your option) any later version.

 *

 * This library is distributed in the hope that it will be useful, but 

 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 

 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 

 * License for more details.

 *

 * You should have received a copy of the GNU Lesser General Public License along 

 * with this library; if not, write to the Free Software Foundation, Inc., 59 

 * Temple Place, Suite 330, Boston, MA 02111-1307 USA  

 ********************************************************************/

var WYSIWYG = {



	/**

	 * Settings class, holds all customizeable properties

	 */

	Settings: function() {

	

		// Images Directory

		this.ImagesDir = "../includes/OW/images/";

		

		// Popups Directory

		this.PopupsDir = "../includes/OW/popups/";

		

		// CSS Directory File

		this.CSSFile = "../includes/OW/styles/wysiwyg.css";		

		

		// Default WYSIWYG width and height (use px or %)

		this.Width = "300px";

		this.Height = "200px";

		

		// Default stylesheet of the WYSIWYG editor window

		this.DefaultStyle = "font-family: Arial; font-size: 12px; background-color: #FFFFFF";

		

		// Stylesheet if editor is disabled

		this.DisabledStyle = "font-family: Arial; font-size: 12px; background-color: #EEEEEE";

				

		// Width + Height of the preview window

		this.PreviewWidth = 800;

		this.PreviewHeight = 600;

		

		// Confirmation message if you strip any HTML added by word

		this.RemoveFormatConfMessage = "Clean HTML inserted by MS Word ?";

		

		// Nofication if browser is not supported by openWYSIWYG, leave it blank for no message output.

		this.NoValidBrowserMessage = "openWYSIWYG does not support your browser.";

				

		// Anchor path to strip, leave it blank to ignore

		// or define auto to strip the path where the editor is placed 

		// (only IE)

		this.AnchorPathToStrip = "auto";

		

		// Image path to strip, leave it blank to ignore

		// or define auto to strip the path where the editor is placed 

		// (only IE)

		this.ImagePathToStrip = "auto";

		

		// Enable / Disable the custom context menu

		this.ContextMenu = true;

		

		// Enabled the status bar update. Within the status bar 

		// node tree of the actually selected element will build

		this.StatusBarEnabled = true;

		

		// If enabled than the capability of the IE inserting line breaks will be inverted.

		// Normal: ENTER = <p> , SHIFT + ENTER = <br>

		// Inverted: ENTER = <br>, SHIFT + ENTER = <p>

		this.InvertIELineBreaks = false;

		

		// Replace line breaks with <br> tags

		this.ReplaceLineBreaks = false;

      

		// Page that opened the WYSIWYG (Used for the return command)

		this.Opener = "admin.asp";

		

		// Insert image implementation

		this.ImagePopupFile = "";

		this.ImagePopupWidth = 0;

		this.ImagePopupHeight = 0;

		

		// Holds the available buttons displayed 

		// on the toolbar of the editor

		this.Toolbar = new Array();

		this.Toolbar[0] = new Array(

			"font", 

			"fontsize",

			"headings",	

			"bold", 

			"italic", 

			"underline", 

			"strikethrough",

			"seperator", 

			"forecolor", 

			"backcolor", 

			"seperator",

			"justifyfull", 

			"justifyleft", 

			"justifycenter", 

			"justifyright", 

			"seperator", 

			"unorderedlist", 

			"orderedlist",

			"outdent", 

			"indent",

			"subscript", 

			"superscript", 

			"seperator", 

			"preview", 

			"print",

			"seperator", 

			"viewSource",

			"seperator", 

			"help"

		);

		this.Toolbar[1] = new Array(

			"cut", 

			"copy", 

			"paste",

			"removeformat",

			"seperator", 

			"undo", 

			"redo", 

			"seperator", 

			"inserttable", 

			"insertimage", 

			"powerline",

			"createlink"

		);

		

		// DropDowns

		this.DropDowns = new Array();

		// Fonts

		this.DropDowns['font'] = {

			id: "fonts",

			command: "FontName",

			label: "<font style=\"font-family:{value};font-size:12px;\">{value}</font>",

			width: "90px",

			elements: new Array(

				"Arial", 

				"Sans Serif", 

				"Tahoma", 

				"Verdana", 

				"Courier New", 

				"Georgia", 

				"Times New Roman", 

				"Impact", 

				"Comic Sans MS"

			)

		};

		// Font sizes

		this.DropDowns['fontsize'] = {	

			id: "fontsizes",

			command: "FontSize",

			label: "<font size=\"{value}\">Size {value}</font>",

			width: "54px",

			elements: new Array(

				"1", 

				"2", 

				"3", 

				"4", 

				"5", 

				"6", 

				"7"

			)

		};

		// Headings

		this.DropDowns['headings'] = {	

			id: "headings",

			command: "FormatBlock",

			label: "<{value} style=\"margin:0px;text-decoration:none;font-family:Arial\">{value}</{value}>",

			width: "74px",

			elements: new Array(

				"H1", 

				"H2", 

				"H3", 

				"H4", 

				"H5", 

				"H6"

			)

		};

				

		// Add the given element to the defined toolbar

		// on the defined position

		this.addToolbarElement = function(element, toolbar, position) {

			if(element != "seperator") {this.removeToolbarElement(element);}

			if(this.Toolbar[toolbar-1] == null) {

				this.Toolbar[toolbar-1] = new Array();

			}

			this.Toolbar[toolbar-1].splice(position+1, 1, element);			

		};

		

		// Remove an element from the toolbar

		this.removeToolbarElement = function(element) {

			if(element == "seperator") {return;} // do not remove seperators

			for(var i=0;i<this.Toolbar.length;i++) {

				if(this.Toolbar[i]) {

					var toolbar = this.Toolbar[i];

					for(var j=0;j<toolbar.length;j++) {

						if(toolbar[j] != null && toolbar[j] == element) {

							this.Toolbar[i].splice(j,1);

						}

					}

				}

			}

		};

		

		// clear all or a given toolbar

		this.clearToolbar = function(toolbar) {

			if(typeof toolbar == "undefined") {

				this.Toolbar = new Array();

			}

			else {

				this.Toolbar[toolbar+1] = new Array();

			}

		};

		

	},

	

		

	/* ---------------------------------------------------------------------- *\

		!! Do not change something below or you know what you are doning !!

	\* ---------------------------------------------------------------------- */	



	// List of available block formats (not in use)

	//BlockFormats: new Array("Address", "Bulleted List", "Definition", "Definition Term", "Directory List", "Formatted", "Heading 1", "Heading 2", "Heading 3", "Heading 4", "Heading 5", "Heading 6", "Menu List", "Normal", "Numbered List"),



	// List of available actions and their respective ID and images

	ToolbarList: {

	//Name              buttonID               buttonTitle           	buttonImage               buttonImageRollover

	"bold":           ['Bold',                 'Bold',               	'bold.gif',               'bold_on.gif'],

	"italic":         ['Italic',               'Italic',             	'italics.gif',            'italics_on.gif'],

	"underline":      ['Underline',            'Underline',          	'underline.gif',          'underline_on.gif'],

	"strikethrough":  ['Strikethrough',        'Strikethrough',      	'strikethrough.gif',      'strikethrough_on.gif'],

	"seperator":      ['',                     '',                   	'seperator.gif',          'seperator.gif'],

	"subscript":      ['Subscript',            'Subscript',          	'subscript.gif',          'subscript_on.gif'],

	"superscript":    ['Superscript',          'Superscript',        	'superscript.gif',        'superscript_on.gif'],

	"justifyleft":    ['Justifyleft',          'Justifyleft',        	'justify_left.gif',       'justify_left_on.gif'],

	"justifycenter":  ['Justifycenter',        'Justifycenter',      	'justify_center.gif',     'justify_center_on.gif'],

	"justifyright":   ['Justifyright',         'Justifyright',       	'justify_right.gif',      'justify_right_on.gif'],

	"justifyfull": 	  ['Justifyfull', 		   'Justifyfull', 			'justify_justify.gif', 	  'justify_justify_on.gif'], 

	"unorderedlist":  ['InsertUnorderedList',  'Insert Unordered List',	'list_unordered.gif',     'list_unordered_on.gif'],

	"orderedlist":    ['InsertOrderedList',    'Insert Ordered List',  	'list_ordered.gif',       'list_ordered_on.gif'],

	"outdent":        ['Outdent',              'Outdent',            	'indent_left.gif',        'indent_left_on.gif'],

	"indent":         ['Indent',               'Indent',             	'indent_right.gif',       'indent_right_on.gif'],

	"cut":            ['Cut',                  'Cut',                	'cut.gif',                'cut_on.gif'],

	"copy":           ['Copy',                 'Copy',               	'copy.gif',               'copy_on.gif'],

	"paste":          ['Paste',                'Paste',              	'paste.gif',              'paste_on.gif'],

	"forecolor":      ['ForeColor',            'Fore Color',          	'forecolor.gif',          'forecolor_on.gif'],

	"backcolor":      ['BackColor',            'Back Color',          	'backcolor.gif',          'backcolor_on.gif'],

	"undo":           ['Undo',                 'Undo',               	'undo.gif',               'undo_on.gif'],

	"redo":           ['Redo',                 'Redo',               	'redo.gif',               'redo_on.gif'],

	"inserttable":    ['InsertTable',          'Insert Table',        	'insert_table.gif',       'insert_table_on.gif'],

	"insertimage":    ['InsertImage',          'Insert Image',        	'insert_picture.gif',     'insert_picture_on.gif'],

	"createlink":     ['CreateLink',           'Create Link',         	'insert_hyperlink.gif',   'insert_hyperlink_on.gif'],

	"powerline":      ['PowerLine',            'Power Line',         	'pl.gif',   	          'pl_on.gif'],

	"viewSource":     ['ViewSource',           'View Source',         	'view_source.gif',        'view_source_on.gif'],

	"viewText":       ['ViewText',             'View Text',           	'view_text.gif',          'view_text_on.gif'],

	"help":           ['Help',                 'Help',               	'help.gif',               'help_on.gif'],

	"fonts":     	  ['Fonts',           	   'Select Font',        	'select_font.gif',        'select_font_on.gif'],

	"fontsizes":      ['Fontsizes',            'Select Size',        	'select_size.gif',        'select_size_on.gif'],

	"headings":       ['Headings',             'Select Size',        	'select_heading.gif',     'select_heading_on.gif'],

	"preview":		  ['Preview', 			   'Preview',       	 	'preview.gif',			  'preview_on.gif'],

	"print":		  ['Print', 			   'Print',       	 	 	'print.gif',			  'print_on.gif'],

	"removeformat":   ['RemoveFormat',         'Strip Word HTML',    	'remove_format.gif',      'remove_format_on.gif'],

	"delete":         ['Delete',               'Delete',             	'delete.gif',     		  'delete_on.gif'],

	"save": 		  ['Save', 				   'Save document',         'save.gif', 			  'save_on.gif'],

	"return": 		  ['Return', 			   'Return without saving', 'return.gif', 			  'return_on.gif'],

	"maximize": 	  ['Maximize', 			   'Maximize the editor',   'maximize.gif', 		  'maximize_on.gif']

	},

	

	// stores the different settings for each textarea

	// the textarea identifier is used to store the settings object

	config: new Array(),

	// Create viewTextMode global variable and set to 0

	// enabling all toolbar commands while in HTML mode

	viewTextMode: new Array(),

	// maximized

	maximized: new Array(),

	

	/**

	 * Get the range of the given selection

	 *

	 * @param {Selection} sel Selection object

	 * @return {Range} Range object

	 */

	getRange: function(sel) {

		return sel.createRange ? sel.createRange() : sel.getRangeAt(0);

	},

	

	/**

	 * Return the editor div element

	 *

	 * @param {String} n Editor identifier 

	 * @return {HtmlDivElement} Iframe object

	 */

	getEditorDiv: function(n) {

		return $("wysiwyg_div_" + n);

	},

	

	/**

	 * Return the editor table element

	 *

	 * @param {String} n Editor identifier 

	 * @return {HtmlTableElement} Iframe object

	 */

	getEditorTable: function(n) {

		return $("wysiwyg_table_" + n);

	},

	

	/**

	 * Get the iframe object of the WYSIWYG editor

	 * 

	 * @param {String} n Editor identifier 

	 * @return {HtmlIframeElement} Iframe object

	 */

	getEditor: function(n) {

		return $("wysiwyg" + n);

	},

	

	/**

	 * Get editors window element

	 *

	 * @param {String} n Editor identifier 

	 * @return {HtmlWindowElement} Html window object

	 */

	getEditorWindow: function(n) {

		return this.getEditor(n).contentWindow;

	},

	

	/**

	 * Attach the WYSIWYG editor to the given textarea element

	 *

	 * @param {String} id Textarea identifier (all = all textareas)

	 * @param {Settings} settings the settings which will be applied to the textarea

	 */

	attach: function(id, settings) {	

		if(id != "all") {	

			this.setSettings(id, settings);

			WYSIWYG_Core.includeCSS(this.config[id].CSSFile);

			WYSIWYG_Core.addEvent(window, "load", function generateEditor() {WYSIWYG._generate(id, settings);});

		}

		else {

			WYSIWYG_Core.addEvent(window, "load", function generateEditor() {WYSIWYG.attachAll(settings);});

		}

	},

	

	/**

	 * Attach the WYSIWYG editor to all textarea elements

	 *

	 * @param {Settings} settings Settings to customize the look and feel

	 */

	attachAll: function(settings) {

		var areas = document.getElementsByTagName("textarea");

		for(var i=0;i<areas.length;i++) {

			var id = areas[i].getAttribute("id");

			if(id == null || id == "") continue;

			this.setSettings(id, settings);

			WYSIWYG_Core.includeCSS(this.config[id].CSSFile);

			WYSIWYG._generate(id, settings);

		}

	},

	

	/**

	 * Display an iframe instead of the textarea. 

	 * It's used as textarea replacement to display HTML.

	 *

	 * @param id Textarea identifier (all = all textareas)

	 * @param settings the settings which will be applied to the textarea

	 */

	display: function(id, settings) {	

		if(id != "all") {	

			this.setSettings(id, settings);

			WYSIWYG_Core.includeCSS(this.config[id].CSSFile);

			WYSIWYG_Core.addEvent(window, "load", function displayIframe() {WYSIWYG._display(id, settings);});

		}

		else {

			WYSIWYG_Core.addEvent(window, "load", function displayIframe() {WYSIWYG.displayAll(settings);});

		}

	},

	

	/**

	 * Display an iframe instead of the textarea. 

	 * It's apply the iframe to all textareas found in the current document.

	 *

	 * @param settings Settings to customize the look and feel

	 */

	displayAll: function(settings) {

		var areas = document.getElementsByTagName("textarea");

		for(var i=0;i<areas.length;i++) {

			var id = areas[i].getAttribute("id");

			if(id == null || id == "") continue;

			this.setSettings(id, settings);

			WYSIWYG_Core.includeCSS(this.config[id].CSSFile);

			WYSIWYG._display(id, settings);

		}

	},

		

	/**

	 * Set settings in config array, use the textarea id as identifier

	 * 

	 * @param n Textarea identifier (all = all textareas)

	 * @param settings the settings which will be applied to the textarea

	 */

	setSettings: function(n, settings) {

		if(typeof(settings) != "object") {

			this.config[n] = new this.Settings();

		}

		else {

			this.config[n] = settings;

		}

	},

	

	/**

	 * Insert or modify an image

	 * 

	 * @param {String} src Source of the image

	 * @param {Integer} width Width

	 * @param {Integer} height Height

	 * @param {String} align Alignment of the image

	 * @param {String} border Border size

	 * @param {String} alt Alternativ Text

	 * @param {Integer} hspace Horizontal Space

	 * @param {Integer} vspace Vertical Space

	 * @param {String} n The editor identifier (the textarea's ID)

	 */

	insertImage: function(src, width, height, align, border, alt, hspace, vspace, n) {

	

		// get editor

		var doc = this.getEditorWindow(n).document;

		// get selection and range

		var sel = this.getSelection(n);

		var range = this.getRange(sel);

		

		// the current tag of range

		var img = this.findParent("img", range);

		

		// element is not a link

		var update = (img == null) ? false : true;

		if(!update) {

			img = doc.createElement("img");

		}

		

		// set the attributes

		WYSIWYG_Core.setAttribute(img, "src", src);

		WYSIWYG_Core.setAttribute(img, "style", "width:" + width + ";height:" + height);

		if(align != "") { WYSIWYG_Core.setAttribute(img, "align", align); } else { img.removeAttribute("align"); }

		WYSIWYG_Core.setAttribute(img, "border", border);

		WYSIWYG_Core.setAttribute(img, "alt", alt);

		WYSIWYG_Core.setAttribute(img, "hspace", hspace);

		WYSIWYG_Core.setAttribute(img, "vspace", vspace);

		img.removeAttribute("width");

		img.removeAttribute("height");

		

		// on update exit here

		if(update) { return; }   

		

		// Check if IE or Mozilla (other)

		if (WYSIWYG_Core.isMSIE) {

			range.pasteHTML(img.outerHTML);   

		}

		else {

			this.insertNodeAtSelection(img, n);

		}

	},

	

	/**

	 * Insert or modify a link

	 * 

	 * @param {String} href The url of the link

	 * @param {String} target Target of the link

	 * @param {String} style Stylesheet of the link

	 * @param {String} styleClass Stylesheet class of the link

	 * @param {String} name Name attribute of the link

	 * @param {String} n The editor identifier (the textarea's ID)

	 */

	insertLink: function(href, target, style, styleClass, name, n) {

	

		// get editor

		var doc = this.getEditorWindow(n).document;

		// get selection and range

		var sel = this.getSelection(n);

		var range = this.getRange(sel);

		var lin = null;

		

		// get element from selection

		if(WYSIWYG_Core.isMSIE) {

			if(sel.type == "Control" && range.length == 1) {	

				range = this.getTextRange(range(0));

				range.select();

			}

		}



		// find a as parent element

		lin = this.findParent("a", range);

				

		// check if parent is found

		var update = (lin == null) ? false : true;

		if(!update) {

			lin = doc.createElement("a");

		}

		

		// set the attributes

		WYSIWYG_Core.setAttribute(lin, "href", href);

		WYSIWYG_Core.setAttribute(lin, "class", styleClass);

		WYSIWYG_Core.setAttribute(lin, "className", styleClass);

		WYSIWYG_Core.setAttribute(lin, "target", target);

		WYSIWYG_Core.setAttribute(lin, "name", name);

		WYSIWYG_Core.setAttribute(lin, "style", style);

		

		// on update exit here

		if(update) { return; }

	

		// Check if IE or Mozilla (other)

		if (WYSIWYG_Core.isMSIE) {	

			range.select();

			lin.innerHTML = range.htmlText;

			range.pasteHTML(lin.outerHTML);   

		} 

		else {			

			var node = range.startContainer;	

			var pos = range.startOffset;

			if(node.nodeType != 3) { node = node.childNodes[pos]; }

			if(node.tagName)

				lin.appendChild(node);

			else

				lin.innerHTML = sel;

			this.insertNodeAtSelection(lin, n);

		}

	},

	

	/**

	 * Strips any HTML added by word

	 *

     * @param {String} n The editor identifier (the textarea's ID)

	 */

	removeFormat: function(n) {

		

		if ( !confirm(this.config[n].RemoveFormatConfMessage) ) { return; }

		var doc = this.getEditorWindow(n).document;

		var str = doc.body.innerHTML;

		

		str = str.replace(/<span([^>])*>(&nbsp;)*\s*<\/span>/gi, '');

	    str = str.replace(/<span[^>]*>/gi, '');

	    str = str.replace(/<\/span[^>]*>/gi, '');

	    str = str.replace(/<p([^>])*>(&nbsp;)*\s*<\/p>/gi, '');

	    str = str.replace(/<p[^>]*>/gi, '');

	    str = str.replace(/<\/p[^>]*>/gi, '');

	    str = str.replace(/<h([^>])[0-9]>(&nbsp;)*\s*<\/h>/gi, '');

	    str = str.replace(/<h[^>][0-9]>/gi, '');

	    str = str.replace(/<\/h[^>][0-9]>/gi, ''); 

		str = str.replace (/<B [^>]*>/ig, '<b>');

		

		// var repl_i1 = /<I[^>]*>/ig;

		// str = str.replace (repl_i1, '<i>');

		

		str = str.replace (/<DIV[^>]*>/ig, '');

		str = str.replace (/<\/DIV>/gi, '');

		str = str.replace (/<[\/\w?]+:[^>]*>/ig, '');

		str = str.replace (/(&nbsp;){2,}/ig, '&nbsp;');

		str = str.replace (/<STRONG>/ig, '');

		str = str.replace (/<\/STRONG>/ig, '');

		str = str.replace (/<TT>/ig, '');

		str = str.replace (/<\/TT>/ig, '');

		str = str.replace (/<FONT [^>]*>/ig, '');

		str = str.replace (/<\/FONT>/ig, '');

		str = str.replace (/STYLE=\"[^\"]*\"/ig, '');

		str = str.replace(/<([\w]+) class=([^ |>]*)([^>]*)/gi, '<$1$3');

  	    str = str.replace(/<([\w]+) style="([^"]*)"([^>]*)/gi, '<$1$3'); 

		str = str.replace(/width=([^ |>]*)([^>]*)/gi, '');

	    str = str.replace(/classname=([^ |>]*)([^>]*)/gi, '');

	    str = str.replace(/align=([^ |>]*)([^>]*)/gi, '');

	    str = str.replace(/valign=([^ |>]*)([^>]*)/gi, '');

	    str = str.replace(/<\\?\??xml[^>]>/gi, '');

	    str = str.replace(/<\/?\w+:[^>]*>/gi, '');

	    str = str.replace(/<st1:.*?>/gi, '');

	    str = str.replace(/o:/gi, ''); 

	    

	    str = str.replace(/<!--([^>])*>(&nbsp;)*\s*<\/-->/gi, '');

   		str = str.replace(/<!--[^>]*>/gi, '');

   		str = str.replace(/<\/--[^>]*>/gi, '');

		

		doc.body.innerHTML = str;

	},

	

	/**

	 * Display an iframe instead of the textarea.

	 * 

	 * @private

	 * @param {String} n The editor identifier (the textarea's ID)

	 * @param {Object} settings Object which holds the settings

	 */

	_display: function(n, settings) {

			

		// Get the textarea element

		var textarea = $(n);

		

		// Validate if textarea exists

		if(textarea == null) {

			alert("No textarea found with the given identifier (ID: " + n + ").");

			return;

		}

		

		// Validate browser compatiblity

		if(!WYSIWYG_Core.isBrowserCompatible()) {

			if(this.config[n].NoValidBrowserMessage != "") { alert(this.config[n].NoValidBrowserMessage); }

			return;

		}

		

	    // Load settings in config array, use the textarea id as identifier

		if(typeof(settings) != "object") {

			this.config[n] = new this.Settings();

		}

		else {

			this.config[n] = settings;

		}

		

		// Hide the textarea 

		textarea.style.display = "none";

		

		// Override the width and height of the editor with the 

		// size given by the style attributes width and height

		if(textarea.style.width) {

			this.config[n].Width = textarea.style.width;

		}

		if(textarea.style.height) {

			this.config[n].Height = textarea.style.height

		} 

			

	    // determine the width + height

		var currentWidth = this.config[n].Width;

		var currentHeight = this.config[n].Height;

	 

		// Calculate the width + height of the editor 

		var ifrmWidth = "100%";

		var	ifrmHeight = "100%";

		if(currentWidth.search(/%/) == -1) {

			ifrmWidth = currentWidth;

			ifrmHeight = currentHeight;

		}

				

		// Create iframe which will be used for rich text editing

		var iframe = '<table cellpadding="0" cellspacing="0" border="0" style="width:' + currentWidth + '; height:' + currentHeight + ';" class="tableTextareaEditor"><tr><td valign="top">\n'

	    + '<iframe frameborder="0" id="wysiwyg' + n + '" class="iframeText" style="width:' + ifrmWidth + ';height:' + ifrmHeight + ';"></iframe>\n'

	    + '</td></tr></table>\n';

	

	    // Insert after the textArea both toolbar one and two

		textarea.insertAdjacentHTML("afterEnd", iframe);

						

		// Pass the textarea's existing text over to the content variable

	    var content = textarea.value;

		var doc = this.getEditorWindow(n).document;

		

		// Replace all \n with <br> 

		if(this.config[n].ReplaceLineBreaks) {

			content = content.replace(/(\r\n)|(\n)/ig, "<br>");

		}

			

		// Write the textarea's content into the iframe

	    doc.open();

	    doc.write(content);

	    doc.close();

	    

	    // Set default style of the editor window

		WYSIWYG_Core.setAttribute(doc.body, "style", this.config[n].DefaultStyle);

	},

	

	/**

	 * Replace the given textarea with wysiwyg editor

	 * 

	 * @private

	 * @param {String} n The editor identifier (the textarea's ID)

	 * @param {Object} settings Object which holds the settings

	 */

	_generate: function(n, settings) {

				    

		// Get the textarea element

		var textarea = $(n);

		// Validate if textarea exists

		if(textarea == null) {

			alert("No textarea found with the given identifier (ID: " + n + ").");

			return;

		}	    

		

		// Validate browser compatiblity

		if(!WYSIWYG_Core.isBrowserCompatible()) {

			if(this.config[n].NoValidBrowserMessage != "") { alert(this.config[n].NoValidBrowserMessage); }

			return;

		}

								

		// Hide the textarea 

		textarea.style.display = 'none'; 

		

		// Override the width and height of the editor with the 

		// size given by the style attributes width and height

		if(textarea.style.width) {

			this.config[n].Width = textarea.style.width;

		}

		if(textarea.style.height) {

			this.config[n].Height = textarea.style.height

		}

			

	    // determine the width + height

		var currentWidth = this.config[n].Width;

		var currentHeight = this.config[n].Height;

	 

		// Calculate the width + height of the editor 

		var toolbarWidth = currentWidth;

		var ifrmWidth = "100%";

		var	ifrmHeight = "100%";

		if(currentWidth.search(/%/) == -1) {

			toolbarWidth = currentWidth.replace(/px/gi, "");

			toolbarWidth = (parseFloat(toolbarWidth) + 2) + "px";

			ifrmWidth = currentWidth;

			ifrmHeight = currentHeight;

		}

		

	    // Generate the WYSIWYG Table

	    // This table holds the toolbars and the iframe as the editor

	    var editor = "";

	    editor += '<div id="wysiwyg_div_' + n + '" style="width:' + currentWidth  +';">';

	    editor += '<table border="0" cellpadding="0" cellspacing="0" class="tableTextareaEditor" id="wysiwyg_table_' + n + '" style="width:' + currentWidth  + '; height:' + currentHeight + ';">';

	    editor += '<tr><td style="height:22px;vertical-align:top;">';

	    	  

		// Output all command buttons that belong to toolbar one

		for (var j = 0; j < this.config[n].Toolbar.length;j++) { 

			if(this.config[n].Toolbar[j] && this.config[n].Toolbar[j].length > 0) {

				var toolbar = this.config[n].Toolbar[j];

				

				// Generate WYSIWYG toolbar one

			    editor += '<table border="0" cellpadding="0" cellspacing="0" class="toolbar1" style="width:100%;" id="toolbar' + j + '_' + n + '">';

	    		editor += '<tr><td style="width:6px;"><img src="' + this.config[n].ImagesDir + 'seperator2.gif" alt="" hspace="3"></td>';

				

				// Interate over the toolbar element

				for (var i = 0; i < toolbar.length;i++) { 

					var id = toolbar[i];

				    if (toolbar[i]) {

				    	if(typeof (this.config[n].DropDowns[id]) != "undefined") {

				    		var dropdown = this.config[n].DropDowns[id];

				    		editor += '<td style="width: ' + dropdown.width + ';">';

				    		// write the drop down content

				    		editor += this.writeDropDown(n, id);

				    		editor += '</td>';

				    	}

				    	else {

				    			

				    		// Get the values of the Button from the global ToolbarList object

							var buttonObj = this.ToolbarList[toolbar[i]];

							if(buttonObj) {

								var buttonID = buttonObj[0];

								var buttonTitle = buttonObj[1];

								var buttonImage = this.config[n].ImagesDir + buttonObj[2];

								var buttonImageRollover  = this.config[n].ImagesDir + buttonObj[3];

								    

								if (toolbar[i] == "seperator") {

									editor += '<td style="width: 12px;" align="center">';

									editor += '<img src="' + buttonImage + '" border=0 unselectable="on" width="2" height="18" hspace="2" unselectable="on">';

									editor += '</td>';

								}

								// View Source button

								else if (toolbar[i] == "viewSource"){

								    editor += '<td style="width: 22px;">';

									editor += '<span id="HTMLMode' + n + '"><img src="' + buttonImage +  '" border="0" unselectable="on" title="' + buttonTitle + '" id="' + buttonID + '" class="buttonEditor" onmouseover="this.className=\'buttonEditorOver\'; this.src=\'' + buttonImageRollover + '\';" onmouseout="this.className=\'buttonEditor\'; this.src=\'' + buttonImage + '\';" onclick="WYSIWYG.execCommand(\'' + n + '\', \'' + buttonID + '\');" unselectable="on" width="20" height="20"></span>';

									editor += '<span id="textMode' + n + '"><img src="' + this.config[n].ImagesDir + 'view_text.gif" border="0" unselectable="on" title="viewText" id="ViewText" class="buttonEditor" onmouseover="this.className=\'buttonEditorOver\'; this.src=\'' + this.config[n].ImagesDir + 'view_text_on.gif\';" onmouseout="this.className=\'buttonEditor\'; this.src=\'' + this.config[n].ImagesDir + 'view_text.gif\';" onclick="WYSIWYG.execCommand(\'' + n + '\',\'ViewText\');" unselectable="on"  width="20" height="20"></span>';

							        editor += '</td>';

						        }

								else {

									editor += '<td style="width: 22px;">';

									editor += '<img src="' + buttonImage + '" border=0 unselectable="on" title="' + buttonTitle + '" id="' + buttonID + '" class="buttonEditor" onmouseover="this.className=\'buttonEditorOver\'; this.src=\'' + buttonImageRollover + '\';" onmouseout="this.className=\'buttonEditor\'; this.src=\'' + buttonImage + '\';" onclick="WYSIWYG.execCommand(\'' + n + '\', \'' + buttonID + '\');" unselectable="on" width="20" height="20">';

									editor += '</td>';

								}

							}

						}

			  		}

			  	}

			  	editor += '<td>&nbsp;</td></tr></table>';

			}

		}

		

	 	editor += '</td></tr><tr><td valign="top">\n';

		// Create iframe which will be used for rich text editing

		editor += '<iframe frameborder="0" id="wysiwyg' + n + '" class="iframeText" style="width:100%;height:' + currentHeight + ';"></iframe>\n'

	    + '</td></tr>';

	    // Status bar HTML code

	    if(this.config[n].StatusBarEnabled) {

		    editor += '<tr><td class="wysiwyg-statusbar" style="height:10px;" id="wysiwyg_statusbar_' + n + '">&nbsp;</td></tr>';    

		}

	    editor += '</table>';

	    editor += '</div>';

	    

	    // Insert the editor after the textarea	    

	    textarea.insertAdjacentHTML("afterEnd", editor);

	    					

		// Hide the "Text Mode" button

		// Validate if textMode Elements are prensent

		if($("textMode" + n)) {

			$("textMode" + n).style.display = 'none'; 

		}

						

		// Pass the textarea's existing text over to the content variable

	    var content = textarea.value;

		var doc = this.getEditorWindow(n).document;		

		



		// Replace all \n with <br> 

		if(this.config[n].ReplaceLineBreaks) {

			content = content.replace(/\n\r|\n/ig, "<br>");

		}

				

		// Write the textarea's content into the iframe

	    doc.open();

	    doc.write(content);

	    doc.close();

	    		

		// Make the iframe editable in both Mozilla and IE

		// Improve compatiblity for IE + Mozilla

		if (doc.body.contentEditable) {

			doc.body.contentEditable = true;

		}

		else {

			doc.designMode = "on";	

		}

	

		// Set default font style

		WYSIWYG_Core.setAttribute(doc.body, "style", this.config[n].DefaultStyle);

		

		// Enable table highlighting

		WYSIWYG_Table.refreshHighlighting(n);

	    

	    // Event Handling

	    // Update the textarea with content in WYSIWYG when user submits form

	    for (var idx=0; idx < document.forms.length; idx++) {

	    	WYSIWYG_Core.addEvent(document.forms[idx], "submit", function xxx_aa() { WYSIWYG.updateTextArea(n); });

	    }

	    

	    // close font selection if mouse moves over the editor window

	    WYSIWYG_Core.addEvent(doc, "mouseover", function xxx_bb() { WYSIWYG.closeDropDowns(n);});

	    

	    // If it's true invert the line break capability of IE

		if(this.config[n].InvertIELineBreaks) {

			WYSIWYG_Core.addEvent(doc, "keypress", function xxx_cc() { WYSIWYG.invertIELineBreakCapability(n); });

		}

					

		// status bar update

		if(this.config[n].StatusBarEnabled) {

			WYSIWYG_Core.addEvent(doc, "mouseup", function xxx_dd() { WYSIWYG.updateStatusBar(n); });

		}

	    	    

    	// custom context menu

		if(this.config[n].ContextMenu) {	

			WYSIWYG_ContextMenu.init(n);		

		}

								

		// init viewTextMode var

	    this.viewTextMode[n] = false;			

	},

	

	/**

	 * Disable the given WYSIWYG Editor Box

	 * 

	 * @param {String} n The editor identifier (the textarea's ID)

	 */ 

	disable: function(n) {

		

		// get the editor window

		var editor = this.getEditorWindow(n);

	

		// Validate if editor exists

		if(editor == null) {

			alert("No editor found with the given identifier (ID: " + n + ").");

			return;

		}

		

		if(editor) {

			// disable design mode or content editable feature

			if(editor.document.body.contentEditable) {

				editor.document.body.contentEditable = false;

			}

			else {

				editor.document.designMode = "Off";		

			}

				

			// change the style of the body

			WYSIWYG_Core.setAttribute(editor.document.body, "style", this.config[n].DisabledStyle);

			

			// hide the status bar

			this.hideStatusBar(n);

							

			// hide all toolbars

			this.hideToolbars(n);

		}

	},

	

	/**

	 * Enables the given WYSIWYG Editor Box

	 * 

	 * @param {String} n The editor identifier (the textarea's ID)

	 */

	enable: function(n) {

			

		// get the editor window

		var editor = this.getEditorWindow(n);

	

		// Validate if editor exists

		if(editor == null) {

			alert("No editor found with the given identifier (ID: " + n + ").");

			return;

		}

		

		if(editor) {

			// disable design mode or content editable feature

			if(editor.document.body.contentEditable){

				editor.document.body.contentEditable = true;

			}

			else {

				editor.document.designMode = "On";		

			}

				

			// change the style of the body

			WYSIWYG_Core.setAttribute(editor.document.body, "style", this.config[n].DefaultStyle);

			

			// hide the status bar

			this.showStatusBar(n);

							

			// hide all toolbars

			this.showToolbars(n);

		}

	},

	

	/**

	 * Returns the node structure of the current selection as array

	 * 

	 * @param {String} n The editor identifier (the textarea's ID)

	 */

	getNodeTree: function(n) {

		

		var sel = this.getSelection(n);

		var range = this.getRange(sel);	

			

		// get element of range

		var tag = this.getTag(range);

		if(tag == null) { return; }

		// get parent of element

		var node = this.getParent(tag);

		// init the tree as array with the current selected element

		var nodeTree = new Array(tag);

		// get all parent nodes

		var ii = 1;

		

		while(node != null && node.nodeName != "#document") {

			nodeTree[ii] = node;

			node = this.getParent(node);			

			ii++;

		}

		

		return nodeTree;

	},

	

	/**

	 * Removes the current node of the selection

	 *

	 * @param {String} n The editor identifier (the textarea's ID)

	 */

	removeNode: function(n) {

		// get selection and range

		var sel = this.getSelection(n);

		var range = this.getRange(sel);

		// the current tag of range

		var tag = this.getTag(range);

		var parent = tag.parentNode;

		if(tag == null || parent == null) { return; }

		if(tag.nodeName == "HTML" || tag.nodeName == "BODY") { return; }



		// copy child elements of the node to the parent element before remove the node

		var childNodes = new Array();

		for(var i=0; i < tag.childNodes.length;i++)

			childNodes[i] = tag.childNodes[i];	

		for(var i=0; i < childNodes.length;i++)

			parent.insertBefore(childNodes[i], tag);	

		

		// remove node

		parent.removeChild(tag);

		// validate if parent is a link and the node is only 

		// surrounded by the link, then remove the link too

		if(parent.nodeName == "A" && !parent.hasChildNodes()) {

			if(parent.parentNode) { parent.parentNode.removeChild(parent); }

		}

		// update the status bar

		this.updateStatusBar(n);

	},

	

	/**

	 * Get the selection of the given editor

	 * 

	 * @param {String} n The editor identifier (the textarea's ID)

	 */

	getSelection: function(n) {

		var ifrm = this.getEditorWindow(n);

		var doc = ifrm.document;

		var sel = null;

		if(ifrm.getSelection){

			sel = ifrm.getSelection();

		}

		else if (doc.getSelection) {

			sel = doc.getSelection();

		}

		else if (doc.selection) {

			sel = doc.selection;

		}

		return sel;

	},

	

	/**

	 * Updates the status bar with the current node tree

	 *

	 * @param {String} n The editor identifier (the textarea's ID)

	 */

	updateStatusBar: function(n) {

		

		// get the node structure

		var nodeTree = this.getNodeTree(n);

		if(nodeTree == null) { return; }

		// format the output

		var outputTree = "";

		var max = nodeTree.length - 1;

		for(var i=max;i>=0;i--) {

			if(nodeTree[i].nodeName != "HTML" && nodeTree[i].nodeName != "BODY") {

				outputTree += '<a class="wysiwyg-statusbar" href="javascript:WYSIWYG.selectNode(\'' + n + '\',' + i + ');">' + nodeTree[i].nodeName + '</a>';	

			}

			else {

				outputTree += nodeTree[i].nodeName;

			}

			if(i > 0) { outputTree += " > "; }

		}

			

		// update the status bar 	

		var statusbar = $("wysiwyg_statusbar_" + n);

		if(statusbar){ 

			statusbar.innerHTML = outputTree; 

		}

	},

	

	/**

	 * Execute a command on the editor document

	 * 

	 * @param {String} command The execCommand (e.g. Bold)

	 * @param {String} n The editor identifier

	 * @param {String} value The value when applicable

	 */

	execCommand: function(n, cmd, value) {

				

		// When user clicks toolbar button make sure it always targets its respective WYSIWYG

		this.getEditorWindow(n).focus();

		

		// When in Text Mode these execCommands are enabled

		var textModeCommands = new Array("ViewText", "Print");

	  

	  	// Check if in Text mode and a disabled command execute

		var cmdValid = false;

		for (var i = 0; i < textModeCommands.length; i++) {

			if (textModeCommands[i] == cmd) {

				cmdValid = true;

			}

		}

		if(this.viewTextMode[n] && !cmdValid) {

			alert("You are in TEXT Mode. This feature has been disabled.");

		  	return;

		} 

		

		// rbg to hex convertion implementation dependents on browser

		var toHexColor = WYSIWYG_Core.isMSIE ? WYSIWYG_Core._dec_to_rgb : WYSIWYG_Core.toHexColor;

		

		// popup screen positions

		var popupPosition = {left: parseInt(window.screen.availWidth / 3), top: parseInt(window.screen.availHeight / 3)};		

		

		// Check the insert image popup implementation

		var imagePopupFile = this.config[n].PopupsDir + 'insert_image.php';

		var imagePopupWidth = 430;

		var imagePopupHeight = 400;

		if(typeof this.config[n].ImagePopupFile != "undefined" && this.config[n].ImagePopupFile != "") {

			imagePopupFile = this.config[n].ImagePopupFile;

		}

		if(typeof this.config[n].ImagePopupWidth && this.config[n].ImagePopupWidth > 0) {

			imagePopupWidth = this.config[n].ImagePopupWidth;

		}

		if(typeof this.config[n].ImagePopupHeight && this.config[n].ImagePopupHeight > 0) {

			imagePopupHeight = this.config[n].ImagePopupHeight;

		}

		

		// switch which action have to do

		switch(cmd) {

			case "Maximize":

				this.maximize(n);

			break;

			case "FormatBlock":

				WYSIWYG_Core.execCommand(n, cmd, "<" + value + ">");

			break;

			// ForeColor and 

			case "ForeColor":

				var rgb = this.getEditorWindow(n).document.queryCommandValue(cmd);

		      	var currentColor = rgb != '' ? toHexColor(this.getEditorWindow(n).document.queryCommandValue(cmd)) : "000000";

			  	window.open(this.config[n].PopupsDir + 'select_color.html?color=' + currentColor + '&command=' + cmd + '&wysiwyg=' + n, 'popup', 'location=0,status=0,scrollbars=0,width=210,height=165,top=' + popupPosition.top + ',left=' + popupPosition.left).focus();

			break;

			

			// BackColor

			case "BackColor":

				var currentColor = toHexColor(this.getEditorWindow(n).document.queryCommandValue(cmd));

			  	window.open(this.config[n].PopupsDir + 'select_color.html?color=' + currentColor + '&command=' + cmd + '&wysiwyg=' + n, 'popup', 'location=0,status=0,scrollbars=0,width=210,height=165,top=' + popupPosition.top + ',left=' + popupPosition.left).focus();

			break;

			

			// InsertImage

			case "InsertImage": 

				window.open(imagePopupFile + '?wysiwyg=' + n, 'popup', 'location=0,status=0,scrollbars=1,resizable=0,width=' + imagePopupWidth + ',height=' + imagePopupHeight + ',top=' + popupPosition.top + ',left=' + popupPosition.left).focus();

			break;

			

			// Remove Image

			case "RemoveImage": 

				this.removeImage(n);

			break;

			

			// Remove Link

			case "RemoveLink": 

				this.removeLink(n);

			break;

			

			case "PowerLine":

				WYSIWYG.insertHTML("<iframe src=\"/complements/powerline.php\" width=\"150\" height=\"250\" scrolling=\"no\" frameborder=\"0\" allowtransparency=\"true\"></iframe>", n);

			break;

			// Remove a Node

			case "RemoveNode": 

				this.removeNode(n);

			break;

			

			// Create Link

			case "CreateLink": 

				window.open(this.config[n].PopupsDir + 'insert_hyperlink.html?wysiwyg=' + n, 'popup', 'location=0,status=0,scrollbars=0,resizable=0,width=350,height=160,top=' + popupPosition.top + ',left=' + popupPosition.left).focus();

			break;

			

			// InsertTable

			case "InsertTable": 

				window.open(this.config[n].PopupsDir + 'create_table.html?wysiwyg=' + n, 'popup', 'location=0,status=0,scrollbars=0,resizable=0,width=500,height=260,top=' + popupPosition.top + ',left=' + popupPosition.left).focus();

			break;

			

			// ViewSource

			case "ViewSource": 

				this.viewSource(n);

			break;

			

			// ViewText

			case "ViewText": 

				this.viewText(n);

			break;

			

			// Help

			case "Help":

				window.open(this.config[n].PopupsDir + 'about.html?wysiwyg=' + n, 'popup', 'location=0,status=0,scrollbars=0,resizable=0,width=400,height=350,top=' + popupPosition.top + ',left=' + popupPosition.left).focus();

			break;

			

			// Strip any HTML added by word

			case "RemoveFormat":

				this.removeFormat(n);	

			break;

			

			// Preview thx to Korvo

			case "Preview":

				window.open(this.config[n].PopupsDir + 'preview.html?wysiwyg=' + n,'popup', 'location=0,status=0,scrollbars=1,resizable=1,width=' + this.config[n].PreviewWidth + ',height=' + this.config[n].PreviewHeight + ',top=' + popupPosition.top + ',left=' + popupPosition.left).focus();

			break;

			

			// Print

			case "Print":

				this.print(n);

			break;

			

			// Save

			case "Save":

			    WYSIWYG.updateTextArea(n);

			    var form = WYSIWYG_Core.findParentNode("FORM", this.getEditor(n));

			    if(form == null) {

			    	alert("Can not submit the content, because no form element found.");

			    	return;

			    }

			    form.submit();

			break;

			         

			// Return

			case "Return":

			   location.replace(this.config[n].Opener);

			break;

						

			default: 

				WYSIWYG_Core.execCommand(n, cmd, value);

				

		}

	 		

		// hide node the font + font size selection

		this.closeDropDowns(n);

	},	

	

	/**

	 * Maximize the editor instance

	 * 

	 * @param {String} n The editor identifier

	 */

	maximize: function(n) {

		

		var divElm = this.getEditorDiv(n);

		var tableElm = this.getEditorTable(n);

		var editor = this.getEditor(n);

		var setting = this.config[n];

		var size = WYSIWYG_Core.windowSize();

		size.width -= 5;

		if(this.maximized[n]) {

			WYSIWYG_Core.setAttribute(divElm, "style", "position:static;z-index:9998;top:0px;left:0px;width:" + setting.Width + ";height:100%;");

			WYSIWYG_Core.setAttribute(tableElm, "style", "width:" + setting.Width + ";height:" + setting.Height + ";");

			WYSIWYG_Core.setAttribute(editor, "style", "width:100%;height:" + setting.Height + ";");

			this.maximized[n] = false;

		}

		else {

			WYSIWYG_Core.setAttribute(divElm, "style", "position:absolute;z-index:9998;top:0px;left:0px;width:" + size.width + "px;height:" + size.height + "px;");

			WYSIWYG_Core.setAttribute(tableElm, "style", "width:100%;height:100%;");

			WYSIWYG_Core.setAttribute(editor, "style", "width:100%;height:100%;");

			this.maximized[n] = true;

		}



	},	

			

	/**

	 * Insert HTML into WYSIWYG in rich text

	 *

	 * @param {String} html The HTML being inserted (e.g. <b>hello</b>)

	 * @param {String} n The editor identifier

	 */

	insertHTML: function(html, n) {			

		if (WYSIWYG_Core.isMSIE) {	  

			this.getEditorWindow(n).document.selection.createRange().pasteHTML(html);   

		} 

		else {

			var span = this.getEditorWindow(n).document.createElement("span");

			span.innerHTML = html;

			this.insertNodeAtSelection(span, n);		

		}

	},

	

	/* ---------------------------------------------------------------------- *\

	  Function    : insertNodeAtSelection()

	  Description : insert HTML into WYSIWYG in rich text (mozilla)

	  Usage       : WYSIWYG.insertNodeAtSelection(insertNode, n)

	  Arguments   : insertNode - The HTML being inserted (must be innerHTML inserted within a div element)

	                n          - The editor identifier that the HTML will be inserted into (the textarea's ID)

	\* ---------------------------------------------------------------------- */

	insertNodeAtSelection: function(insertNode, n) {

	

		// get editor document

		var doc = this.getEditorWindow(n).document;

		// get current selection

		var sel = this.getSelection(n);

		

		// get the first range of the selection

		// (there's almost always only one range)

		var range = sel.getRangeAt(0);

		

		// deselect everything

		sel.removeAllRanges();

		

		// remove content of current selection from document

		range.deleteContents();

		

		// get location of current selection

		var container = range.startContainer;

		var pos = range.startOffset;

		

		// make a new range for the new selection

		range = doc.createRange();

		

		if (container.nodeType==3 && insertNode.nodeType==3) {					

			// if we insert text in a textnode, do optimized insertion

			container.insertData(pos, insertNode.data);

			// put cursor after inserted text

			range.setEnd(container, pos+insertNode.length);

			range.setStart(container, pos+insertNode.length);		

		} 	

		else {

		

			var afterNode;	

			var beforeNode;

			if (container.nodeType==3) {

				// when inserting into a textnode

				// we create 2 new textnodes

				// and put the insertNode in between

				var textNode = container;

				container = textNode.parentNode;

				var text = textNode.nodeValue;

				

				// text before the split

				var textBefore = text.substr(0,pos);

				// text after the split

				var textAfter = text.substr(pos);

				

				beforeNode = document.createTextNode(textBefore);

				afterNode = document.createTextNode(textAfter);

				

				// insert the 3 new nodes before the old one

				container.insertBefore(afterNode, textNode);

				container.insertBefore(insertNode, afterNode);

				container.insertBefore(beforeNode, insertNode);

				

				// remove the old node

				container.removeChild(textNode);

			} 

			else {

				// else simply insert the node

				afterNode = container.childNodes[pos];

				container.insertBefore(insertNode, afterNode);

			}

			

			try {

				range.setEnd(afterNode, 0);

				range.setStart(afterNode, 0);

			}

			catch(e) {

				//alert(e);

			}

		}

		

		sel.addRange(range);

	},

	

	/**

	 * Prints the content of the WYSIWYG editor area

	 * 

	 * @param {String} n The editor identifier (textarea ID)

	 */

	print: function(n) {

		if(document.all && navigator.appVersion.substring(22,23)==4) {

			var doc = this.getEditorWindow(n).document;

			doc.focus();

			var OLECMDID_PRINT = 6;

			var OLECMDEXECOPT_DONTPROMPTUSER = 2;

			var OLECMDEXECOPT_PROMPTUSER = 1;

			var WebBrowser = '<object id="WebBrowser1" width="0" height="0" classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2"></object>';

			doc.body.insertAdjacentHTML('beforeEnd',WebBrowser);

			WebBrowser.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER);

			WebBrowser.outerHTML = '';

		} else {

			this.getEditorWindow(n).print();

		}

	},

	

	/**

	 * Writes the content of an drop down

	 *

	 * @param {String} n The editor identifier (textarea ID)

	 * @param {String} id Drop down identifier

	 * @return {String} Drop down HTML

	 */

	writeDropDown: function(n, id) {

	

		var dropdown = this.config[n].DropDowns[id];

		var toolbarObj = this.ToolbarList[dropdown.id];

		var image = this.config[n].ImagesDir  + toolbarObj[2];

		var imageOn  = this.config[n].ImagesDir + toolbarObj[3];

		dropdown.elements.sort();

		

		var output = "";

		output += '<table border="0" cellpadding="0" cellspacing="0"><tr>';

		output += '<td onMouseOver="$(\'img_' + dropdown.id + '_' + n + '\').src=\'' + imageOn + '\';" onMouseOut="$(\'img_' + dropdown.id + '_' + n + '\').src=\'' + image + '\';">';

		output += '<img src="' + image + '" id="img_' + dropdown.id + '_' + n + '" height="20" onClick="WYSIWYG.openDropDown(\'' + n + '\',\'' + dropdown.id + '\');" unselectable="on" border="0"><br>';

		output += '<span id="elm_' + dropdown.id + '_' + n + '" class="dropdown" style="width: 145px;display:none;">';

		for (var i = 0; i < dropdown.elements.length;i++) {

			if (dropdown.elements[i]) {

				var value = dropdown.elements[i];

				var label = dropdown.label.replace(/{value}/gi, value);

				// output

		  		output += '<button type="button" onClick="WYSIWYG.execCommand(\'' + n + '\',\'' + dropdown.command + '\',\'' + value + '\')\;" onMouseOver="this.className=\'mouseOver\'" onMouseOut="this.className=\'mouseOut\'" class="mouseOut" style="width: 120px;">';

		  		output += '<table cellpadding="0" cellspacing="0" border="0"><tr>';

		  		output += '<td align="left">' + label + '</td>';

		  		output += '</tr></table></button><br>';	

		  	}

	  	}

  		output += '</span></td></tr></table>';	

  		

		return output;

	},

	

	/**

	 * Close all drop downs. You can define a exclude dropdown id

	 * 

	 * @param {String} n The editor identifier (textarea ID)

     * @param {String} exid Excluded drop down identifier

	 */

	closeDropDowns: function(n, exid) {

		if(typeof(exid) == "undefined") exid = "";

		var dropdowns = this.config[n].DropDowns;

		for(var id in dropdowns) {

			var dropdown = dropdowns[id];

			if(dropdown.id != exid) {

				var divId = "elm_" + dropdown.id + "_" + n;

				if($(divId)) $(divId).style.display = 'none';

			}

		}			

	},

	

	/**

	 * Open a defined drop down

	 * 

     * @param {String} n The editor identifier (textarea ID)

	 * @param {String} id Drop down identifier

	 */

	openDropDown: function(n, id) {

		var divId = "elm_" + id + "_" + n;

		if($(divId).style.display == "none") {	

			$(divId).style.display = "block"; 

		}

		else {

			$(divId).style.display = "none"; 

		}

		$(divId).style.position = "absolute";

		this.closeDropDowns(n, id);

	},

	

	/**

	 * Shows the HTML source code generated by the WYSIWYG editor

	 * 

	 * @param {String} n The editor identifier (textarea ID)

	 */

	viewSource: function(n) {

		

		// document

		var doc = this.getEditorWindow(n).document;

		

		// Enable table highlighting

		WYSIWYG_Table.disableHighlighting(n);

			

		// View Source for IE 	 

		if (WYSIWYG_Core.isMSIE) {

			var iHTML = doc.body.innerHTML;

			// strip off the absolute urls

			iHTML = this.stripURLPath(n, iHTML);

			// replace all decimal color strings with hex decimal color strings

			iHTML = WYSIWYG_Core.replaceRGBWithHexColor(iHTML);

			doc.body.innerText = iHTML;

		}

	  	// View Source for Mozilla/Netscape

	  	else {

	  		// replace all decimal color strings with hex decimal color strings

			var html = WYSIWYG_Core.replaceRGBWithHexColor(doc.body.innerHTML);

	    	html = document.createTextNode(html);

	    	doc.body.innerHTML = "";

	    	doc.body.appendChild(html);

	  	}

	  

		// Hide the HTML Mode button and show the Text Mode button

		// Validate if Elements are present

		if($('HTMLMode' + n)) {

		    $('HTMLMode' + n).style.display = 'none'; 

		}

	    if($('textMode' + n)) {

		    $('textMode' + n).style.display = 'block';

		}

		

		// set the font values for displaying HTML source

		doc.body.style.fontSize = "12px";

		doc.body.style.fontFamily = "Courier New"; 

		

	  	this.viewTextMode[n] = true;

	},

		

	/**

	 * Shows the HTML source code generated by the WYSIWYG editor

	 * 

	 * @param {String} n The editor identifier (textarea ID)

	 */

	viewText: function(n) { 

		

		// get document

		var doc = this.getEditorWindow(n).document;

		

		// View Text for IE 	  	 

		if (WYSIWYG_Core.isMSIE) {

	    	var iText = doc.body.innerText;

	    	// strip off the absolute urls

			iText = this.stripURLPath(n, iText);

			// replace all decimal color strings with hex decimal color strings

			iText = WYSIWYG_Core.replaceRGBWithHexColor(iText);

	    	doc.body.innerHTML = iText;

		}

	  

		// View Text for Mozilla/Netscape

	  	else {

	    	var html = doc.body.ownerDocument.createRange();

	    	html.selectNodeContents(doc.body);

	    	// replace all decimal color strings with hex decimal color strings

			html = WYSIWYG_Core.replaceRGBWithHexColor(html.toString());

	    	doc.body.innerHTML = html;

		}

		

		// Enable table highlighting

		WYSIWYG_Table.refreshHighlighting(n);

					  

		// Hide the Text Mode button and show the HTML Mode button

		// Validate if Elements are present

		if($('textMode' + n)) {

			$('textMode' + n).style.display = 'none'; 

		}

		if($('HTMLMode' + n)) {

			$('HTMLMode' + n).style.display = 'block';

		}

		

		// reset the font values (changed)

		WYSIWYG_Core.setAttribute(doc.body, "style", this.config[n].DefaultStyle);

		

		this.viewTextMode[n] = false;

	},

		

	/* ---------------------------------------------------------------------- *\

	  Function    : stripURLPath()

	  Description : Strips off the defined image and the anchor urls of the given content.

	  				It also can strip the document URL automatically if you define auto.

	  Usage       : WYSIWYG.stripURLPath(content)

	  Arguments   : content  - Content on which the stripping applies

	\* ---------------------------------------------------------------------- */

	stripURLPath: function(n, content, exact) {

	

		// parameter exact is optional

		if(typeof exact == "undefined") {

			exact = true;

		}

	

		var stripImgageUrl = null;

		var stripAnchorUrl = null;

		

		// add url to strip of anchors to array

		if(this.config[n].AnchorPathToStrip == "auto") {

			stripAnchorUrl = WYSIWYG_Core.getDocumentUrl(document);

		}

		else if(this.config[n].AnchorPathToStrip != "") {

			stripAnchorUrl = this.config[n].AnchorPathToStrip;

		}

		

		// add strip url of images to array

		if(this.config[n].ImagePathToStrip == "auto") {

			stripImgageUrl = WYSIWYG_Core.getDocumentUrl(document);

		}

		else if(this.config[n].ImagePathToStrip != "") {

			stripImgageUrl = this.config[n].ImagePathToStrip;

		}

		

		var url;

		var regex;

		var result;

		// strip url of image path

		if(stripImgageUrl) {

			// escape reserved characters to be a valid regex	

			url = WYSIWYG_Core.stringToRegex(WYSIWYG_Core.getDocumentPathOfUrl(stripImgageUrl));	

			

			// exact replacing of url. regex: src="<url>"

			if(exact) {

				regex = eval("/(src=\")(" + url + ")([^\"]*)/gi");

				content = content.replace(regex, "$1$3");	

			}

			// not exect replacing of url. regex: <url>

			else {

				regex = eval("/(" + url + ")(.+)/gi");

				content = content.replace(regex, "$2");	

			}

			

			// strip absolute urls without a heading slash ("images/print.gif")	

			result = WYSIWYG_Core.getDocumentPathOfUrl(stripImgageUrl).match(/.+[\/]{2,3}[^\/]*/,"");

			if(result) {

				url = WYSIWYG_Core.stringToRegex(result[0]);

				

				// exact replacing of url. regex: src="<url>"

				if(exact) {

					regex = eval("/(src=\")(" + url + ")([^\"]*)/gi");

					content = content.replace(regex, "$1$3");

				}

				// not exect replacing of url. regex: <url>

				else {

					regex = eval("/(" + url + ")(.+)/gi");

					content = content.replace(regex, "$2");	

				}

			}	

		}

		

		// strip url of image path

		if(stripAnchorUrl) {						

			// escape reserved characters to be a valid regex		

			url = WYSIWYG_Core.stringToRegex(WYSIWYG_Core.getDocumentPathOfUrl(stripAnchorUrl));

			

			// strip absolute urls with a heading slash ("/product/index.html")

			// exact replacing of url. regex: src="<url>"

			if(exact) {

				regex = eval("/(href=\")(" + url + ")([^\"]*)/gi");

				content = content.replace(regex, "$1$3");	

			}

			// not exect replacing of url. regex: <url>

			else {

				regex = eval("/(" + url + ")(.+)/gi");

				content = content.replace(regex, "$2");	

			}

			

			// strip absolute urls without a heading slash ("product/index.html")	

			result = WYSIWYG_Core.getDocumentPathOfUrl(stripAnchorUrl).match(/.+[\/]{2,3}[^\/]*/,"");

			if(result) {

				url = WYSIWYG_Core.stringToRegex(result[0]);

				// exact replacing of url. regex: src="<url>"

				if(exact) {

					regex = eval("/(href=\")(" + url + ")([^\"]*)/gi");

					content = content.replace(regex, "$1$3");	

				}

				// not exect replacing of url. regex: <url>

				else {

					regex = eval("/(" + url + ")(.+)/gi");

					content = content.replace(regex, "$2");	

				}

				

			}

			

			// stip off anchor links with #name			

			url = WYSIWYG_Core.stringToRegex(stripAnchorUrl);

			// exact replacing of url. regex: src="<url>"

			if(exact) {

				regex = eval("/(href=\")(" + url + ")(#[^\"]*)/gi");

				content = content.replace(regex, "$1$3");

			}

			// not exect replacing of url. regex: <url>

			else {

				regex = eval("/(" + url + ")(.+)/gi");

				content = content.replace(regex, "$2");	

			}

			

			

			// stip off anchor links with #name (only for local system)

			url = WYSIWYG_Core.getDocumentUrl(document);

			var pos = url.lastIndexOf("/");

			if(pos != -1) {

				url = url.substring(pos + 1, url.length);

				url = WYSIWYG_Core.stringToRegex(url);

				// exact replacing of url. regex: src="<url>"

				if(exact) {

					regex = eval("/(href=\")(" + url + ")(#[^\"]*)/gi");

					content = content.replace(regex, "$1$3");

				}

				// not exect replacing of url. regex: <url>

				else {

					regex = eval("/(" + url + ")(.+)/gi");

					content = content.replace(regex, "$2");	

				}

			}

		}

		

		return content;

	},	

		

	/* ---------------------------------------------------------------------- *\

	  Function    : updateTextArea()

	  Description : Updates the text area value with the HTML source of the WYSIWYG

	  Arguments   : n   - The editor identifier (the textarea's ID)

	\* ---------------------------------------------------------------------- */

	updateTextArea: function(n) {	

		// on update switch editor back to html mode

		if(this.viewTextMode[n]) { this.viewText(n); }

		// get inner HTML

		var content = this.getEditorWindow(n).document.body.innerHTML;

		// strip off defined URLs on IE

		content = this.stripURLPath(n, content);

		// replace all decimal color strings with hex color strings

		content = WYSIWYG_Core.replaceRGBWithHexColor(content);

		// remove line breaks before content will be updated

		if(this.config[n].ReplaceLineBreaks) { content = content.replace(/(\r\n)|(\n)/ig, ""); }

		// set content back in textarea

		$(n).value = content;

	},

		

	/* ---------------------------------------------------------------------- *\

	  Function    : hideToolbars()

	  Description : Hide all toolbars

	  Usage       : WYSIWYG.hideToolbars(n)

	  Arguments   : n - The editor identifier (the textarea's ID)

	\* ---------------------------------------------------------------------- */

	hideToolbars: function(n) {

		for(var i=0;i<this.config[n].Toolbar.length;i++) {

			var toolbar = $("toolbar" + i + "_" + n);

			if(toolbar) { toolbar.style.display = "none"; }

		}	

	},

	

	/* ---------------------------------------------------------------------- *\

	  Function    : showToolbars()

	  Description : Display all toolbars

	  Usage       : WYSIWYG.showToolbars(n)

	  Arguments   : n - The editor identifier (the textarea's ID)

	\* ---------------------------------------------------------------------- */

	showToolbars: function(n) {

		for(var i=0;i<this.config[n].Toolbar.length;i++) {

			var toolbar = $("toolbar" + i + "_" + n);

			if(toolbar) { toolbar.style.display = ""; }

		}	

	},

	

	/* ---------------------------------------------------------------------- *\

	  Function    : hideStatusBar()

	  Description : Hide the status bar

	  Usage       : WYSIWYG.hideStatusBar(n)

	  Arguments   : n - The editor identifier (the textarea's ID)

	\* ---------------------------------------------------------------------- */

	hideStatusBar: function(n) {

		var statusbar = $('wysiwyg_statusbar_' + n);

		if(statusbar) {	statusbar.style.display = "none"; }

	},

	

	/* ---------------------------------------------------------------------- *\

	  Function    : showStatusBar()

	  Description : Display the status bar

	  Usage       : WYSIWYG.showStatusBar(n)

	  Arguments   : n - The editor identifier (the textarea's ID)

	\* ---------------------------------------------------------------------- */

	showStatusBar: function(n) {

		var statusbar = $('wysiwyg_statusbar_' + n);

		if(statusbar) { statusbar.style.display = ""; }

	},

	

	/**

	 * Finds the node with the given tag name in the given range

	 * 

	 * @param {String} tagName Parent tag to find

	 * @param {Range} range Current range

	 */

	findParent: function(parentTagName, range){

		parentTagName = parentTagName.toUpperCase();

		var rangeWorking;

		var elmWorking = null;

		try {

			if(!WYSIWYG_Core.isMSIE) {

				var node = range.startContainer;	

				var pos = range.startOffset;

				if(node.nodeType != 3) { node = node.childNodes[pos]; }

				return WYSIWYG_Core.findParentNode(parentTagName, node);

			}

			else {

				elmWorking = (range.length > 0) ? range.item(0): range.parentElement();					

				elmWorking = WYSIWYG_Core.findParentNode(parentTagName, elmWorking);

				if(elmWorking != null) return elmWorking;

				

				rangeWorking = range.duplicate();

				rangeWorking.collapse(true);

				rangeWorking.moveEnd("character", 1);

				if (rangeWorking.text.length>0) {

					while (rangeWorking.compareEndPoints("EndToEnd", range) < 0){

			  			rangeWorking.move("Character");

			  			if (null != this.findParentTag(parentTagName, rangeWorking)){

			   				return this.findParentTag(parentTagName, rangeWorking);

			  			}

			 		}

			 	}

			 	return null;

			}

		}

		catch(e) {

			return null;

		}

	},

		

	/**

	 * Get the acutally tag of the given range

	 *

	 * @param {Range} range Current range

	 */

	getTag: function(range) {

		try {

		    if(!WYSIWYG_Core.isMSIE) {

				var node = range.startContainer;	

				var pos = range.startOffset;

				if(node.nodeType != 3) { node = node.childNodes[pos]; }

				

				if(node.nodeName && node.nodeName.search(/#/) != -1) {

					return node.parentNode;

				}

				return node;

			}

			else {

				if(range.length > 0) {

					return range.item(0);

				}

				else if(range.parentElement()) {

					return range.parentElement();

				}

			}

			return null;

		}

		catch(e) {

			return null;

		}

	},

	

	/**

	 * Get the parent node of the given node

	 * 

	 * @param {DOMElement} element - Element which parent will be returned

	 */

	getParent: function(element) {

		if(element.parentNode) {

			return element.parentNode;

		}

		return null;

	},

	

	/* ---------------------------------------------------------------------- *\

	  Function    : getTextRange()

	  Description : Get the text range object of the given element

	  Usage       : WYSIWYG.getTextRange(element)

	  Arguments   : element - An element of which you get the text range object

	\* ---------------------------------------------------------------------- */

	getTextRange: function(element){

		var range = element.parentTextEdit.createTextRange();

		range.moveToElementText(element);

		return range;

	},

	

	/* ---------------------------------------------------------------------- *\

	  Function    : invertIELineBreakCapability()

	  Description : Inverts the line break capability of IE (Thx to richyrich)

	  				Normal: ENTER = <p> , SHIFT + ENTER = <br>

	  				Inverted: ENTER = <br>, SHIFT + ENTER = <p>

	  Usage       : WYSIWYG.invertIELineBreakCapability(n)

	  Arguments   : n   - The editor identifier (the textarea's ID)

	\* ---------------------------------------------------------------------- */

	invertIELineBreakCapability: function(n) {

	

		var editor = this.getEditorWindow(n);

		var sel;

		// validate if the press key is the carriage return key

		if (editor.event.keyCode==13) {

	    	if (!editor.event.shiftKey) {

				sel = this.getRange(this.getSelection(n));

	            sel.pasteHTML("<br>");

	            editor.event.cancelBubble = true;

	            editor.event.returnValue = false;

	            sel.select();

	            sel.moveEnd("character", 1);

	            sel.moveStart("character", 1);

	            sel.collapse(false);

	            return false;

			}

	        else {

	            sel = this.getRange(this.getSelection(n));

	            sel.pasteHTML("<p>");

	            editor.event.cancelBubble = true;

	            editor.event.returnValue = false;

	            sel.select();

	            sel.moveEnd("character", 1);

	            sel.moveStart("character", 1);

	            sel.collapse(false);

	            return false;

	    	}

		}  

	},

	

	/* ---------------------------------------------------------------------- *\

	  Function    : selectNode()

	  Description : Select a node within the current editor

	  Usage       : WYSIWYG.selectNode(n, level)

	  Arguments   : n   - The editor identifier (the textarea's ID)

	  				level - identifies the level of the element which will be selected

	\* ---------------------------------------------------------------------- */

	selectNode: function(n, level) {

		

		var sel = this.getSelection(n);

		var range = this.getRange(sel);

		var parentnode = this.getTag(range);

		var i = 0;

		

		for (var node=parentnode; (node && (node.nodeType == 1)); node=node.parentNode) {

			if (i == level) {

				this.nodeSelection(n, node);

			}

			i++;

		}

		

		this.updateStatusBar(n);

	},

	

	/* ---------------------------------------------------------------------- *\

	  Function    : nodeSelection()

	  Description : Do the node selection

	  Usage       : WYSIWYG.nodeSelection(n, node)

	  Arguments   : n   - The editor identifier (the textarea's ID)

	  				node - The node which will be selected

	\* ---------------------------------------------------------------------- */

	nodeSelection: function(n, node) {

		

		var doc = this.getEditorWindow(n).document;

		var sel = this.getSelection(n);

		var range = this.getRange(sel);

		

		if(!WYSIWYG_Core.isMSIE) {

			if (node.nodeName == "BODY") {

				range.selectNodeContents(node);

			} else {

				range.selectNode(node);

			}



			/*

			if (endNode) {

				try {

					range.setStart(node, startOffset);

					range.setEnd(endNode, endOffset);

				} catch(e) {

				}

			}

			*/

			

			if (sel) { sel.removeAllRanges(); }

			if (sel) { sel.addRange(range);	 }

		}

		else {

			// MSIE may not select everything when BODY is selected - 

			// start may be set to first text node instead of first non-text node - 

			// no known workaround

			if ((node.nodeName == "TABLE") || (node.nodeName == "IMG") || (node.nodeName == "INPUT") || (node.nodeName == "SELECT") || (node.nodeName == "TEXTAREA")) {

				try {

					range = doc.body.createControlRange();

					range.addElement(node);

					range.select();

				} 

				catch(e) { }

			} 

			else {

				range = doc.body.createTextRange();

				if (range) {

					range.collapse();

					if (range.moveToElementText) {

						try {

							range.moveToElementText(node);

							range.select();

						} catch(e) {

							try {

								range = doc.body.createTextRange();

								range.moveToElementText(node);

								range.select();

							} 

							catch(e) {}

						}

					} else {

						try {

							range = doc.body.createTextRange();

							range.moveToElementText(node);

							range.select();

						} 

						catch(e) {}

					}

				}

			}

		}

	}

}



/********************************************************************

 * openWYSIWYG core functions Copyright (c) 2006 openWebWare.com

 * Contact us at devs@openwebware.com

 * This copyright notice MUST stay intact for use.

 *

 * $Id: wysiwyg.js,v 1.22 2007/09/08 21:45:57 xhaggi Exp $

 ********************************************************************/

var WYSIWYG_Core = {



	/**

	 * Holds true if browser is MSIE, otherwise false

	 */

	isMSIE: navigator.appName == "Microsoft Internet Explorer" ? true : false,



	/**

	 * Holds true if browser is Firefox (Mozilla)

	 */

	isFF: !document.all && document.getElementById && !this.isOpera,

	

	/**

	 * Holds true if browser is Opera, otherwise false

	 */

	isOpera: navigator.appName == "Opera" ? true : false,

	

	/**

	 * Trims whitespaces of the given string

	 *

	 * @param str String

	 * @return Trimmed string

	 */

	trim: function(str) {

		return str.replace(/^\s*|\s*$/g,"");

	},

	

	/**

	 * Determine if the given parameter is defined

	 * 

	 * @param p Parameter

	 * @return true/false dependents on definition of the parameter 

	 */

	defined: function(p) {

		return typeof p == "undefined" ? false : true;	

	},

	

	/**

	 * Determine if the browser version is compatible

	 *

	 * @return true/false depending on compatiblity of the browser

	 */

	isBrowserCompatible: function() {

		// Validate browser and compatiblity

		if ((navigator.userAgent.indexOf('Safari') != -1 ) || !document.getElementById || !document.designMode){   

			//no designMode (Safari lies)

	   		return false;

		} 

		return true;

	},

	

	/**

	 * Set the style attribute of the given element.

	 * Private method to solve the IE bug while setting the style attribute.

	 *

	 * @param {DOMElement} node The element on which the style attribute will affect

	 * @param {String} style Stylesheet which will be set

	 */

	_setStyleAttribute: function(node, style) {

		if(style == null) return;

		var styles = style.split(";");

		var pos;

		for(var i=0;i<styles.length;i++) {

			var attributes = styles[i].split(":");

			if(attributes.length == 2) {

				try {

					var attr = WYSIWYG_Core.trim(attributes[0]);

					while((pos = attr.search(/-/)) != -1) {

						var strBefore = attr.substring(0, pos);

						var strToUpperCase = attr.substring(pos + 1, pos + 2);

						var strAfter = attr.substring(pos + 2, attr.length);

						attr = strBefore + strToUpperCase.toUpperCase() + strAfter;

					}

					var value = WYSIWYG_Core.trim(attributes[1]).toLowerCase();

					node.style[attr] = value;

				}

				catch (e) {

					//alert(e);

				}

			}

		}

	},

	

	/**

	 * Fix's the issue while getting the attribute style on IE

	 * It's return an object but we need the style string

	 *

	 * @private

	 * @param {DOMElement} node Node element

	 * @return {String} Stylesheet

	 */

	_getStyleAttribute: function(node) {

		if(this.isMSIE) {

			return node.style['cssText'].toLowerCase();		

		}	

		else {

			return node.getAttribute("style");

		}

	},

	

	/**

	 * Set an attribute's value on the given node element.

	 *

	 * @param {DOMElement} node Node element

	 * @param {String} attr Attribute which is set

	 * @param {String} value Value of the attribute

	 */

	setAttribute: function(node, attr, value) {

		if(value == null || node == null || attr == null) return;

		if(attr.toLowerCase() == "style") {

			this._setStyleAttribute(node, value);

		}

		else {

			node.setAttribute(attr, value);

		}

	},

	

	/**

	 * Removes an attribute on the given node

	 * 

	 * @param {DOMElement} node Node element

	 * @param {String} attr Attribute which will be removed

	 */ 

	removeAttribute: function(node, attr) {

		node.removeAttribute(attr, false);

	},

	

	/**

	 * Get the vale of the attribute on the given node

	 * 

	 * @param {DOMElement} node Node element

	 * @param {String} attr Attribute which value will be returned

	 */

	getAttribute: function(node, attr) {

		if(node == null || attr == null) return;

		if(attr.toLowerCase() == "style") {

			return this._getStyleAttribute(node);

		}

		else {

			return node.getAttribute(attr);

		}

	},

	

	/**

	 * Get the path out of an given url

	 * 

	 * @param {String} url The url with is used to get the path

	 */

	getDocumentPathOfUrl: function(url) {

		var path = null;

		

		// if local file system, convert local url into web url

		url = url.replace(/file:\/\//gi, "file:///");

		url = url.replace(/\\/gi, "\/");

		var pos = url.lastIndexOf("/");

		if(pos != -1) {

			path = url.substring(0, pos + 1);

		}

		return path;

	},

	

	/**

	 * Get the documents url, convert local urls to web urls

	 * 

	 * @param {DOMElement} doc Document which is used to get the url

	 */

	getDocumentUrl: function(doc) {

		// if local file system, convert local url into web url

		var url = doc.URL;

		url = url.replace(/file:\/\//gi, "file:///");

		url = url.replace(/\\/gi, "\/");

		return url;

	},

	

	/**

	 * Find a parent node with the given name, of the given start node

	 * 

	 * @param {String} tagName - Tag name of the node to find

	 * @param {DOMElement} node - Node element

	 */

	findParentNode: function(tagName, node) {

		while (node.tagName != "HTML") {

	  		if (node.tagName == tagName){

	  			return node;

	  		} 

	  		node = node.parentNode;

	 	}

	 	return null;

	},

	

	/**

	 * Cancel the given event.

	 *

	 * @param e Event which will be canceled

	 */

	cancelEvent: function(e) {

		if (!e) return false;

		if (this.isMSIE) {

			e.returnValue = false;

			e.cancelBubble = true;

		} else {

			e.preventDefault();

			e.stopPropagation && e.stopPropagation();

		}

		return false;	

	},

	

	/**

	 * Converts a RGB color string to hex color string.

	 *

	 * @param color RGB color string

	 * @param Hex color string

	 */

	toHexColor: function(color) {

		color = color.replace(/^rgb/g,'');

		color = color.replace(/\(/g,'');

		color = color.replace(/\)/g,'');

		color = color.replace(/ /g,'');

		color = color.split(',');

		var r = parseFloat(color[0]).toString(16).toUpperCase();

		var g = parseFloat(color[1]).toString(16).toUpperCase();

		var b = parseFloat(color[2]).toString(16).toUpperCase();

		if (r.length<2) { r='0'+r; }

		if (g.length<2) { g='0'+g; }

		if (b.length<2) { b='0'+b; }

		return r + g + b;

	},

	

	/**

	 * Converts a decimal color to hex color string.

	 *

	 * @param Decimal color

	 * @param Hex color string

	 */

	_dec_to_rgb: function(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 nybble (4 bits)

			var nybble1 = (myByte >> 4) & 0x0F;   // get high nybble

			hex_string += nybble1.toString(16);   // convert nybble to hex

			hex_string += nybble2.toString(16);   // convert nybble to hex

		}

		return hex_string.toUpperCase();

	},

	

	/**

	 * Replace RGB color strings with hex color strings within a string.

	 * 

	 * @param {String} str RGB String

	 * @param {String} Hex color string

	 */

	replaceRGBWithHexColor: function(str) {

		if(str == null) return "";

		// find all decimal color strings

		var matcher = str.match(/rgb\([0-9 ]+,[0-9 ]+,[0-9 ]+\)/gi);

		if(matcher) {

			for(var j=0; j<matcher.length;j++) {

				var regex = eval("/" + WYSIWYG_Core.stringToRegex(matcher[j]) + "/gi");

				// replace the decimal color strings with hex color strings

				str = str.replace(regex, "#" + this.toHexColor(matcher[j]));

			}

		}

		return str;

	},

	

	/**

	 * Execute the given command on the given editor

	 * 

	 * @param n The editor's identifier

	 * @param cmd Command which is execute

	 */

	execCommand: function(n, cmd, value) {

		if(typeof(value) == "undefined") value = null;

		

		// firefox BackColor problem fixed

		if(cmd == 'BackColor' && WYSIWYG_Core.isFF) cmd = 'HiliteColor';

		

		// firefox cut, paste and copy

		if(WYSIWYG_Core.isFF && (cmd == "Cut" || cmd == "Paste" || cmd == "Copy")) {

			try {

				WYSIWYG.getEditorWindow(n).document.execCommand(cmd, false, value);

			}

			catch(e) {

				if(confirm("Copy/Cut/Paste is not available in Mozilla and Firefox\nDo you want more information about this issue?")) {

					window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html');

				}

			}

		}

		

		else {

			WYSIWYG.getEditorWindow(n).document.execCommand(cmd, false, value);

		}

	},

	

	/**

	 * Parse a given string to a valid regular expression

	 * 

	 * @param {String} string String to be parsed

	 * @return {RegEx} Valid regular expression

	 */

	stringToRegex: function(string) {

		

		string = string.replace(/\//gi, "\\/");

		string = string.replace(/\(/gi, "\\(");

		string = string.replace(/\)/gi, "\\)");

		string = string.replace(/\[/gi, "\\[");

		string = string.replace(/\]/gi, "\\]");

		string = string.replace(/\+/gi, "\\+");

		string = string.replace(/\$/gi, "\\$");

		string = string.replace(/\*/gi, "\\*");

		string = string.replace(/\?/gi, "\\?");

		string = string.replace(/\^/gi, "\\^");

		string = string.replace(/\\b/gi, "\\\\b");

		string = string.replace(/\\B/gi, "\\\\B");

		string = string.replace(/\\d/gi, "\\\\d");

		string = string.replace(/\\B/gi, "\\\\B");

		string = string.replace(/\\D/gi, "\\\\D");

		string = string.replace(/\\f/gi, "\\\\f");

		string = string.replace(/\\n/gi, "\\\\n");

		string = string.replace(/\\r/gi, "\\\\r");

		string = string.replace(/\\t/gi, "\\\\t");

		string = string.replace(/\\v/gi, "\\\\v");

		string = string.replace(/\\s/gi, "\\\\s");

		string = string.replace(/\\S/gi, "\\\\S");

		string = string.replace(/\\w/gi, "\\\\w");

		string = string.replace(/\\W/gi, "\\\\W");

		

		return string;			

	},

	

	/**

	 * Add an event listener

	 *

	 * @param obj Object on which the event will be attached

	 * @param ev Kind of event

	 * @param fu Function which is execute on the event

	 */

	addEvent: function(obj, ev, fu) {

		if (obj.attachEvent)

			obj.attachEvent("on" + ev, fu);

		else

			obj.addEventListener(ev, fu, false);

	},

	

	/**

	 * Remove an event listener

	 *

	 * @param obj Object on which the event will be attached

	 * @param ev Kind of event

	 * @param fu Function which is execute on the event

	 */

	removeEvent:  function(obj, ev, fu) {

		if (obj.attachEvent)

			obj.detachEvent("on" + ev, fu);

		else

			obj.removeEventListener(ev, fu, false);

	},

	

	/**

	 * Includes a javascript file

	 *

	 * @param file Javascript file path and name

	 */

	includeJS: function(file) {

		var script = document.createElement("script");

		this.setAttribute(script, "type", "text/javascript");

		this.setAttribute(script, "src", file);

		var heads = document.getElementsByTagName("head");

		for(var i=0;i<heads.length;i++) {

			heads[i].appendChild(script);		

		}

	},

	

	/**

	 * Includes a stylesheet file

	 *

	 * @param file Stylesheet file path and name

	 */

	includeCSS: function(path) {

		var link = document.createElement("link");

		this.setAttribute(link, "rel", "stylesheet");

		this.setAttribute(link, "type", "text/css");

		this.setAttribute(link, "href", path);

		var heads = document.getElementsByTagName("head");

		for(var i=0;i<heads.length;i++) {

			heads[i].appendChild(link);		

		}

	},

	

	/**

	 * Get the screen position of the given element.

	 * 

	 * @param {HTMLObject} elm1 Element which position will be calculate

	 * @param {HTMLObject} elm2 Element which is the last one before calculation stops

	 * @param {Object} Left and top position of the given element

	 */

	getElementPosition: function(elm1, elm2) {

		var top = 0, left = 0; 	

		while (elm1 && elm1 != elm2) {

			left += elm1.offsetLeft;

			top += elm1.offsetTop;

			elm1 = elm1.offsetParent;

		}

		return {left : left, top : top};

	},

	

	/**

	 * Get the window size

	 * @private

	 */

	windowSize: function() {

		if (window.innerWidth) {

	  		return {width: window.innerWidth, height: window.innerHeight};

	  	} 

		else if (document.body && document.body.offsetWidth) {

	  		return {width: document.body.offsetWidth, height: document.body.offsetHeight};

	  	} 

		else {

	  		return {width: 0, height: 0};

	  	}

	}

}



/**

 * Context menu object

 */

var WYSIWYG_ContextMenu = {

	

	html: "",

	contextMenuDiv: null,

	

	/**

	 * Init function

	 *

	 * @param {String} n Editor identifier

	 */

	init: function(n) {

		var doc = WYSIWYG.getEditorWindow(n).document;

			

		// create context menu div

		this.contextMenuDiv = document.createElement("div");

		this.contextMenuDiv.className = "wysiwyg-context-menu-div";

		this.contextMenuDiv.setAttribute("class", "wysiwyg-context-menu-div");

		this.contextMenuDiv.style.display = "none";

		this.contextMenuDiv.style.position = "absolute";

		this.contextMenuDiv.style.zIndex = 9999;

		this.contextMenuDiv.style.left = "0";

		this.contextMenuDiv.style.top = "0";

		this.contextMenuDiv.unselectable = "on";		

		document.body.insertBefore(this.contextMenuDiv, document.body.firstChild);

		

		// bind event listeners

		WYSIWYG_Core.addEvent(doc, "contextmenu", function context(e) { WYSIWYG_ContextMenu.show(e, n); });

		WYSIWYG_Core.addEvent(doc, "click", function context(e) { WYSIWYG_ContextMenu.close(); });

		WYSIWYG_Core.addEvent(doc, "keydown", function context(e) { WYSIWYG_ContextMenu.close(); });

		WYSIWYG_Core.addEvent(document, "click", function context(e) { WYSIWYG_ContextMenu.close(); });

	},

	

	/**

	 * Show the context menu

	 *

	 * @param e Event

	 * @param n Editor identifier

	 */

	show: function(e, n) {

		if(this.contextMenuDiv == null) return false;

		

		var ifrm = WYSIWYG.getEditor(n);

		var doc = WYSIWYG.getEditorWindow(n).document;

	

		// set the context menu position

		var pos = WYSIWYG_Core.getElementPosition(ifrm);		

		var x = WYSIWYG_Core.isMSIE ? pos.left + e.clientX : pos.left + (e.pageX - doc.body.scrollLeft);

		var y = WYSIWYG_Core.isMSIE ? pos.top + e.clientY : pos.top + (e.pageY - doc.body.scrollTop);

					

		this.contextMenuDiv.style.left = x + "px"; 

		this.contextMenuDiv.style.top = y + "px";

		this.contextMenuDiv.style.visibility = "visible";

		this.contextMenuDiv.style.display = "block";	

		

		// call the context menu, mozilla needs some time

		window.setTimeout("WYSIWYG_ContextMenu.output('" + n + "')", 10);

			

		WYSIWYG_Core.cancelEvent(e);

		return false;

	},

	

	/**

	 * Output the context menu items

	 *

	 * @param n Editor identifier

	 */

	output: function (n) {

												

		// get selection

		var sel = WYSIWYG.getSelection(n);

		var range = WYSIWYG.getRange(sel);

	

		// get current selected node					

		var tag = WYSIWYG.getTag(range);

		if(tag == null) { return; }

		

		// clear context menu

		this.clear();

		

		// Determine kind of nodes

		var isImg = (tag.nodeName == "IMG") ? true : false;

		var isLink = (tag.nodeName == "A") ? true : false;

		

		// Selection is an image or selection is a text with length greater 0

		var len = 0;

		if(WYSIWYG_Core.isMSIE)

			len = (document.selection && range.text) ? range.text.length : 0;

		else

			len = range.toString().length;

		var sel = len != 0 || isImg;

		

		// Icons

		var iconLink = { enabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["createlink"][3], disabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["createlink"][2]};

		var iconImage = { enabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["insertimage"][3], disabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["insertimage"][2]};

		var iconDelete = { enabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["delete"][3], disabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["delete"][2]};

		var iconCopy = { enabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["copy"][3], disabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["copy"][2]};

		var iconCut = { enabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["cut"][3], disabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["cut"][2]};

		var iconPaste = { enabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["paste"][3], disabled: WYSIWYG.config[n].ImagesDir + WYSIWYG.ToolbarList["paste"][2]};

		

		// Create context menu html

		this.html += '<table class="wysiwyg-context-menu" border="0" cellpadding="0" cellspacing="0">';

		

		// Add items

		this.addItem(n, 'Copy', iconCopy, 'Copy', sel);

		this.addItem(n, 'Cut', iconCut, 'Cut', sel);

		this.addItem(n, 'Paste', iconPaste, 'Paste', true);

		this.addSeperator();

		this.addItem(n, 'InsertImage', iconImage, 'Modify Image Properties...', isImg);

		this.addItem(n, 'CreateLink', iconLink, 'Create or Modify Link...', sel || isLink);

		this.addItem(n, 'RemoveNode', iconDelete, 'Remove', true);

		

		this.html += '</table>';

		this.contextMenuDiv.innerHTML = this.html;

	},

	

	/**

	 * Close the context menu

	 */

	close: function() {

		this.contextMenuDiv.style.visibility = "hidden";

		this.contextMenuDiv.style.display = "none";

	},

	

	/**

	 * Clear context menu

	 */

	clear: function() {

		this.contextMenuDiv.innerHTML = "";

		this.html = "";	

	},

		

	/**

	 * Add context menu item 

	 * 

	 * @param n editor identifier

	 * @param cmd Command

	 * @param icon Icon which is diabled

	 * @param title Title of the item

	 * @param disabled If item is diabled

	 */

	addItem: function(n, cmd, icon, title, disabled) {

		var item = '';

		

		if(disabled) {

			item += '<tr>';

			item += '<td class="icon"><a href="javascript:WYSIWYG.execCommand(\'' + n + '\',\'' + cmd + '\', null);"><img src="' + icon.enabled + '" border="0"></a></td>';

			item += '<td onmouseover="this.className=\'mouseover\'" onmouseout="this.className=\'\'" onclick="WYSIWYG.execCommand(\'' + n + '\', \'' + cmd + '\', null);WYSIWYG_ContextMenu.close();"><a href="javascript:void(0);">' + title + '</a></td>';

			item += '</tr>';

		}

		else {

			item += '<tr>';

			item += '<td class="icon"><img src="' + icon.disabled + '" border="0"></td>';

			item += '<td onmouseover="this.className=\'mouseover\'" onmouseout="this.className=\'\'"><span class="disabled">' + title + '</span></td>';

			item += '</tr>';

		}

		

		this.html += item;

	},

	

	/**

	 * Add seperator to context menu

	 */

	addSeperator: function() {

		var output = '';

		output += '<tr>';

		output += '<td colspan="2" style="text-align:center;"><hr size="1" color="#C9C9C9" width="95%"></td>';

		output += '</tr>';

		this.html += output;

	}

}



/**

 * Table object

 */

var WYSIWYG_Table = {



	/**

	 * 

	 */

	create: function(n, tbl) {

		

		// get editor

		var doc = WYSIWYG.getEditorWindow(n).document;

		// get selection and range

		var sel = WYSIWYG.getSelection(n);

		var range = WYSIWYG.getRange(sel);

		var table = null;

				

		// get element from selection

		if(WYSIWYG_Core.isMSIE) {

			if(sel.type == "Control" && range.length == 1) {	

				range = WYSIWYG.getTextRange(range(0));

				range.select();

			}

		}



		// find a parent TABLE element

		//table = WYSIWYG.findParent("table", range);

				

		// check if parent is found

		//var update = (table == null) ? false : true;

		//if(!update) table = tbl;

		table = tbl;

		

		// add rows and cols

		var rows = WYSIWYG_Core.getAttribute(tbl, "tmprows");

		var cols = WYSIWYG_Core.getAttribute(tbl, "tmpcols");

		WYSIWYG_Core.removeAttribute(tbl, "tmprows");

		WYSIWYG_Core.removeAttribute(tbl, "tmpcols");
		
		var style = WYSIWYG_Core.getAttribute(tbl, "style");

		for(var i=0;i<rows;i++) {

			var tr = doc.createElement("tr");

			for(var j=0;j<cols;j++){

				var td = createTD(style);

				tr.appendChild(td);	

			}

			table.appendChild(tr);

		}

		

		// on update exit here

		//if(update) { return; }

	

		// Check if IE or Mozilla (other)

		if (WYSIWYG_Core.isMSIE) {

			range.pasteHTML(table.outerHTML);   

		}

		else {

			WYSIWYG.insertNodeAtSelection(table, n);

		}

		

		// refresh table highlighting

		this.refreshHighlighting(n);

		

		

		

		

	 	// functions

		function createTD(style) {

			//var style = WYSIWYG_Core.getAttribute(n, "style");	
		
			var td = doc.createElement("td");

			td.innerHTML = "&nbsp;";
			
			//td.style = "border:1px dashed #AAAAAA;";
			WYSIWYG_Core.setAttribute(td, "style", style);
			
			return td;

		}

	 	

	},



	/**

	 * Enables the table highlighting

	 * 

	 * @param {String} n The editor identifier (the textarea's ID)

	 */

	refreshHighlighting: function(n) {

		var doc = WYSIWYG.getEditorWindow(n).document;

		var tables = doc.getElementsByTagName("table");	

		for(var i=0;i<tables.length;i++) {

			this._enableHighlighting(tables[i]);

		}

		var tds = doc.getElementsByTagName("td");	

		for(var i=0;i<tds.length;i++) {

			this._enableHighlighting(tds[i]);

		}

	},

	

	/**

	 * Enables the table highlighting

	 * 

	 * @param {String} n The editor identifier (the textarea's ID)

	 */

	disableHighlighting: function(n) {

		var doc = WYSIWYG.getEditorWindow(n).document;

		var tables = doc.getElementsByTagName("table");	

		for(var i=0;i<tables.length;i++) {

			this._disableHighlighting(tables[i]);

		}

		var tds = doc.getElementsByTagName("td");	

		for(var i=0;i<tds.length;i++) {

			this._disableHighlighting(tds[i]);

		}

	

	},

	

	/**

	 * @private

	 */

	_enableHighlighting: function(node) {

		var style = WYSIWYG_Core.getAttribute(node, "style");	

		if(style == null) style = " ";

		//alert("ENABLE: ELM = " + node.tagName + "; STYLE = " + style);

		//WYSIWYG_Core.removeAttribute(node, "prevstyle");

		//WYSIWYG_Core.setAttribute(node, "prevstyle", style);

		//WYSIWYG_Core.setAttribute(node, "style", "border:1px dashed #AAAAAA;");
		
		WYSIWYG_Core.setAttribute(node, "style", style);

	},

	

	/**

	 * @private

	 */

	_disableHighlighting: function(node) {

		var style = WYSIWYG_Core.getAttribute(node, "prevstyle");

		//alert("DISABLE: ELM = " + node.tagName + "; STYLE = " + style);

		// if no prevstyle is defined, the table is not in highlighting mode

		if(style == null || style == "") { 

			this._enableHighlighting(node); 

			return; 

		}			

		WYSIWYG_Core.removeAttribute(node, "prevstyle");

		WYSIWYG_Core.removeAttribute(node, "style");

		WYSIWYG_Core.setAttribute(node, "style", style);

	}

}





/**

 * Get an element by it's identifier

 *

 * @param id Element identifier

 */

function $(id) {

	return document.getElementById(id);

}



/**

 * Emulates insertAdjacentHTML(), insertAdjacentText() and 

 * insertAdjacentElement() three functions so they work with Netscape 6/Mozilla

 * by Thor Larholm me@jscript.dk

 */

if(typeof HTMLElement!="undefined" && !HTMLElement.prototype.insertAdjacentElement){

	HTMLElement.prototype.insertAdjacentElement = function (where,parsedNode) {

	  switch (where){

		case 'beforeBegin':

			this.parentNode.insertBefore(parsedNode,this);

			break;

		case 'afterBegin':

			this.insertBefore(parsedNode,this.firstChild);

			break;

		case 'beforeEnd':

			this.appendChild(parsedNode);

			break;

		case 'afterEnd':

			if (this.nextSibling) { 

				this.parentNode.insertBefore(parsedNode,this.nextSibling); 

			}

			else { 

				this.parentNode.appendChild(parsedNode); 

			}

			break;

	  }

	};



	HTMLElement.prototype.insertAdjacentHTML = function (where,htmlStr) {

		var r = this.ownerDocument.createRange();

		r.setStartBefore(this);

		var parsedHTML = r.createContextualFragment(htmlStr);

		this.insertAdjacentElement(where,parsedHTML);

	};





	HTMLElement.prototype.insertAdjacentText = function (where,txtStr) {

		var parsedText = document.createTextNode(txtStr);

		this.insertAdjacentElement(where,parsedText);

	};

}








