/********************************************************************
 * openWYSIWYG v1.46c Copyright (c) 2006 openWebWare.com
 * Contact us at devs@openwebware.com
 * This copyright notice MUST stay intact for use.
 *
 * $Id: wysiwyg.js,v 1.10 2006/12/25 09:17:07 xhaggi Exp $
 *
 * An open source WYSIWYG editor for use in web based applications.
 * For full source code and docs, visit http://www.openwebware.com
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along
 * with this library; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ********************************************************************/
var WYSIWYG = {

        /**
         * Settings class, holds all customizeable properties
         */
        Settings: function() {

                // Images Directory
                this.ImagesDir = "openwysiwyg/images/";

                // Popups Directory
                this.PopupsDir = "openwysiwyg/popups/";

                // CSS Directory File
                this.CSSFile = "openwysiwyg/styles/wysiwyg.css";

                // Default WYSIWYG width and height (use px or %)
                this.Width = "500px";
                this.Height = "200px";

                // Default stylesheet of the WYSIWYG editor window
                this.DefaultStyle = "font-family: Verdana; font-size: 10px; background-color: #FFFFFF";

                // Stylesheet if editor is disabled
                this.DisabledStyle = "font-family: Verdana; font-size: 10px; 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 = "Eliminare i tag HTML dal testo?";

                // Nofication if browser is not supported by openWYSIWYG, leave it blank for no message output.
                this.NoValidBrowserMessage = "openWYSIWYG non è supportata su questo 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 = "";

                // 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 = "";

                // 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 = false;

                // 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;

                // Insert image implementation
                this.ImagePopupFile = "";
                this.ImagePopupWidth = 0;
                this.ImagePopupHeight = 0;

                // Holds the available buttons displayed
                // on the toolbar of the editor
                this.Toolbar = new Array();
                this.Toolbar[0] = new Array(
                        "font",
                        "fontsize",
                        "bold",
                        "italic",
                        "underline",
                        "strikethrough",
                        "seperator",
                        "forecolor",
                        "backcolor",
                        "seperator",
                        "justifyleft",
                        "justifycenter",
                        "justifyright",
                        "miGiustifichi",
                        "seperator",
                        "unorderedlist",
                        "orderedlist",
                        "outdent",
                        "indent"
                );
                this.Toolbar[1] = new Array(
                        "subscript",
                        "superscript",
                        "seperator",
                        "cut",
                        "copy",
                        "paste",
                        "removeformat",
                        "seperator",
                        "inserttable",
                        "insertimage",
                        "createlink",
                        "seperator",
                        "preview",
                        "print",
                        "seperator",
                        "viewSource"
                );

                // List of available font types
            this.Fonts = new Array(
                        "Arial",
                        "Sans Serif",
                        "Tahoma",
                        "Verdana",
                        "Courier New",
                        "Georgia",
                        "Times New Roman",
                        "Impact",
                        "Comic Sans MS"
                );

                // List of available font sizes
            this.Fontsizes = new Array(
                        "1",
                        "2",
                        "3",
                        "4",
                        "5",
                        "6",
                        "7"
                );

                // 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',                 'Grassetto',                  'bold.gif',               'bold_on.gif'],
        "italic":         ['Italic',               'Corsivo',                    'italics.gif',            'italics_on.gif'],
        "underline":      ['Underline',            'Sottolineato',               'underline.gif',          'underline_on.gif'],
        "strikethrough":  ['Strikethrough',        'Barrato',                    'strikethrough.gif',      'strikethrough_on.gif'],
        "seperator":      ['',                     '',                           'seperator.gif',          'seperator.gif'],
        "subscript":      ['Subscript',            'Pedice',                     'subscript.gif',          'subscript_on.gif'],
        "superscript":    ['Superscript',          'Apice',                      'superscript.gif',        'superscript_on.gif'],
        "justifyleft":    ['Justifyleft',          'Giustificato sinistra',      'justify_left.gif',       'justify_left_on.gif'],
        "justifycenter":  ['Justifycenter',        'Giustificato in centro',     'justify_center.gif',     'justify_center_on.gif'],
        "justifyright":   ['Justifyright',         'Giustificato a destra',      'justify_right.gif',      'justify_right_on.gif'],
        "miGiustifichi":  ['miGiustifichi',        'Giustificato',               'justify.gif',            'justify_on.gif'],
        "unorderedlist":  ['InsertUnorderedList',  'Lista',                      'list_unordered.gif',     'list_unordered_on.gif'],
        "orderedlist":    ['InsertOrderedList',    'Lista numerica',             'list_ordered.gif',       'list_ordered_on.gif'],
        "outdent":        ['Outdent',              'Riduci rientro',             'indent_left.gif',        'indent_left_on.gif'],
        "indent":         ['Indent',               'Aumenta rientro',            'indent_right.gif',       'indent_right_on.gif'],
        "cut":            ['Cut',                  'Taglia',                     'cut.gif',                'cut_on.gif'],
        "copy":           ['Copy',                 'Copia',                      'copy.gif',               'copy_on.gif'],
        "paste":          ['Paste',                'Incolla',                    'paste.gif',              'paste_on.gif'],
        "forecolor":      ['ForeColor',            'Colore testo',               'forecolor.gif',          'forecolor_on.gif'],
        "backcolor":      ['BackColor',            'Colore di sfondo',           'backcolor.gif',          'backcolor_on.gif'],
        "undo":           ['Undo',                 'Anulla operazione',          'undo.gif',               'undo_on.gif'],
        "redo":           ['Redo',                 'Ripeti operazione',          'redo.gif',               'redo_on.gif'],
        "inserttable":    ['InsertTable',          'Insrisci tabella',           'insert_table.gif',       'insert_table_on.gif'],
        "insertimage":    ['InsertImage',          'inserisci immagine',         'insert_picture.gif',     'insert_picture_on.gif'],
        "createlink":     ['CreateLink',           'Crea link',                  'insert_hyperlink.gif',   'insert_hyperlink_on.gif'],
        "viewSource":     ['ViewSource',           'Editor testuale',            'view_source.gif',        'view_source_on.gif'],
        "viewText":       ['ViewText',             'Editor grafico',             'view_text.gif',          'view_text_on.gif'],
        "help":           ['Help',                 'Aiuto',                      'help.gif',               'help_on.gif'],
        "selectfont":     ['SelectFont',           'Seleziona font',             'select_font.gif',        'select_font_on.gif'],
        "selectsize":     ['SelectSize',           'Seleziona dimensione font',  'select_size.gif',        'select_size_on.gif'],
        "preview":        ['Preview',              'Anteprima',                  'preview.gif',            'preview_on.gif'],
        "print":          ['Print',                'Stampa',                     'print.gif',              'print_on.gif'],
        "removeformat":   ['RemoveFormat',         'Elimina HTML',               'remove_format.gif',      'remove_format_on.gif'],
        "delete":         ['Delete',               'Cancella',                   'delete.gif',             'delete_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(),

        /**
         * 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);
        },

        /**
         * Get the iframe object of the WYSIWYG editor
         *
         * @param {String} n Editor identifier
         * @return {HtmlIframeObject} Iframe object
         */
        getEditor: function(n) {
                return $("wysiwyg" + n);
        },

        /**
         * Get editors window element
         *
         * @param {String} n Editor identifier
         * @return {Object} 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;
                }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : insertImage()
          Description : insert an image into WYSIWYG in rich text
          Usage       : WYSIWYG.insertImage("test.jpg", 500, 200, "center", 0, "Picture Alternativ", 5, 5, "textareaID")
          Arguments   : src - Source of the image
                                          width - Width
                                        height - Height
                                        align - Alignment of the image
                                        border - border
                                        alt - Alternativ Text
                                        hspace - Horizontal Space
                                        vspace - Vertical Space
                        n  - The editor identifier (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        insertImage: function(src, n) {

                // get editor
                var doc = this.getEditorWindow(n).document;
                // get selection and range
                var sel = this.getSelection(n);
                var range = this.getRange(sel);

                // the current tag of range
                var img = this.findParentTag("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);
                }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : insertLink()
          Description : insert a link into WYSIWYG in rich text
          Usage       : WYSIWYG.insertLink("http://www.google.de", "_blank", "", "", "", "textareaID")
          Arguments   : href - The link url
                                          target - Target of the link
                                        style - Stylesheet of the link
                                        styleClass - Stylesheet class of the link
                                        name - Name attribute of the link
                        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.findParentTag("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);
                }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : removeFormat()
          Description : Strip any HTML added by word
          Usage       : removeFormat(n)
          Arguments   : 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;
        },


        /* ---------------------------------------------------------------------- *\
          Function    : justifyText()
          Description : justify the text left and right side
          Usage       : justifyText(n)
          Arguments   : n  - The editor identifier (the textarea's ID)
          Add by      : Alberto Guzzetti (kodyfile@gmail.com)
        \* ---------------------------------------------------------------------- */
        justifyText: function(n) {

                      // // Check if IE or Mozilla (other)
                      if(!WYSIWYG_Core.isMSIE) {
                          alert("Il comando è supportato solo da Internet Explorer.");
                          return;
                      }

                      var doc = this.getEditorWindow(n).document;
                      var breakbefore = 0;

                      // get selection and range
                      var sel = this.getSelection(n);
                      var range = this.getRange(sel);
                      var lin = null;

                      // get element from selection
                      if(sel.type == "Control" && range.length == 1) {
                         range = this.getTextRange(range(0));
                         range.select();
                      }

                      // get text selected
                      lin = range.text;
                      if(!lin) {
                          lin = doc.body.innerHTML;
                          breakbefore = 1;
                      }

                      // apply the style
                      lin = lin.replace(/<p([^>])*>(&nbsp;)*\s*<\/p>/gi, '');
                      lin = lin.replace(/<p[^>]*>/gi, '');
                      lin = lin.replace(/<\/p[^>]*>/gi, '');
                      lin = "<P align=justify>" + lin + "</P>";

                      // selected range or all text
                      if(breakbefore) {
                         doc.body.innerHTML = lin;
                      }else{
                         range.pasteHTML(lin);
                      }
        },


        /**
         * Display an iframe instead of the textarea.
         *
         * @param n - ID of textarea to replace
         * @param 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
         *
         * @param n - ID of textarea to replace
         * @param 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 += '<table border="0" cellpadding="0" cellspacing="0" class="tableTextareaEditor" id="wysiwyg_table_' + n + '" style="width:' + currentWidth  + '; height:' + currentHeight + ';">';
            editor += '<tr><td>';

                // 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>';

                                for (var i = 0; i < toolbar.length;i++) {
                                    if (toolbar[i]) {
                                            // Font selection
                                                if (toolbar[i] == "font"){
                                                        editor += '<td style="width: 90px;"><span id="FontSelect' + n + '"></span></td>';
                                                }
                                                // Font size selection
                                                else if (toolbar[i] == "fontsize"){
                                                        editor += '<td style="width: 60px;"><span id="FontSizes'  + n + '"></span></td>';
                                                }
                                                // Button print out
                                                else {
                                                        // Get the values of the Button from the global ToolbarList object
                                                        var buttonObj = this.ToolbarList[toolbar[i]];
                                                        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.formatText(\'' + buttonID + '\',\'' + n + '\');" 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.formatText(\'ViewText\',\'' + n + '\');" 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.formatText(\'' + buttonID + '\',\'' + n + '\');" 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>\n';

            // Insert the editor after the textarea
            textarea.insertAdjacentHTML("afterEnd", editor);

            // Insert the Font Type and Size drop downs into the toolbar
            // Hide the dynamic drop down lists for the Font Types and Sizes
            this.outputFontSelect(n);
            this.outputFontSizes(n);
            this.hideFonts(n);
            this.hideFontSizes(n);

            // 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);

            // 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.hideFonts(n); WYSIWYG.hideFontSizes(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;
        },

        /* ---------------------------------------------------------------------- *\
          Function    : disable()
          Description : Disable the given WYSIWYG Editor Box
          Usage       : WYSIWYG.disable(textareaID)
          Arguments   : textareaID - The editor identifier (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        disable: function(textareaID) {
                // set n to textareaID
                var n = textareaID;

                // 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);
                }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : enable()
          Description : Enables the given WYSIWYG Editor Box
          Usage       : WYSIWYG.enable(textareaID)
          Arguments   : textareaID - The editor identifier (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        enable: function(textareaID) {
                // set n to textareaID
                var n = textareaID;

                // 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);
                }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : getNodeTree()
          Description : Returns the node structure of the current selection as array
          Usage       : WYSIWYG.getNodeTree(n);
          Arguments   : 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 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;
        },

        /* ---------------------------------------------------------------------- *\
          Function    : updateStatusBar()
          Description : Updates the status bar with the current node tree
          Usage       : WYSIWYG.updateStatusBar(n);
          Arguments   : 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;
                }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : disableDesignMode()
          Description : Disable the design mode if right mouse button is pressed.
                                          It's needed for custom context menus on mozilla (firefox),
                                          because if design mode is on then you can`t diabled the browser
                                          context menu.
          Usage       : WYSIWYG.disableDesignMode(e, n);
          Arguments   : event - browser event (like which button pressed)
                                          n  - The editor identifier (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        disableDesignMode: function(event, n) {
                var doc = this.getEditorWindow(n).document;
                if(event.which == 3) {
                        doc.designMode = "off";
                        return false;
                }
                else if(event.which != 3 && doc.designMode == "off") {
                        doc.designMode = "on";
                        return true;
                }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : formatText() (changed)
          Description : Format the content within the WYSIWYG Editor
          Usage       : WYSIWYG.formatText(id, n, selected);
          Arguments   : cmd - The execCommand (e.g. Bold)
                        n  - The editor identifier that the command affects (the textarea's ID)
                        selected - The selected value when applicable (e.g. Arial)
        \* ---------------------------------------------------------------------- */
        formatText: function(cmd, n, selected) {

                // When user clicks toolbar button make sure it always targets its respective WYSIWYG
                this.getEditorWindow(n).focus();

                // When in Text Mode these execCommands are disabled
                var formatIDs = new Array("FontSize","FontName","Bold","Italic","Underline","Subscript","Superscript","Strikethrough","Justifyleft","Justifyright","Justifycenter","miGiustifichi","InsertUnorderedList","InsertOrderedList","Indent","Outdent","ForeColor","BackColor","InsertImage","InsertTable","CreateLink", "Preview", "RemoveFormat");

                // Check if button clicked is in disabled list
                for (var i = 0; i < formatIDs.length; i++) {
                        if (formatIDs[i] == cmd) {
                                 var disabled_id = 1;
                        }
                }

                // 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 if in Text Mode and disabled button was clicked
                if (this.viewTextMode[n] == true && disabled_id == 1) {
                  alert("Sei in modalità testo HTML.\nIn questa modalità i pulsanti sono disabilitati.");
                  return;
                }

                // Check the insert image popup implementation
                var imagePopupFile = this.config[n].PopupsDir + 'insert_image.php';
                var imagePopupWidth = 400;
                var imagePopupHeight = 210;
                if(typeof this.config[n].ImagePopupFile != "undefined" && this.config[n].ImagePopupFile != "") {
                        imagePopupFile = this.config[n].ImagePopupFile;
                }
                if(typeof this.config[n].ImagePopupWidth && this.config[n].ImagePopupWidth > 0) {
                        imagePopupWidth = this.config[n].ImagePopupWidth;
                }
                if(typeof this.config[n].ImagePopupHeight && this.config[n].ImagePopupHeight > 0) {
                        imagePopupHeight = this.config[n].ImagePopupHeight;
                }

                // switch which action have to do
                switch(cmd) {

                        // test giustificato
                        case "miGiustifichi":
                              this.justifyText(n);
                        break;

                        // Font size
                        case "FontSize":
                                this.getEditorWindow(n).document.execCommand("FontSize", false, selected);
                        break;

                        // FontName
                        case "FontName":
                                this.getEditorWindow(n).document.execCommand("FontName", false, selected);
                        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;

                        // Remove Image
                        case "RemoveImage":
                                this.removeImage(n);
                        break;

                        // Remove Link
                        case "RemoveLink":
                                this.removeLink(n);
                        break;

                        // Remove a Node
                        case "RemoveNode":
                                this.removeNode(n);
                        break;

                        // Create Link
                        case "CreateLink":
                                window.open(this.config[n].PopupsDir + 'insert_hyperlink.html?wysiwyg=' + n, 'popup', 'location=0,status=0,scrollbars=0,resizable=0,width=350,height=160,top=' + popupPosition.top + ',left=' + popupPosition.left).focus();
                        break;

                        // InsertTable
                        case "InsertTable":
                                window.open(this.config[n].PopupsDir + 'create_table.html?wysiwyg=' + n, 'popup', 'location=0,status=0,scrollbars=0,resizable=0,width=400,height=370,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;

                        default:
                                WYSIWYG_Core.execCommand(n, cmd);

                }

                // hide node the font + font size selection
                this.hideFonts(n);
                this.hideFontSizes(n);
        },

        /* ---------------------------------------------------------------------- *\
          Function    : insertHTML()
          Description : Insert HTML into WYSIWYG in rich text
          Usage       : WYSIWYG.insertHTML("<b>hello</b>", "textareaID")
          Arguments   : html - The HTML being inserted (e.g. <b>hello</b>)
                        n  - The editor identifier that the HTML
                                                 will be inserted into (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        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);
                        }

                        range.setEnd(afterNode, 0);
                        range.setStart(afterNode, 0);
                }

                sel.addRange(range);
        },

        /* ---------------------------------------------------------------------- *\
          Function    : print()
          Description : Print out the content of the WYSIWYG editor area
          Usage       : WYSIWYG.print(n)
          Arguments   : 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();
                }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : outputFontSelect()
          Description : creates the Font Select drop down and inserts it into the toolbar
          Usage       : WYSIWYG.outputFontSelect(n)
          Arguments   : n - The editor identifier that the Font Select will update
                                when making font changes (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        outputFontSelect: function(n) {

                var fontDiv = $('FontSelect' + n);
                if(fontDiv == null) { return; }

                var fonts = this.config[n].Fonts;
                var FontSelectObj = this.ToolbarList['selectfont'];
                var FontSelect = this.config[n].ImagesDir  + FontSelectObj[2];
                var FontSelectOn  = this.config[n].ImagesDir + FontSelectObj[3];
                fonts.sort();

                var FontSelectDropDown = new Array;
                FontSelectDropDown[n] = '<table border="0" cellpadding="0" cellspacing="0"><tr><td onMouseOver="$(\'selectFont' + n + '\').src=\'' + FontSelectOn + '\';" onMouseOut="$(\'selectFont' + n + '\').src=\'' + FontSelect + '\';"><img src="' + FontSelect + '" id="selectFont' + n + '" width="85" height="20" onClick="WYSIWYG.showFonts(\'' + n + '\');" unselectable="on" border="0"><br>';
                FontSelectDropDown[n] += '<span id="Fonts' + n + '" class="dropdown" style="width: 145px;">';

                for (var i = 0; i < fonts.length;i++) {
                          if (fonts[i]) {
                                  FontSelectDropDown[n] += '<button type="button" onClick="WYSIWYG.formatText(\'FontName\',\'' + n + '\',\'' + fonts[i] + '\')\;" onMouseOver="this.className=\'mouseOver\'" onMouseOut="this.className=\'mouseOut\'" class="mouseOut" style="width: 120px;"><table cellpadding="0" cellspacing="0" border="0"><tr><td align="left" style="font-family:' + fonts[i] + '; font-size: 12px;">' + fonts[i] + '</td></tr></table></button><br>';
                          }
                  }

                FontSelectDropDown[n] += '</span></td></tr></table>';
                fontDiv.insertAdjacentHTML("afterBegin", FontSelectDropDown[n]);
        },

        /* ---------------------------------------------------------------------- *\
          Function    : outputFontSizes()
          Description : creates the Font Sizes drop down and inserts it into the toolbar
          Usage       : WYSIWYG.outputFontSelect(n)
          Arguments   : n   - The editor identifier that the Font Sizes will update
                                    when making font changes (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        outputFontSizes: function(n) {

                var fontSizeDiv = $('FontSizes' + n);
                if(fontSizeDiv == null) { return; }

                var fontSize = this.config[n].Fontsizes;
                var FontSizeObj = this.ToolbarList['selectsize'];
                var FontSize = this.config[n].ImagesDir + FontSizeObj[2];
                var FontSizeOn = this.config[n].ImagesDir + FontSizeObj[3];

                fontSize.sort();
                var FontSizesDropDown = new Array;
                FontSizesDropDown[n] = '<table border="0" cellpadding="0" cellspacing="0"><tr><td onMouseOver="$(\'selectSize' + n + '\').src=\'' + FontSizeOn + '\';" onMouseOut="$(\'selectSize' + n + '\').src=\'' + FontSize + '\';"><img src="' + FontSize + '" id="selectSize' + n + '" width="49" height="20" onClick="WYSIWYG.showFontSizes(\'' + n + '\');" unselectable="on" border="0"><br>';
                  FontSizesDropDown[n] += '<span id="Sizes' + n + '" class="dropdown" style="width: 170px;">';

                for (var i = 0; i < fontSize.length;i++) {
                  if (fontSize[i]) {
                      FontSizesDropDown[n] += '<button type="button" onClick="WYSIWYG.formatText(\'FontSize\',\'' + n + '\',\'' + fontSize[i] + '\')\;" onMouseOver="this.className=\'mouseOver\'" onMouseOut="this.className=\'mouseOut\'" class="mouseOut" style="width: 145px;"><table cellpadding="0" cellspacing="0" border="0"><tr><td align="left" style="font-family: arial, verdana, helvetica;"><font size="' + fontSize[i] + '">size ' + fontSize[i] + '</font></td></tr></table></button><br>';
              }
                  }

                FontSizesDropDown[n] += '</span></td></tr></table>';
                fontSizeDiv.insertAdjacentHTML("afterBegin", FontSizesDropDown[n]);
        },

        /* ---------------------------------------------------------------------- *\
          Function    : hideFonts()
          Description : Hides the list of font names in the font select drop down
          Usage       : WYSIWYG.hideFonts(n)
          Arguments   : n   - The editor identifier (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        hideFonts: function(n) {
                if($('Fonts' + n)) { $('Fonts' + n).style.display = 'none'; }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : hideFontSizes()
          Description : Hides the list of font sizes in the font sizes drop down
          Usage       : WYSIWYG.hideFontSizes(n)
          Arguments   : n   - The editor identifier (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        hideFontSizes: function(n) {
                if($('Sizes' + n)) { $('Sizes' + n).style.display = 'none'; }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : showFonts()
          Description : Shows the list of font names in the font select drop down
          Usage       : WYSIWYG.showFonts(n)
          Arguments   : n   - The editor identifier (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        showFonts: function(n) {
                if($('Fonts' + n) == null) { return; }
                if ($('Fonts' + n).style.display == 'block') {
                        $('Fonts' + n).style.display = 'none';
                }
                else {
                        $('Fonts' + n).style.display = 'block';
                        $('Fonts' + n).style.position = 'absolute';
                }

                // hide font size selection
                this.hideFontSizes(n);
        },

        /* ---------------------------------------------------------------------- *\
          Function    : showFontSizes()
          Description : Shows the list of font sizes in the font sizes drop down
          Usage       : WYSIWYG.showFonts(n)
          Arguments   : n   - The editor identifier (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        showFontSizes: function(n) {
                if($('Sizes' + n) == null) { return; }
                if ($('Sizes' + n).style.display == 'block') {
                        $('Sizes' + n).style.display = 'none';
                }
                else {
                        $('Sizes' + n).style.display = 'block';
                        $('Sizes' + n).style.position = 'absolute';
                }

                // hide font size selection
                this.hideFonts(n);
        },

        /* ---------------------------------------------------------------------- *\
          Function    : viewSource()
          Description : Shows the HTML source code generated by the WYSIWYG editor
          Usage       : WYSIWYG.showFonts(n)
          Arguments   : n   - The editor identifier (the textarea's ID)
        \* ---------------------------------------------------------------------- */
        viewSource: function(n) {

                // document
                var doc = this.getEditorWindow(n).document;

                // 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;
        },

        /* ---------------------------------------------------------------------- *\
          Function    : viewSource()
          Description : Shows the HTML source code generated by the WYSIWYG editor
          Usage       : WYSIWYG.showFonts(n)
          Arguments   : n   - The editor identifier (the textarea's 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;
                }

                // 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    : getDocumentPath()
          Description : Get the path of the given document
          Usage       : WYSIWYG.getDocumentPath(doc)
          Arguments   : doc  - Document of which you get the 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;
        },

        /* ---------------------------------------------------------------------- *\
          Function    : getDocumentUrl()
          Description : Get the documents url, convert local urls to web urls
          Usage       : WYSIWYG.getDocumentUrl(doc)
          Arguments   : doc  - Document of which you get the the path
        \* ---------------------------------------------------------------------- */
        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;
        },

        /* ---------------------------------------------------------------------- *\
          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 = this.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 = this.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(this.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 = this.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(this.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 = this.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 = this.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 = ""; }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : findParentTag()
          Description : Get the given parent tag of a range
          Usage       : WYSIWYG.findParentTag(parentTagName, range)
          Arguments   : parentTagName - Parent tag to find
                                          range - Range
        \* ---------------------------------------------------------------------- */
        findParentTag: 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]; }
                                elmWorking = node;
                                while (elmWorking.tagName != "HTML") {
                                          if (elmWorking.tagName == parentTagName){
                                                  return elmWorking;
                                          }
                                          elmWorking = elmWorking.parentNode;
                                 }
                                 return null;
                        }
                        else {
                                if(range.length > 0) {
                                        elmWorking = range.item(0);
                                }
                                else {
                                        elmWorking = range.parentElement();
                                }
                                while (elmWorking.tagName != "HTML") {
                                          if (elmWorking.tagName == parentTagName){
                                                   return elmWorking;
                                          } else {
                                                   elmWorking = elmWorking.parentElement;
                                          }
                                 }
                                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;
                }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : getTag()
          Description : Get the acutally tag of the given range
          Usage       : WYSIWYG.getTag(range)
          Arguments   : range - 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;
                }
        },

        /* ---------------------------------------------------------------------- *\
          Function    : getParent()
          Description : Get the parent node of an node
          Usage       : WYSIWYG.getParent(node)
          Arguments   : 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.10 2006/12/25 09:17:07 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 element The element on which the style attribute will affect
         * @param style Stylesheet which will be set
         */
        _setStyleAttribute: function(element, style) {
                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();
                                        element.style[attr] = value;
                                }
                                catch (e) {
                                        //alert(e);
                                }
                        }
                }
        },

        /**
         * Set an attribute's value on the given node element.
         *
         * @param node Node element
         * @param attr Attribute which is set
         * @param value Value of the attribute
         */
        setAttribute: function(node, attr, value) {
                if(value == "") {return;}
                if(attr.toLowerCase() == "style") {
                        this._setStyleAttribute(node, value);
                }
                else {
                        node.setAttribute(attr, value);
                }
        },

        /**
         * 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) {
                // 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("Copia/Taglia/Incolla non sono disponibili con Mozilla e Firefox\nVuoi maggiori informazioni riguardo questo problema?")) {
                                        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};
        }
}

/**
 * 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 = 1000;
                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="1" cellspacing="1">';

                // Add items
                this.addItem(n, 'Copy', iconCopy, 'Copia', sel);
                this.addItem(n, 'Cut', iconCut, 'Taglia', sel);
                this.addItem(n, 'Paste', iconPaste, 'Incolla', true);
                this.addSeperator();
                //this.addItem(n, 'InsertImage', iconImage, 'Modify Image Properties...', isImg);
                this.addItem(n, 'CreateLink', iconLink, 'Crea o modifica link...', sel || isLink);
                this.addItem(n, 'RemoveNode', iconDelete, 'Cancella blocco', 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.formatText(\'' + cmd + '\',\'' + n + '\', null);"><img src="' + icon.enabled + '" border="0"></a></td>';
                        item += '<td onmouseover="this.className=\'mouseover\'" onmouseout="this.className=\'\'" onclick="WYSIWYG.formatText(\'' + cmd + '\',\'' + n + '\', null);WYSIWYG_ContextMenu.close();"><a href="javascript:void(0);">' + title + '</a></td>';
                        item += '</tr>';
                }
                else {
                        item += '<tr>';
                        item += '<td class="icon"><a><img src="' + icon.disabled + '" border="0"></a></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;
        }
}

/**
 * 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);
        };
}