
var WYSIWYG = {

    /**
	 * Settings class, holds all customizeable properties
	 */
    Settings: function()
    {

        // Images Directory
        this.ImagesDir = "../images/icons/";

        // Popups Directory
        this.PopupsDir = "";

        // CSS Directory File
        this.CSSFile = "../includes/styles/wysiwyg.css";

        // Default WYSIWYG width and height (use px or %)
        this.Width = "780px";
        this.Height = "350px";

        // 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 = 500;
        this.PreviewHeight = 400;

        // 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;

        // Insert image implementation
        this.FilePopupFile = "";
        this.FilePopupWidth = 0;
        this.FilePopupHeight = 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"
            );
        this.Toolbar[1] = new Array(
            "save",
            // "return",  // return button disabled by default
            "seperator",
            "subscript",
            "superscript",
            "seperator",
            "cut",
            "copy",
            "paste",
            "removeformat",
            "seperator",
            "undo",
            "redo",
            "seperator",
            "inserttable",
            "insertimage",
            "insertfile",
            "createlink",
            "seperator",
            "preview",
            "print",
            "seperator",
            "viewSource",
            "maximize",
            "seperator",
            "help"
            );

        // 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'],
        "insertfile":    ['InsertFile',          'Insert File',        	'insert_file.gif',     'insert_file_on.gif'],
        "createlink":     ['CreateLink',           'Create Link',         	'insert_hyperlink.gif',   'insert_hyperlink_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)

    {
        var lastIndex=src.lastIndexOf(".");
        var fileFormat=src.substring(lastIndex+1, src.length);
          
      
        // 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;

        if(fileFormat!="doc" && fileFormat!="pdf" && fileFormat!="xls")
        {
            // 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);
            }
        }
        else
        {

       
            // 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 update1 = (lin == null) ? false : true;
            if(!update1) {
                lin = doc.createElement("a");
            }

            // set the attributes
            WYSIWYG_Core.setAttribute(lin, "href", src);

            // on update exit here
            if(update1) {
                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);
            }
        }
		

    },



    insertFile: 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);
        }
    },

    /**
	 * 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.jsp';
        var imagePopupWidth = 500;
        var imagePopupHeight = 300;
        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;
        }

        // Check the insert image popup implementation
        var filePopupFile = this.config[n].PopupsDir + 'insert_file.jsp';
        var filePopupWidth = 470;
        var filePopupHeight = 200;
        if(typeof this.config[n].FilePopupFile != "undefined" && this.config[n].FilePopupFile != "") {
            filePopupFile = this.config[n].FilePopupFile;
        }
        if(typeof this.config[n].FilePopupWidth && this.config[n].FilePopupWidth > 0) {
            filePopupWidth = this.config[n].FilePopupWidth;
        }
        if(typeof this.config[n].FilePopupHeight && this.config[n].FilePopupHeight > 0) {
            filePopupHeight = this.config[n].FilePopupHeight;
        }

        // 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;

            // InsertFile
            case "InsertFile":
                window.open(filePopupFile + '?wysiwyg=' + n, 'popup', 'location=0,status=0,scrollbars=0,resizable=0,width=' + filePopupWidth + ',height=' + filePopupHeight + ',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=200,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");
        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 $(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);
    };
}




