function HTMLArea(textarea, config) { if (HTMLArea.checkSupportedBrowser()) { if (typeof config == "undefined") { this.config = new HTMLArea.Config(); } else { this.config = config; } if (this.config.debug) { alert("DEBUG ON!!"); } this._htmlArea = null; this._textArea = textarea; this._mode = "wysiwyg"; } }; HTMLArea.Config = function () { this.version = "3.0"; // this.width = "504px"; this.width = "500px"; this.height = "300px"; // this.width = "auto"; // this.height = "auto"; // the next parameter specifies whether the toolbar should be included // in the size or not. this.sizeIncludesToolbar = false; this.bodyStyle = "background-color: #fff; font-family: verdana,sans-serif; font-size: 8pt"; this.editorURL = "lib/htmlarea3/"; this.popupURL = "popups/"; this.imgURL = "images/"; this.stylesheet = "../../ofclass.css"; this.debug = 0; this.replaceNextLines = 0; this.plainTextInput = 0; this.toolbar = [ [ "fontname", "space" ], [ "fontsize", "space" ], [ "formatblock", "space"], [ "bold", "italic", "underline", "separator" ], [ "strikethrough", "subscript", "superscript", "linebreak" ], [ "justifyleft", "justifycenter", "justifyright", "justifyfull", "separator" ], [ "orderedlist", "unorderedlist", "outdent", "indent", "separator" ], [ "forecolor", "backcolor", "textindicator", "separator" ], [ "horizontalrule", "createlink", "insertimage", "inserttable", "htmlmode", "separator" ], [ "popupeditor" ] ]; this.fontstyles = [ {name: "body", className: "body", classStyle: ""}, {name: "html", className: "menucentral", classStyle: ""}, {name: "table", className: "tabla", classStyle: ""}, {name: "th", className: "mdisclaimer", classStyle: ""}, {name: "td", className: "td", classStyle: ""}, {name: "td_alt", className: "td", classStyle: ""}, {name: "a", className: "a", classStyle: ""}, {name: "a_hover", className: "a", classStyle: ""}, {name: "a_visited", className: "a", classStyle: ""}, {name: "a_active", className: "a", classStyle: ""}, {name: "a_link", className: "a", classStyle: ""}, {name: "barraright", className: "rightbar", classStyle: ""}, {name: "barraleft", className: "leftbar", classStyle: ""}, {name: "menu", className: "menu", classStyle: ""}, {name: "fecha", className: "fecha", classStyle: ""}, {name: "titulo", className: "oftitulo", classStyle: ""}, {name: "descripcion", className: "rest_info", classStyle: ""}, {name: "input", className: "buscador", classStyle: ""}, {name: "input_text", className: "buscador", classStyle: ""}, {name: "input_select", className: "buscador", classStyle: ""}, {name: "input_radio", className: "light", classStyle: ""}, {name: "input_list", className: "of", classStyle: ""}, {name: "input_button", className: "botonbuscador", classStyle: ""}, {name: "pie", className: "pie", classStyle: ""}, {name: "cablistado", className: "titnoticia", classStyle: ""}, {name: "listado", className: "noticias", classStyle: ""}]; this.fontname = { "Arial": 'arial,helvetica,sans-serif', "Courier New": 'courier new,courier,monospace', "Georgia": 'georgia,times new roman,times,serif', "Tahoma": 'tahoma,arial,helvetica,sans-serif', "Times New Roman": 'times new roman,times,serif', "Verdana": 'verdana,arial,helvetica,sans-serif', "impact": 'impact', "WingDings": 'wingdings' }; this.fontsize = { "1 (8 pt)": "1", "2 (10 pt)": "2", "3 (12 pt)": "3", "4 (14 pt)": "4", "5 (18 pt)": "5", "6 (24 pt)": "6", "7 (36 pt)": "7" }; this.formatblock = { "Encabezado 1": "h1", "Encabezado 2": "h2", "Encabezado 3": "h3", "Encabezado 4": "h4", "Encabezado 5": "h5", "Encabezado 6": "h6", "Normal": "p", "Dirección": "address", "Sin formato": "pre" }; // ID CMD ToolTip Icon Enabled in text mode? this.btnList = { bold: ["Bold", "Negrita", "ed_format_bold.png", false], italic: ["Italic", "Cursiva", "ed_format_italic.png", false], underline: ["Underline", "Subrayado", "ed_format_underline.png", false], strikethrough: ["StrikeThrough", "Tachado", "ed_format_strike.png", false], subscript: ["SubScript", "Subíndice", "ed_format_sub.png", false], superscript: ["SuperScript", "Superíndice", "ed_format_sup.png", false], justifyleft: ["JustifyLeft", "Alineado Izquierda", "ed_align_left.png", false], justifycenter: ["JustifyCenter", "Centrado", "ed_align_center.png", false], justifyright: ["JustifyRight", "Alineado Derecha", "ed_align_right.png", false], justifyfull: ["JustifyFull", "Justificado", "ed_align_justify.png", false], orderedlist: ["InsertOrderedList", "Lista Ordenada", "ed_list_num.png", false], unorderedlist: ["InsertUnorderedList", "Lista", "ed_list_bullet.png", false], outdent: ["Outdent", "Indentar -", "ed_indent_less.png", false], indent: ["Indent", "Indentar +", "ed_indent_more.png", false], forecolor: ["ForeColor", "Color de fuente", "ed_color_fg.png", false], backcolor: ["BackColor", "Color de fondo", "ed_color_bg.png", false], horizontalrule: ["InsertHorizontalRule", "Línea Horizontal", "ed_hr.png", false], createlink: ["CreateLink", "Insertar Enlace", "ed_link.png", false], insertimage: ["InsertImage", "Insertar Imagen", "ed_image.png", false], inserttable: ["InsertTable", "Insertar Tabla", "insert_table.png", false], htmlmode: ["HtmlMode", "Ver Fuente", "ed_html.png", true], popupeditor: ["popupeditor", "Aumentar Editor", "fullscreen_maximize.png", true] // about: ["about", "Acerca de...", "ed_about.png", true], // help: ["showhelp", "Ayuda...", "ed_help.png", true] }; HTMLArea.I18N = { tooltips: { bold: "Negrita", italic: "Cursiva", underline: "Subrayado", strikethrough: "Tachado", subscript: "Subíndice", superscript: "Superíndice", justifyleft: "Alineado Izquierda", justifycenter: "Centrado", justifyright: "Alineado Derecha", justifyfull: "Justificado", orderedlist: "Lista ordenada", unorderedlist: "Lista", outdent: "Indentar -", indent: "Indentar +", forecolor: "Color de fuente", backcolor: "Color de fondo", horizontalrule: "Línea Horizontal", createlink: "Insertar enlace", insertimage: "Insertar Imagen", inserttable: "Insertar Tabla", htmlmode: "Ver Fuente", popupeditor: "Aumentar Editor", about: "Acerca de...", help: "Ayuda...", textindicator: "Estilo actual" } }; // initialize tooltips from the I18N module for (var i in this.btnList) { var btn = this.btnList[i]; if (typeof HTMLArea.I18N.tooltips[i] != "undefined") { btn[1] = HTMLArea.I18N.tooltips[i]; } } }; /** Helper function: replace all TEXTAREA-s in the document with HTMLArea-s. */ HTMLArea.replaceAll = function() { var tas = document.getElementsByTagName("textarea"); for (var i = tas.length; i > 0; (new HTMLArea(tas[--i])).generate()); }; // Creates the toolbar and appends it to the _htmlarea HTMLArea.prototype._createToolbar = function () { var editor = this; // to access this in nested functions var toolbar = document.createElement("div"); this._toolbar = toolbar; toolbar.className = "toolbar"; toolbar.unselectable = "1"; if (editor.config.debug) { toolbar.style.border = "1px solid red"; } var tb_row = null; var tb_objects = new Object(); this._toolbarObjects = tb_objects; // creates a new line in the toolbar function newLine() { var table = document.createElement("table"); table.border = "0px"; table.cellSpacing = "0px"; table.cellPadding = "0px"; toolbar.appendChild(table); // TBODY is required for IE, otherwise you don't see anything // in the TABLE. var tb_body = document.createElement("tbody"); table.appendChild(tb_body); tb_row = document.createElement("tr"); tb_body.appendChild(tb_row); }; // init first line newLine(); // appends a new button to toolbar function createButton(txt) { // updates the state of a toolbar element function setButtonStatus(id, newval) { var oldval = this[id]; var el = this.element; if (oldval != newval) { switch (id) { case "enabled": if (newval) { HTMLArea._removeClass(el, "buttonDisabled"); el.disabled = false; } else { HTMLArea._addClass(el, "buttonDisabled"); el.disabled = true; } break; case "active": if (newval) { HTMLArea._addClass(el, "buttonPressed"); } else { HTMLArea._removeClass(el, "buttonPressed"); } break; } this[id] = newval; } }; // this function will handle creation of combo boxes function createSelect() { var options = null; var el = null; var cmd = null; switch (txt) { case "fontstyles": case "fontsize": case "fontname": case "formatblock": options = editor.config[txt]; // HACK ;) cmd = txt; break; } if (options) { el = document.createElement("select"); var obj = { name: txt, // field name element: el, // the UI element (SELECT) enabled: true, // is it enabled? text: false, // enabled in text mode? cmd: cmd, // command ID state: setButtonStatus // for changing state }; tb_objects[txt] = obj; for (var i in options) { var op = document.createElement("option"); op.appendChild(document.createTextNode(i)); op.value = options[i]; el.appendChild(op); } HTMLArea._addEvent(el, "change", function () { editor._comboSelected(el, txt); }); } return el; }; // the element that will be created var el = null; var btn = null; switch (txt) { case "separator": el = document.createElement("div"); el.className = "separator"; break; case "space": el = document.createElement("div"); el.className = "space"; break; case "linebreak": newLine(); return false; case "textindicator": el = document.createElement("div"); el.appendChild(document.createTextNode("A")); el.className = "indicator"; el.title = HTMLArea.I18N.tooltips.textindicator; var obj = { name: txt, // the button name (i.e. 'bold') element: el, // the UI element (DIV) enabled: true, // is it enabled? active: false, // is it pressed? text: false, // enabled in text mode? cmd: "textindicator", // the command ID state: setButtonStatus // for changing state }; tb_objects[txt] = obj; break; default: btn = editor.config.btnList[txt]; break; } if (!el && btn) { el = document.createElement("div"); el.title = btn[1]; el.className = "button"; // let's just pretend we have a button object, and // assign all the needed information to it. var obj = { name: txt, // the button name (i.e. 'bold') element: el, // the UI element (DIV) enabled: true, // is it enabled? active: false, // is it pressed? text: btn[3], // enabled in text mode? cmd: btn[0], // the command ID state: setButtonStatus // for changing state }; tb_objects[txt] = obj; // handlers to emulate nice flat toolbar buttons HTMLArea._addEvent(el, "mouseover", function () { if (obj.enabled) { HTMLArea._addClass(el, "buttonHover"); } }); HTMLArea._addEvent(el, "mouseout", function () { if (obj.enabled) with (HTMLArea) { _removeClass(el, "buttonHover"); _removeClass(el, "buttonActive"); (obj.active) && _addClass(el, "buttonPressed"); } }); HTMLArea._addEvent(el, "mousedown", function (ev) { if (obj.enabled) with (HTMLArea) { _addClass(el, "buttonActive"); _removeClass(el, "buttonPressed"); _stopEvent(is_ie ? window.event : ev); } }); // when clicked, do the following: HTMLArea._addEvent(el, "click", function (ev) { if (obj.enabled) with (HTMLArea) { _removeClass(el, "buttonActive"); _removeClass(el, "buttonHover"); editor._buttonClicked(txt); _stopEvent(is_ie ? window.event : ev); } }); var img = document.createElement("img"); img.src = editor.imgURL(btn[2]); el.appendChild(img); } else if (!el) { el = createSelect(); } if (el) { var tb_cell = document.createElement("td"); tb_row.appendChild(tb_cell); tb_cell.appendChild(el); } else { alert("FIXME: Unknown toolbar item: " + txt); } return el; }; for (var i in this.config.toolbar) { var group = this.config.toolbar[i]; for (var j in group) { createButton(group[j]); } } this._htmlArea.appendChild(toolbar); }; // Creates the HTMLArea object and replaces the textarea with it. HTMLArea.prototype.generate = function () { if (navigator.userAgent.indexOf("Opera")!=-1) { return false; } var editor = this; // we'll need "this" in some nested functions // get the textarea var textarea = this._textArea; var tipo = typeof textarea; if (typeof textarea == "string") { // it's not element but ID this._textArea = textarea = document.getElementById(textarea); } this._ta_size = { w: textarea.offsetWidth, h: textarea.offsetHeight }; // hide the textarea textarea.style.display = "none"; // create the editor framework var htmlarea = document.createElement("div"); htmlarea.className = "htmlarea"; this._htmlArea = htmlarea; // insert the editor before the textarea. textarea.parentNode.insertBefore(htmlarea, textarea); // retrieve the HTML on submit HTMLArea._addEvent(textarea.form, "submit", function (event) { editor._formSubmit(HTMLArea.is_ie ? window.event : event); }); // creates & appends the toolbar this._createToolbar(); // create the IFRAME var iframe = document.createElement("iframe"); htmlarea.appendChild(iframe); this._iframe = iframe; // remove the default border as it keeps us from computing correctly // the sizes. (somebody tell me why doesn't this work in IE) // iframe.style.border = "none"; // iframe.frameborder = "0"; // size the IFRAME according to user's prefs or initial textarea var height = (this.config.height == "auto" ? (this._ta_size.h + "px") : this.config.height); height = parseInt(height); var width = (this.config.width == "auto" ? (this._ta_size.w + "px") : this.config.width); width = parseInt(width); iframe.style.width = width + "px"; if (this.config.sizeIncludesToolbar) { // substract toolbar height height -= this._toolbar.offsetHeight; } iframe.style.height = height + "px"; // now create a secondary textarea so that we can switch between // WYSIWYG & text mode. textarea = document.createElement("textarea"); // hidden by default textarea.style.display = "none"; // make it the same size as the editor textarea.style.width = iframe.style.width; textarea.style.height = iframe.style.height; // insert it after the iframe htmlarea.appendChild(textarea); // remember it for later this._textArea2 = textarea; // IMPORTANT: we have to allow Mozilla a short time to recognize the // new frame. Otherwise we get a stupid exception. function initIframe() { var doc = editor._iframe.contentWindow.document; if (!doc) { if (HTMLArea.is_gecko) { setTimeout(function () { editor._initIframe(); }, 10); return false; } else { alert("ERROR: IFRAME can't be initialized."); } } if (HTMLArea.is_gecko) { // enable editable mode for Mozilla doc.designMode = "on"; } editor._doc = doc; doc.open(); var html = "\n"; html += "
\n"; html += "\n"; html += "\n"; html += "\n"; html += editor._textArea.value; html += "\n"; html += ""; doc.write(html); doc.close(); if (HTMLArea.is_ie) { // enable editable mode for IE. For some reason this // doesn't work if done in the same place as for Gecko // (above). doc.body.contentEditable = true; } // Si le damos el foco al editor la página se desplaza // editor.focusEditor(); // intercept some events; for updating the toolbar & keyboard handlers HTMLArea._addEvents (doc, ["keydown", "keypress", "mousedown", "mouseup", "drag"], function (event) { return editor._editorEvent(HTMLArea.is_ie ? editor._iframe.contentWindow.event : event); }); editor.updateToolbar(); // editor.focusEditor(); }; setTimeout(initIframe, HTMLArea.is_gecko ? 10 : 0); }; // Switches editor mode; parameter can be "textmode" or "wysiwyg" HTMLArea.prototype.setMode = function(mode) { switch (mode) { case "textmode": this._textArea2.value = this.getHTML(); this._iframe.style.display = "none"; this._textArea2.style.display = "block"; break; case "wysiwyg": this._doc.body.innerHTML = this.getHTML(); this._iframe.style.display = "block"; this._textArea2.style.display = "none"; if (HTMLArea.is_gecko) { // we need to refresh that info for Moz-1.3a this._doc.designMode = "on"; } break; default: alert("Mode <" + mode + "> not defined!"); return false; } this._mode = mode; this.focusEditor(); }; /*************************************************** * Category: EDITOR UTILITIES ***************************************************/ // focuses the iframe window. returns a reference to the editor document. HTMLArea.prototype.focusEditor = function() { switch (this._mode) { case "wysiwyg": this._iframe.focus(); // this._iframe.contentWindow.focus(); break; case "textmode": this._textArea2.focus(); break; default: alert("ERROR: mode " + this._mode + " is not defined"); break; } return this._doc; }; // updates enabled/disable/active state of the toolbar elements HTMLArea.prototype.updateToolbar = function() { var doc = this._doc; var text = (this._mode == "textmode"); for (var i in this._toolbarObjects) { var btn = this._toolbarObjects[i]; var cmd = btn.cmd; if (typeof cmd == "function") { continue; } cmd = cmd.toLowerCase(); btn.state("enabled", !text || btn.text); switch (cmd) { case "fontstyles": case "fontname": case "fontsize": case "formatblock": if (!text) { var value = ("" + doc.queryCommandValue(cmd)).toLowerCase(); if (!value) { // FIXME: what do we do here? break; } var options = this.config[i]; // HACK!! var k = 0; // btn.element.selectedIndex = 0; for (var j in options) { // FIXME: the following line is scary. if ((j.toLowerCase() == value) || (options[j].substr(0, value.length).toLowerCase() == value)) { btn.element.selectedIndex = k; break; } ++k; } } break; case "textindicator": if (!text) { try {with (btn.element.style) { backgroundColor = HTMLArea._makeColor(doc.queryCommandValue("backcolor")); color = HTMLArea._makeColor(doc.queryCommandValue("forecolor")); fontFamily = doc.queryCommandValue("fontname"); fontWeight = doc.queryCommandState("bold") ? "bold" : "normal"; fontStyle = doc.queryCommandState("italic") ? "italic" : "normal"; }} catch (e) { alert(e + "\n\n" + cmd); } } break; case "htmlmode": btn.state("active", text); break; default: try { btn.state("active", (!text && doc.queryCommandState(cmd))); } catch (e) {} break; } } }; /** Returns a node after which we can insert other nodes, in the current * selection. The selection is removed. It splits a text node, if needed. */ HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) { if (!HTMLArea.is_ie) { var sel = this._getSelection(); var range = this._createRange(sel); // remove the current selection sel.removeAllRanges(); range.deleteContents(); var node = range.startContainer; var pos = range.startOffset; range = this._createRange(); switch (node.nodeType) { case 3: // Node.TEXT_NODE // we have to split it at the caret position. if (toBeInserted.nodeType == 3) { // do optimized insertion node.insertData(pos, toBeInserted.data); range.setEnd(node, pos + toBeInserted.length); range.setStart(node, pos + toBeInserted.length); } else { node = node.splitText(pos); node.parentNode.insertBefore(toBeInserted, node); range.setStart(node, 0); range.setEnd(node, 0); } break; case 1: // Node.ELEMENT_NODE node = node.childNodes[pos]; node.parentNode.insertBefore(toBeInserted, node); range.setStart(node, 0); range.setEnd(node, 0); break; } sel.addRange(range); } else { return null; // this function not yet used for IE