/********************************************************************
 * openWYSIWYG v1.47 Copyright (c) 2006 openWebWare.com 
 * Contact us at devs@openwebware.com
 * This copyright notice MUST stay intact for use.
 *
 * $Id: openwysiwyg.modified.js,v 1.6 2009/05/07 17:27:34 thenicespider Exp $
 * $Revision: 1.6 $
 *
 * 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() {
  this.ImagesDir = "/images/"; //Images Directory
  this.PopupsDir = "/popups/"; // Popups Directory
  this.CSSFile   = "/styles/wysiwyg.css"; //CSS Directory File
  this.Width     = "450px"; // Default width and height (use px or %)
  this.Height    = "200px";
  this.DefaultStyle = "font-family:Arial; font-size:12px; background-color:#FFFFFF"; //Default styles of WYSIWYG window
  this.DisabledStyle = "font-family:Arial; font-size:12px; background-color:#EEEEEE"; //Style if editor is disabled
  this.PreviewWidth  = 500; // Width + Height of the preview window
  this.PreviewHeight = 400;
	this.RemoveFormatConfMessage = "Clean HTML inserted by MS Word ?"; //Strip any HTML added by word
  this.NoValidBrowserMessage   = "The WYSIWYG editor does not support your browser."; // if browser is not supported
  
  // 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 = ""; 
  
  // 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";  
  this.ContextMenu = true; // Enable/Disable the custom context menu
  
  // Status bar update. Within the status bar node tree of the actually selected element will build
  // 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.StatusBarEnabled = true; 
  
  this.InvertIELineBreaks = false;
  this.ReplaceLineBreaks  = false; // Replace line breaks with <br> tags
  this.Opener = "index.php"; // Page that opened the WYSIWYG (Used for the return command)
  this.ImagePopupFile = "";
  this.ImagePopupWidth  = 600;
  this.ImagePopupHeight = 245;
  this.Toolbar = new Array(); // Holds the available buttons displayed on the toolbar of the editor
  this.Toolbar[0] = new Array(
   "fonts", "fontsizes", "bold", "italic", "underline", "strikethrough","seperator", 
   "forecolor", "backcolor", "seperator", "justifyleft", "justifycenter", "justifyright", "seperator", 
   "unorderedlist", "orderedlist", "outdent", "indent"
  );
  this.Toolbar[1] = new Array(
   // "save", //Wendy: drupal no need this
   // "return", // return button disabled by default
   "seperator", "headings", "seperator", "subscript", "superscript", "seperator", "cut", "copy", "paste","removeformat",
   "seperator", "undo", "redo", "seperator", "inserttable", "createlink", 
   "seperator", "preview", "print"
 );
 
 // DropDowns
 this.DropDowns = new Array();
 // Fonts
 this.DropDowns['fonts'] = {
  id: "fonts",
  command: "FontName",
  label: "<font style=\"font-family:{value};font-size:12px;\">{value}</font>",
  width: "54px",
  elements: new Array("Arial","Sans Serif","Tahoma","Verdana","Courier New","Georgia","Times New Roman","Impact","Comic Sans MS")
 };
 // Font sizes
 this.DropDowns['fontsizes'] = { 
  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: "42px",
  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.gif'],
 "italic" :['Italic','Italic','italic.gif','italic.gif'],
 "underline" :['Underline','Underline','underline.gif','underline.gif'],
 "strikethrough":['Strikethrough','Strikethrough','strikethrough.gif','strikethrough.gif'],
 "seperator":['','','seperator.gif','seperator.gif'],
 "subscript":['Subscript','Subscript','subscript.gif','subscript.gif'],
 "superscript":['Superscript','Superscript','superscript.gif','superscript.gif'],
 "justifyleft":['Justifyleft','Justifyleft','justifyleft.gif','justifyleft.gif'],
 "justifycenter":['Justifycenter','Justifycenter','justifycenter.gif','justifycenter.gif'],
 "justifyright":['Justifyright','Justifyright','justifyright.gif','justifyright.gif'],
 "justifyfull":['Justifyfull','Justifyfull','Justifyfull.gif','Justifyfull.gif'],
 "unorderedlist":['InsertUnorderedList','Insert Unordered List','unorderedlist.gif','unorderedlist.gif'],
 "orderedlist":['InsertOrderedList','Insert Ordered List','orderedlist.gif','orderedlist.gif'],
 "outdent":['Outdent','Outdent','outdent.gif','outdent.gif'],
 "indent":['Indent','Indent','indent.gif','indent.gif'],
 "cut":['Cut','Cut','cut.gif','cut.gif'],
 "copy":['Copy','Copy','copy.gif','copy.gif'],
 "paste":['Paste','Paste','paste.gif','paste.gif'],
 "forecolor":['ForeColor','Fore Color','forecolor.gif','forecolor.gif'],
 "backcolor":['BackColor','Back Color','backcolor.gif','backcolor.gif'],
 "undo":['Undo','Undo','undo.gif','undo.gif'],
 "redo":['Redo','Redo','redo.gif','redo.gif'],
 "inserttable":['InsertTable','Insert Table','inserttable.gif','inserttable.gif'],
 "insertimage":['InsertImage','Insert Image','insertimage.gif','insertimage.gif'],
 "createlink":['CreateLink','Create Link','createlink.gif','createlink.gif'],
 "viewSource":['ViewSource','View Source','viewsource.gif','viewsource.gif'],
 "viewText":['ViewText','View Text','viewtext.gif','viewtext.gif'],
 "teaser":['Teaser','Teaser','teaser.gif','teaser.gif'],
 "help":['Help','Help','help.gif','help.gif'],
 "fonts":['Fonts','Select Font','fonts.gif','fonts_on.gif'],
 "fontsizes":['Fontsizes','Select Size','fontsizes.gif','fontsizes_on.gif'],
 "headings":['Headings','Select Size','headings.gif','headings_on.gif'],
 "preview":['Preview','Preview','preview.gif','preview.gif'],
 "print":['Print','Print','print.gif','print.gif'],
 "removeformat":['RemoveFormat','Strip Word HTML','removeformat.gif','removeformat.gif'],
 "delete":['Delete','Delete','delete.gif','delete.gif'],
 //"save":['Save','Save document','save.gif','save.gif'],
 //"return":['Return','Return without saving','return.gif','return.gif'],
 "maximize":['Maximize','Maximize the editor','maximize.gif','maximize.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: new Array(), // maximized
 
 // 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 $_openwysiwyg("wysiwyg_div_" + n);
 },
 
 // Return the editor table element
 // @param {String} n Editor identifier 
 // @return {HtmlTableElement} Iframe object
 getEditorTable: function(n) {
 return $_openwysiwyg("wysiwyg_table_" + n);
 },
 
 // Get the iframe object of the WYSIWYG editor
 // @param {String} n Editor identifier 
 // @return {HtmlIframeElement} Iframe object
 getEditor: function(n) {
 return $_openwysiwyg("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) {
 
 var doc = this.getEditorWindow(n).document; // get editor
 var sel = this.getSelection(n); // get selection and range
 var range = this.getRange(sel);
 var img = this.findParent("img", range); // the current tag of range
 var update = (img == null) ? false : true; // element is not a link
 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");
 
 if(update) { return; }  // on update exit here
 
 if (WYSIWYG_Core.isMSIE) { range.pasteHTML(img.outerHTML); } // Check if IE or Mozilla (other)
 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) {
 
 var doc = this.getEditorWindow(n).document; // get editor
 var sel = this.getSelection(n); // get selection and range
 var range = this.getRange(sel);
 var lin = null;
 
 if(WYSIWYG_Core.isMSIE) { // get element from selection
  if(sel.type == "Control" && range.length == 1) { 
  range = this.getTextRange(range(0));
  range.select();
  }
 }

 lin = this.findParent("a", range); // find a as parent element
  
 var update = (lin == null) ? false : true; // check if parent is found
 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);
 
 if(update) { return; } // on update exit here
 
 if (WYSIWYG_Core.isMSIE) {  // Check if IE or Mozilla (other)
  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) {
  
 
 var textarea = $_openwysiwyg(n); // Get the textarea element
 
 if(textarea == null) { // Validate if textarea exists
  alert("No textarea found with the given identifier (ID: " + n + ").");
  return;
 }
 
 if(!WYSIWYG_Core.isBrowserCompatible()) {  // Validate browser compatiblity
  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; }
 
 textarea.style.display = "none"; // Hide the textarea 
 
 // 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 } 
  
 var currentWidth = this.config[n].Width; // determine the width + height
 var currentHeight = this.config[n].Height;
 var ifrmWidth = "100%"; // Calculate the width + height of the editor
 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';
 
 textarea.insertAdjacentHTML("afterEnd", iframe); // Insert after the textArea both toolbar one and two
   
 var content = textarea.value; // Pass the textarea's existing text over to the content variable
 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) {
    
 var textarea = $_openwysiwyg(n); // Get the textarea element
 if(textarea == null) { // Validate if textarea exists
  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;
 }
    
 textarea.style.display = 'none'; // Hide the textarea 
 
 // 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
 }
  
 var currentWidth = this.config[n].Width; // determine the width + height
 var currentHeight = this.config[n].Height;
 var toolbarWidth = currentWidth; // Calculate the width + height of the editor 
 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 + 'viewtext.gif" border="0" unselectable="on" title="viewText" id="ViewText" class="buttonEditor" onmouseover="this.className=\'buttonEditorOver\'; this.src=\'' + this.config[n].ImagesDir + 'viewtext.gif\';" onmouseout="this.className=\'buttonEditor\'; this.src=\'' + this.config[n].ImagesDir + 'viewtext.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($_openwysiwyg("textMode" + n)) {
  $_openwysiwyg("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 = $_openwysiwyg("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.html';
 var imagePopupWidth = 400;
 // var imagePopupHeight = 210;
 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=0,resizable=0,width=' + imagePopupWidth + ',height=' + imagePopupHeight + ',top=' + popupPosition.top + ',left=' + popupPosition.left).focus();
  break;
  */
   case "InsertImage":
    window.open('/addons/imagelibrary/insert_image.php'+'?wysiwyg='+n,'popup',
     'location=0,status=0,scrollbars=0,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;
  
  // 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;
  
  // Teaser
  case "teaser":
  this.insertNodeAtSelection('<!--break-->', n);
  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="$_openwysiwyg(\'img_' + dropdown.id + '_' + n + '\').src=\'' + imageOn + '\';" onMouseOut="$_openwysiwyg(\'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($_openwysiwyg(divId)) $_openwysiwyg(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($_openwysiwyg(divId).style.display == "none") { 
  $_openwysiwyg(divId).style.display = "block"; 
 }
 else {
  $_openwysiwyg(divId).style.display = "none"; 
 }
 $_openwysiwyg(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($_openwysiwyg('HTMLMode' + n)) {
   $_openwysiwyg('HTMLMode' + n).style.display = 'none'; 
 }
   if($_openwysiwyg('textMode' + n)) {
   $_openwysiwyg('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($_openwysiwyg('textMode' + n)) {
  $_openwysiwyg('textMode' + n).style.display = 'none'; 
 }
 if($_openwysiwyg('HTMLMode' + n)) {
  $_openwysiwyg('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
 $_openwysiwyg(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 = $_openwysiwyg("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 = $_openwysiwyg("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 = $_openwysiwyg('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 = $_openwysiwyg('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: openwysiwyg.modified.js,v 1.6 2009/05/07 17:27:34 thenicespider 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");
 for(var i=0;i<rows;i++) {
  var tr = doc.createElement("tr");
  for(var j=0;j<cols;j++){
  var td = createTD();
  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() {
  var td = doc.createElement("td");
  td.innerHTML = "&nbsp;";
  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;");
 },
 
 /**
 * @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 $_openwysiwyg(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);
 };
}
