version 1.1, 2004/02/18 08:07:15
|
version 1.6, 2006/07/27 22:27:22
|
Line 1
|
Line 1
|
// |
// htmlArea v3.0 - Copyright (c) 2002-2004 interactivetools.com, inc. |
// htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc. |
|
// This copyright notice MUST stay intact for use (see license.txt). |
// This copyright notice MUST stay intact for use (see license.txt). |
// |
// |
|
// Portions (c) dynarch.com, 2003-2004 |
|
// |
// A free WYSIWYG editor replacement for <textarea> fields. |
// A free WYSIWYG editor replacement for <textarea> fields. |
// For full source code and docs, visit http://www.interactivetools.com/ |
// For full source code and docs, visit http://www.interactivetools.com/ |
// |
// |
// Version 3.0 developed by Mihai Bazon for InteractiveTools. |
// Version 3.0 developed by Mihai Bazon. |
// http://students.infoiasi.ro/~mishoo |
// http://dynarch.com/mishoo |
// |
// |
// $Id$ |
// $Id$ |
|
|
|
if (typeof _editor_url == "string") { |
|
// Leave exactly one backslash at the end of _editor_url |
|
_editor_url = _editor_url.replace(/\x2f*$/, '/'); |
|
} else { |
|
alert("WARNING: _editor_url is not set! You should set this variable to the editor files path; it should preferably be an absolute path, like in '/htmlarea', but it can be relative if you prefer. Further we will try to load the editor files correctly but we'll probably fail."); |
|
_editor_url = ''; |
|
} |
|
|
|
// make sure we have a language |
|
if (typeof _editor_lang == "string") { |
|
_editor_lang = _editor_lang.toLowerCase(); |
|
} else { |
|
_editor_lang = "en"; |
|
} |
|
|
// Creates a new HTMLArea object. Tries to replace the textarea with the given |
// Creates a new HTMLArea object. Tries to replace the textarea with the given |
// ID with it. |
// ID with it. |
function HTMLArea(textarea, config) { |
function HTMLArea(textarea, config) { |
Line 24 function HTMLArea(textarea, config) {
|
Line 40 function HTMLArea(textarea, config) {
|
this._editMode = "wysiwyg"; |
this._editMode = "wysiwyg"; |
this.plugins = {}; |
this.plugins = {}; |
this._timerToolbar = null; |
this._timerToolbar = null; |
|
this._timerUndo = null; |
|
this._undoQueue = new Array(this.config.undoSteps); |
|
this._undoPos = -1; |
|
this._customUndo = false; |
this._mdoc = document; // cache the document, we need it in plugins |
this._mdoc = document; // cache the document, we need it in plugins |
|
this.doctype = ''; |
} |
} |
}; |
}; |
|
|
|
// load some scripts |
|
(function() { |
|
var scripts = HTMLArea._scripts = [ _editor_url + "htmlarea.js", |
|
_editor_url + "dialog.js", |
|
_editor_url + "popupwin.js", |
|
_editor_url + "lang/" + _editor_lang + ".js" ]; |
|
var head = document.getElementsByTagName("head")[0]; |
|
// start from 1, htmlarea.js is already loaded |
|
for (var i = 1; i < scripts.length; ++i) { |
|
var script = document.createElement("script"); |
|
script.src = scripts[i]; |
|
head.appendChild(script); |
|
} |
|
})(); |
|
|
|
// cache some regexps |
|
HTMLArea.RE_tagName = /(<\/|<)\s*([^ \t\n>]+)/ig; |
|
HTMLArea.RE_doctype = /(<!doctype((.|\n)*?)>)\n?/i; |
|
HTMLArea.RE_head = /<head>((.|\n)*?)<\/head>/i; |
|
HTMLArea.RE_body = /<body>((.|\n)*?)<\/body>/i; |
|
|
HTMLArea.Config = function () { |
HTMLArea.Config = function () { |
this.version = "3.0"; |
this.version = "3.0"; |
|
|
Line 37 HTMLArea.Config = function () {
|
Line 79 HTMLArea.Config = function () {
|
// enable creation of a status bar? |
// enable creation of a status bar? |
this.statusBar = true; |
this.statusBar = true; |
|
|
|
// maximum size of the undo queue |
|
this.undoSteps = 20; |
|
|
|
// the time interval at which undo samples are taken |
|
this.undoTimeout = 500; // 1/2 sec. |
|
|
// the next parameter specifies whether the toolbar should be included |
// the next parameter specifies whether the toolbar should be included |
// in the size or not. |
// in the size or not. |
this.sizeIncludesToolbar = true; |
this.sizeIncludesToolbar = true; |
|
|
|
// if true then HTMLArea will retrieve the full HTML, starting with the |
|
// <HTML> tag. |
|
this.fullPage = false; |
|
|
// style included in the iframe document |
// style included in the iframe document |
this.pageStyle = "body { background-color: #fff; font-family: verdana,sans-serif; }"; |
this.pageStyle = ""; |
if (typeof _editor_url != "undefined") { |
|
this.editorURL = _editor_url; |
// set to true if you want Word code to be cleaned upon Paste |
} else { |
this.killWordOnPaste = false; |
this.editorURL = ""; |
|
} |
// BaseURL included in the iframe document |
|
this.baseURL = document.baseURI || document.URL; |
|
if (this.baseURL && this.baseURL.match(/(.*)\/([^\/]+)/)) |
|
this.baseURL = RegExp.$1 + "/"; |
|
|
// URL-s |
// URL-s |
this.imgURL = "images/"; |
this.imgURL = "images/"; |
this.popupURL = "popups/"; |
this.popupURL = "popups/"; |
|
|
// configuration for plugins |
|
this.plugins = {}; |
|
|
|
/** CUSTOMIZING THE TOOLBAR |
/** CUSTOMIZING THE TOOLBAR |
* ------------------------- |
* ------------------------- |
* |
* |
Line 69 HTMLArea.Config = function () {
|
Line 121 HTMLArea.Config = function () {
|
[ "fontname", "space", |
[ "fontname", "space", |
"fontsize", "space", |
"fontsize", "space", |
"formatblock", "space", |
"formatblock", "space", |
"bold", "italic", "underline", "separator", |
"bold", "italic", "underline", "strikethrough", "separator", |
"strikethrough", "subscript", "superscript", "separator", |
"subscript", "superscript", "separator", |
"copy", "cut", "paste", "space", "undo", "redo" ], |
"copy", "cut", "paste", "space", "undo", "redo" ], |
|
|
[ "justifyleft", "justifycenter", "justifyright", "justifyfull", "separator", |
[ "justifyleft", "justifycenter", "justifyright", "justifyfull", "separator", |
|
"lefttoright", "righttoleft", "separator", |
"insertorderedlist", "insertunorderedlist", "outdent", "indent", "separator", |
"insertorderedlist", "insertunorderedlist", "outdent", "indent", "separator", |
"forecolor", "hilitecolor", "textindicator", "separator", |
"forecolor", "hilitecolor", "separator", |
"inserthorizontalrule", "createlink", "insertimage", "inserttable", "htmlmode", "separator", |
"inserthorizontalrule", "createlink", "insertimage", "inserttable", "htmlmode", "separator", |
"popupeditor", "separator", "showhelp", "about" ] |
"popupeditor", "separator", "showhelp", "about" ] |
]; |
]; |
|
|
this.fontname = { |
this.fontname = { |
"Arial": 'arial,helvetica,sans-serif', |
"Arial": 'arial,helvetica,sans-serif', |
Line 116 HTMLArea.Config = function () {
|
Line 169 HTMLArea.Config = function () {
|
this.customSelects = {}; |
this.customSelects = {}; |
|
|
function cut_copy_paste(e, cmd, obj) { |
function cut_copy_paste(e, cmd, obj) { |
try { |
e.execCommand(cmd); |
e.execCommand(cmd); |
|
} catch (e) { |
|
if (HTMLArea.is_gecko) { |
|
alert("Some revisions of Mozilla/Gecko do not support programatic " + |
|
"access to cut/copy/paste functions, for security reasons. " + |
|
"Your browser is one of them. Please use the standard key combinations:\n" + |
|
"CTRL-X for cut, CTRL-C for copy, CTRL-V for paste."); |
|
obj.element.style.display = "none"; |
|
} |
|
} |
|
}; |
}; |
|
|
// ADDING CUSTOM BUTTONS: please read below! |
// ADDING CUSTOM BUTTONS: please read below! |
Line 144 HTMLArea.Config = function () {
|
Line 187 HTMLArea.Config = function () {
|
// - Icon: path to an icon image file for the button (TODO: use one image for all buttons!) |
// - Icon: path to an icon image file for the button (TODO: use one image for all buttons!) |
// - Enabled in text mode: if false the button gets disabled for text-only mode; otherwise enabled all the time. |
// - Enabled in text mode: if false the button gets disabled for text-only mode; otherwise enabled all the time. |
this.btnList = { |
this.btnList = { |
bold: [ "Bold", "images/ed_format_bold.gif", false, function(e) {e.execCommand("bold");} ], |
bold: [ "Bold", "ed_format_bold.gif", false, function(e) {e.execCommand("bold");} ], |
italic: [ "Italic", "images/ed_format_italic.gif", false, function(e) {e.execCommand("italic");} ], |
italic: [ "Italic", "ed_format_italic.gif", false, function(e) {e.execCommand("italic");} ], |
underline: [ "Underline", "images/ed_format_underline.gif", false, function(e) {e.execCommand("underline");} ], |
underline: [ "Underline", "ed_format_underline.gif", false, function(e) {e.execCommand("underline");} ], |
strikethrough: [ "Strikethrough", "images/ed_format_strike.gif", false, function(e) {e.execCommand("strikethrough");} ], |
strikethrough: [ "Strikethrough", "ed_format_strike.gif", false, function(e) {e.execCommand("strikethrough");} ], |
subscript: [ "Subscript", "images/ed_format_sub.gif", false, function(e) {e.execCommand("subscript");} ], |
subscript: [ "Subscript", "ed_format_sub.gif", false, function(e) {e.execCommand("subscript");} ], |
superscript: [ "Superscript", "images/ed_format_sup.gif", false, function(e) {e.execCommand("superscript");} ], |
superscript: [ "Superscript", "ed_format_sup.gif", false, function(e) {e.execCommand("superscript");} ], |
justifyleft: [ "Justify Left", "images/ed_align_left.gif", false, function(e) {e.execCommand("justifyleft");} ], |
justifyleft: [ "Justify Left", "ed_align_left.gif", false, function(e) {e.execCommand("justifyleft");} ], |
justifycenter: [ "Justify Center", "images/ed_align_center.gif", false, function(e) {e.execCommand("justifycenter");} ], |
justifycenter: [ "Justify Center", "ed_align_center.gif", false, function(e) {e.execCommand("justifycenter");} ], |
justifyright: [ "Justify Right", "images/ed_align_right.gif", false, function(e) {e.execCommand("justifyright");} ], |
justifyright: [ "Justify Right", "ed_align_right.gif", false, function(e) {e.execCommand("justifyright");} ], |
justifyfull: [ "Justify Full", "images/ed_align_justify.gif", false, function(e) {e.execCommand("justifyfull");} ], |
justifyfull: [ "Justify Full", "ed_align_justify.gif", false, function(e) {e.execCommand("justifyfull");} ], |
insertorderedlist: [ "Ordered List", "images/ed_list_num.gif", false, function(e) {e.execCommand("insertorderedlist");} ], |
insertorderedlist: [ "Ordered List", "ed_list_num.gif", false, function(e) {e.execCommand("insertorderedlist");} ], |
insertunorderedlist: [ "Bulleted List", "images/ed_list_bullet.gif", false, function(e) {e.execCommand("insertunorderedlist");} ], |
insertunorderedlist: [ "Bulleted List", "ed_list_bullet.gif", false, function(e) {e.execCommand("insertunorderedlist");} ], |
outdent: [ "Decrease Indent", "images/ed_indent_less.gif", false, function(e) {e.execCommand("outdent");} ], |
outdent: [ "Decrease Indent", "ed_indent_less.gif", false, function(e) {e.execCommand("outdent");} ], |
indent: [ "Increase Indent", "images/ed_indent_more.gif", false, function(e) {e.execCommand("indent");} ], |
indent: [ "Increase Indent", "ed_indent_more.gif", false, function(e) {e.execCommand("indent");} ], |
forecolor: [ "Font Color", "images/ed_color_fg.gif", false, function(e) {e.execCommand("forecolor");} ], |
forecolor: [ "Font Color", "ed_color_fg.gif", false, function(e) {e.execCommand("forecolor");} ], |
hilitecolor: [ "Background Color", "images/ed_color_bg.gif", false, function(e) {e.execCommand("hilitecolor");} ], |
hilitecolor: [ "Background Color", "ed_color_bg.gif", false, function(e) {e.execCommand("hilitecolor");} ], |
inserthorizontalrule: [ "Horizontal Rule", "images/ed_hr.gif", false, function(e) {e.execCommand("inserthorizontalrule");} ], |
inserthorizontalrule: [ "Horizontal Rule", "ed_hr.gif", false, function(e) {e.execCommand("inserthorizontalrule");} ], |
createlink: [ "Insert Web Link", "images/ed_link.gif", false, function(e) {e.execCommand("createlink", true);} ], |
createlink: [ "Insert Web Link", "ed_link.gif", false, function(e) {e.execCommand("createlink", true);} ], |
insertimage: [ "Insert Image", "images/ed_image.gif", false, function(e) {e.execCommand("insertimage");} ], |
insertimage: [ "Insert/Modify Image", "ed_image.gif", false, function(e) {e.execCommand("insertimage");} ], |
inserttable: [ "Insert Table", "images/insert_table.gif", false, function(e) {e.execCommand("inserttable");} ], |
inserttable: [ "Insert Table", "insert_table.gif", false, function(e) {e.execCommand("inserttable");} ], |
htmlmode: [ "Toggle HTML Source", "images/ed_html.gif", true, function(e) {e.execCommand("htmlmode");} ], |
htmlmode: [ "Toggle HTML Source", "ed_html.gif", true, function(e) {e.execCommand("htmlmode");} ], |
popupeditor: [ "Enlarge Editor", "images/fullscreen_maximize.gif", true, function(e) {e.execCommand("popupeditor");} ], |
popupeditor: [ "Enlarge Editor", "fullscreen_maximize.gif", true, function(e) {e.execCommand("popupeditor");} ], |
about: [ "About this editor", "images/ed_about.gif", true, function(e) {e.execCommand("about");} ], |
about: [ "About this editor", "ed_about.gif", true, function(e) {e.execCommand("about");} ], |
showhelp: [ "Help using editor", "images/ed_help.gif", true, function(e) {e.execCommand("showhelp");} ], |
showhelp: [ "Help using editor", "ed_help.gif", true, function(e) {e.execCommand("showhelp");} ], |
undo: [ "Undoes your last action", "images/ed_undo.gif", false, function(e) {e.execCommand("undo");} ], |
undo: [ "Undoes your last action", "ed_undo.gif", false, function(e) {e.execCommand("undo");} ], |
redo: [ "Redoes your last action", "images/ed_redo.gif", false, function(e) {e.execCommand("redo");} ], |
redo: [ "Redoes your last action", "ed_redo.gif", false, function(e) {e.execCommand("redo");} ], |
cut: [ "Cut selection", "images/ed_cut.gif", false, cut_copy_paste ], |
cut: [ "Cut selection", "ed_cut.gif", false, cut_copy_paste ], |
copy: [ "Copy selection", "images/ed_copy.gif", false, cut_copy_paste ], |
copy: [ "Copy selection", "ed_copy.gif", false, cut_copy_paste ], |
paste: [ "Paste from clipboard", "images/ed_paste.gif", false, cut_copy_paste ] |
paste: [ "Paste from clipboard", "ed_paste.gif", false, cut_copy_paste ], |
|
lefttoright: [ "Direction left to right", "ed_left_to_right.gif", false, function(e) {e.execCommand("lefttoright");} ], |
|
righttoleft: [ "Direction right to left", "ed_right_to_left.gif", false, function(e) {e.execCommand("righttoleft");} ] |
}; |
}; |
/* ADDING CUSTOM BUTTONS |
/* ADDING CUSTOM BUTTONS |
* --------------------- |
* --------------------- |
Line 197 HTMLArea.Config = function () {
|
Line 242 HTMLArea.Config = function () {
|
* An alternate (also more convenient and recommended) way to |
* An alternate (also more convenient and recommended) way to |
* accomplish this is to use the registerButton function below. |
* accomplish this is to use the registerButton function below. |
*/ |
*/ |
// initialize tooltips from the I18N module |
// initialize tooltips from the I18N module and generate correct image path |
for (var i in this.btnList) { |
for (var i in this.btnList) { |
var btn = this.btnList[i]; |
var btn = this.btnList[i]; |
|
btn[1] = _editor_url + this.imgURL + btn[1]; |
if (typeof HTMLArea.I18N.tooltips[i] != "undefined") { |
if (typeof HTMLArea.I18N.tooltips[i] != "undefined") { |
btn[0] = HTMLArea.I18N.tooltips[i]; |
btn[0] = HTMLArea.I18N.tooltips[i]; |
} |
} |
Line 235 HTMLArea.Config.prototype.registerButton
|
Line 281 HTMLArea.Config.prototype.registerButton
|
} |
} |
// check for existing id |
// check for existing id |
if (typeof this.customSelects[the_id] != "undefined") { |
if (typeof this.customSelects[the_id] != "undefined") { |
alert("WARNING [HTMLArea.Config::registerDropdown]:\nA dropdown with the same ID already exists."); |
// alert("WARNING [HTMLArea.Config::registerDropdown]:\nA dropdown with the same ID already exists."); |
} |
} |
if (typeof this.btnList[the_id] != "undefined") { |
if (typeof this.btnList[the_id] != "undefined") { |
alert("WARNING [HTMLArea.Config::registerDropdown]:\nA button with the same ID already exists."); |
// alert("WARNING [HTMLArea.Config::registerDropdown]:\nA button with the same ID already exists."); |
} |
} |
switch (typeof id) { |
switch (typeof id) { |
case "string": this.btnList[id] = [ tooltip, image, textMode, action, context ]; break; |
case "string": this.btnList[id] = [ tooltip, image, textMode, action, context ]; break; |
Line 255 HTMLArea.Config.prototype.registerButton
|
Line 301 HTMLArea.Config.prototype.registerButton
|
HTMLArea.Config.prototype.registerDropdown = function(object) { |
HTMLArea.Config.prototype.registerDropdown = function(object) { |
// check for existing id |
// check for existing id |
if (typeof this.customSelects[object.id] != "undefined") { |
if (typeof this.customSelects[object.id] != "undefined") { |
alert("WARNING [HTMLArea.Config::registerDropdown]:\nA dropdown with the same ID already exists."); |
// alert("WARNING [HTMLArea.Config::registerDropdown]:\nA dropdown with the same ID already exists."); |
} |
} |
if (typeof this.btnList[object.id] != "undefined") { |
if (typeof this.btnList[object.id] != "undefined") { |
alert("WARNING [HTMLArea.Config::registerDropdown]:\nA button with the same ID already exists."); |
// alert("WARNING [HTMLArea.Config::registerDropdown]:\nA button with the same ID already exists."); |
} |
} |
this.customSelects[object.id] = object; |
this.customSelects[object.id] = object; |
}; |
}; |
|
|
|
/** Call this function to remove some buttons/drop-down boxes from the toolbar. |
|
* Pass as the only parameter a string containing button/drop-down names |
|
* delimited by spaces. Note that the string should also begin with a space |
|
* and end with a space. Example: |
|
* |
|
* config.hideSomeButtons(" fontname fontsize textindicator "); |
|
* |
|
* It's useful because it's easier to remove stuff from the defaul toolbar than |
|
* create a brand new toolbar ;-) |
|
*/ |
|
HTMLArea.Config.prototype.hideSomeButtons = function(remove) { |
|
var toolbar = this.toolbar; |
|
for (var i in toolbar) { |
|
var line = toolbar[i]; |
|
for (var j = line.length; --j >= 0; ) { |
|
if (remove.indexOf(" " + line[j] + " ") >= 0) { |
|
var len = 1; |
|
if (/separator|space/.test(line[j + 1])) { |
|
len = 2; |
|
} |
|
line.splice(j, len); |
|
} |
|
} |
|
} |
|
}; |
|
|
/** Helper function: replace all TEXTAREA-s in the document with HTMLArea-s. */ |
/** Helper function: replace all TEXTAREA-s in the document with HTMLArea-s. */ |
HTMLArea.replaceAll = function(config) { |
HTMLArea.replaceAll = function(config) { |
var tas = document.getElementsByTagName("textarea"); |
var tas = document.getElementsByTagName("textarea"); |
Line 271 HTMLArea.replaceAll = function(config) {
|
Line 343 HTMLArea.replaceAll = function(config) {
|
|
|
/** Helper function: replaces the TEXTAREA with the given ID with HTMLArea. */ |
/** Helper function: replaces the TEXTAREA with the given ID with HTMLArea. */ |
HTMLArea.replace = function(id, config) { |
HTMLArea.replace = function(id, config) { |
var ta = document.getElementById(id); |
var ta = HTMLArea.getElementById("textarea", id); |
return ta ? (new HTMLArea(ta, config)).generate() : null; |
return ta ? (new HTMLArea(ta, config)).generate() : null; |
}; |
}; |
|
|
Line 477 HTMLArea.prototype._createToolbar = func
|
Line 549 HTMLArea.prototype._createToolbar = func
|
} |
} |
}); |
}); |
var img = document.createElement("img"); |
var img = document.createElement("img"); |
img.src = editor.imgURL(btn[1]); |
img.src = btn[1]; |
img.style.width = "18px"; |
img.style.width = "18px"; |
img.style.height = "18px"; |
img.style.height = "18px"; |
el.appendChild(img); |
el.appendChild(img); |
Line 525 HTMLArea.prototype._createToolbar = func
|
Line 597 HTMLArea.prototype._createToolbar = func
|
}; |
}; |
|
|
HTMLArea.prototype._createStatusBar = function() { |
HTMLArea.prototype._createStatusBar = function() { |
var div = document.createElement("div"); |
var statusbar = document.createElement("div"); |
div.className = "statusBar"; |
statusbar.className = "statusBar"; |
this._htmlArea.appendChild(div); |
this._htmlArea.appendChild(statusbar); |
this._statusBar = div; |
this._statusBar = statusbar; |
div.appendChild(document.createTextNode(HTMLArea.I18N.msg["Path"] + ": ")); |
// statusbar.appendChild(document.createTextNode(HTMLArea.I18N.msg["Path"] + ": ")); |
// creates a holder for the path view |
// creates a holder for the path view |
div = document.createElement("span"); |
div = document.createElement("span"); |
div.className = "statusBarTree"; |
div.className = "statusBarTree"; |
|
div.innerHTML = HTMLArea.I18N.msg["Path"] + ": "; |
this._statusBarTree = div; |
this._statusBarTree = div; |
this._statusBar.appendChild(div); |
this._statusBar.appendChild(div); |
if (!this.config.statusBar) { |
if (!this.config.statusBar) { |
// disable it... |
// disable it... |
div.style.display = "none"; |
statusbar.style.display = "none"; |
} |
} |
}; |
}; |
|
|
Line 548 HTMLArea.prototype.generate = function (
|
Line 621 HTMLArea.prototype.generate = function (
|
var textarea = this._textArea; |
var textarea = this._textArea; |
if (typeof textarea == "string") { |
if (typeof textarea == "string") { |
// it's not element but ID |
// it's not element but ID |
this._textArea = textarea = document.getElementById(textarea); |
this._textArea = textarea = HTMLArea.getElementById("textarea", textarea); |
} |
} |
this._ta_size = { |
this._ta_size = { |
w: textarea.offsetWidth, |
w: textarea.offsetWidth, |
Line 567 HTMLArea.prototype.generate = function (
|
Line 640 HTMLArea.prototype.generate = function (
|
if (textarea.form) { |
if (textarea.form) { |
// we have a form, on submit get the HTMLArea content and |
// we have a form, on submit get the HTMLArea content and |
// update original textarea. |
// update original textarea. |
textarea.form.onsubmit = function() { |
var f = textarea.form; |
|
if (typeof f.onsubmit == "function") { |
|
var funcref = f.onsubmit; |
|
if (typeof f.__msh_prevOnSubmit == "undefined") { |
|
f.__msh_prevOnSubmit = []; |
|
} |
|
f.__msh_prevOnSubmit.push(funcref); |
|
} |
|
f.onsubmit = function() { |
editor._textArea.value = editor.getHTML(); |
editor._textArea.value = editor.getHTML(); |
|
var a = this.__msh_prevOnSubmit; |
|
// call previous submit methods if they were there. |
|
if (typeof a != "undefined") { |
|
for (var i in a) { |
|
a[i](); |
|
} |
|
} |
}; |
}; |
} |
} |
|
|
Line 636 HTMLArea.prototype.generate = function (
|
Line 724 HTMLArea.prototype.generate = function (
|
// FIXME: don't know what else to do here. Normally |
// FIXME: don't know what else to do here. Normally |
// we'll never reach this point. |
// we'll never reach this point. |
if (HTMLArea.is_gecko) { |
if (HTMLArea.is_gecko) { |
setTimeout(initIframe, 10); |
setTimeout(initIframe, 100); |
return false; |
return false; |
} else { |
} else { |
alert("ERROR: IFRAME can't be initialized."); |
alert("ERROR: IFRAME can't be initialized."); |
Line 647 HTMLArea.prototype.generate = function (
|
Line 735 HTMLArea.prototype.generate = function (
|
doc.designMode = "on"; |
doc.designMode = "on"; |
} |
} |
editor._doc = doc; |
editor._doc = doc; |
doc.open(); |
if (!editor.config.fullPage) { |
var html = "<html>\n"; |
doc.open(); |
html += "<head>\n"; |
var html = "<html>\n"; |
html += "<style>" + editor.config.pageStyle + "</style>\n"; |
html += "<head>\n"; |
html += "</head>\n"; |
if (editor.config.baseURL) |
html += "<body>\n"; |
html += '<base href="' + editor.config.baseURL + '" />'; |
html += editor._textArea.value; |
html += "<style> html,body { border: 0px; } " + |
html += "</body>\n"; |
editor.config.pageStyle + "</style>\n"; |
html += "</html>"; |
html += "</head>\n"; |
doc.write(html); |
html += "<body>\n"; |
doc.close(); |
html += editor._textArea.value; |
|
html += "</body>\n"; |
|
html += "</html>"; |
|
doc.write(html); |
|
doc.close(); |
|
} else { |
|
var html = editor._textArea.value; |
|
if (html.match(HTMLArea.RE_doctype)) { |
|
editor.setDoctype(RegExp.$1); |
|
html = html.replace(HTMLArea.RE_doctype, ""); |
|
} |
|
doc.open(); |
|
doc.write(html); |
|
doc.close(); |
|
} |
|
|
if (HTMLArea.is_ie) { |
if (HTMLArea.is_ie) { |
// enable editable mode for IE. For some reason this |
// enable editable mode for IE. For some reason this |
Line 673 HTMLArea.prototype.generate = function (
|
Line 775 HTMLArea.prototype.generate = function (
|
function (event) { |
function (event) { |
return editor._editorEvent(HTMLArea.is_ie ? editor._iframe.contentWindow.event : event); |
return editor._editorEvent(HTMLArea.is_ie ? editor._iframe.contentWindow.event : event); |
}); |
}); |
editor.updateToolbar(); |
|
|
// check if any plugins have registered refresh handlers |
|
for (var i in editor.plugins) { |
|
var plugin = editor.plugins[i].instance; |
|
if (typeof plugin.onGenerate == "function") |
|
plugin.onGenerate(); |
|
} |
|
|
|
setTimeout(function() { |
|
editor.updateToolbar(); |
|
}, 250); |
|
|
|
if (typeof editor.onGenerate == "function") |
|
editor.onGenerate(); |
}; |
}; |
setTimeout(initIframe, HTMLArea.is_gecko ? 10 : 0); |
setTimeout(initIframe, 100); |
}; |
}; |
|
|
// Switches editor mode; parameter can be "textmode" or "wysiwyg". If no |
// Switches editor mode; parameter can be "textmode" or "wysiwyg". If no |
Line 696 HTMLArea.prototype.setMode = function(mo
|
Line 811 HTMLArea.prototype.setMode = function(mo
|
case "wysiwyg": |
case "wysiwyg": |
if (HTMLArea.is_gecko) { |
if (HTMLArea.is_gecko) { |
// disable design mode before changing innerHTML |
// disable design mode before changing innerHTML |
this._doc.designMode = "off"; |
try { |
|
this._doc.designMode = "off"; |
|
} catch(e) {}; |
} |
} |
this._doc.body.innerHTML = this.getHTML(); |
if (!this.config.fullPage) |
|
this._doc.body.innerHTML = this.getHTML(); |
|
else |
|
this.setFullHTML(this.getHTML()); |
this._iframe.style.display = "block"; |
this._iframe.style.display = "block"; |
this._textArea.style.display = "none"; |
this._textArea.style.display = "none"; |
if (HTMLArea.is_gecko) { |
if (HTMLArea.is_gecko) { |
// we need to refresh that info for Moz-1.3a |
// we need to refresh that info for Moz-1.3a |
this._doc.designMode = "on"; |
try { |
|
this._doc.designMode = "on"; |
|
} catch(e) {}; |
} |
} |
if (this.config.statusBar) { |
if (this.config.statusBar) { |
this._statusBar.innerHTML = ''; |
this._statusBar.innerHTML = ''; |
Line 719 HTMLArea.prototype.setMode = function(mo
|
Line 841 HTMLArea.prototype.setMode = function(mo
|
this.focusEditor(); |
this.focusEditor(); |
}; |
}; |
|
|
|
HTMLArea.prototype.setFullHTML = function(html) { |
|
var save_multiline = RegExp.multiline; |
|
RegExp.multiline = true; |
|
if (html.match(HTMLArea.RE_doctype)) { |
|
this.setDoctype(RegExp.$1); |
|
html = html.replace(HTMLArea.RE_doctype, ""); |
|
} |
|
RegExp.multiline = save_multiline; |
|
if (!HTMLArea.is_ie) { |
|
if (html.match(HTMLArea.RE_head)) |
|
this._doc.getElementsByTagName("head")[0].innerHTML = RegExp.$1; |
|
if (html.match(HTMLArea.RE_body)) |
|
this._doc.getElementsByTagName("body")[0].innerHTML = RegExp.$1; |
|
} else { |
|
var html_re = /<html>((.|\n)*?)<\/html>/i; |
|
html = html.replace(html_re, "$1"); |
|
this._doc.open(); |
|
this._doc.write(html); |
|
this._doc.close(); |
|
this._doc.body.contentEditable = true; |
|
return true; |
|
} |
|
}; |
|
|
/*************************************************** |
/*************************************************** |
* Category: PLUGINS |
* Category: PLUGINS |
***************************************************/ |
***************************************************/ |
|
|
|
// this is the variant of the function above where the plugin arguments are |
|
// already packed in an array. Externally, it should be only used in the |
|
// full-screen editor code, in order to initialize plugins with the same |
|
// parameters as in the opener window. |
|
HTMLArea.prototype.registerPlugin2 = function(plugin, args) { |
|
if (typeof plugin == "string") |
|
plugin = eval(plugin); |
|
var obj = new plugin(this, args); |
|
if (obj) { |
|
var clone = {}; |
|
var info = plugin._pluginInfo; |
|
for (var i in info) |
|
clone[i] = info[i]; |
|
clone.instance = obj; |
|
clone.args = args; |
|
this.plugins[plugin._pluginInfo.name] = clone; |
|
} else |
|
alert("Can't register plugin " + plugin.toString() + "."); |
|
}; |
|
|
// Create the specified plugin and register it with this HTMLArea |
// Create the specified plugin and register it with this HTMLArea |
HTMLArea.prototype.registerPlugin = function(pluginName) { |
HTMLArea.prototype.registerPlugin = function() { |
this.plugins[pluginName] = eval("new " + pluginName + "(this);"); |
var plugin = arguments[0]; |
|
var args = []; |
|
for (var i = 1; i < arguments.length; ++i) |
|
args.push(arguments[i]); |
|
this.registerPlugin2(plugin, args); |
}; |
}; |
|
|
// static function that loads the required plugin and lang file, based on the |
// static function that loads the required plugin and lang file, based on the |
// language loaded already for HTMLArea. You better make sure that the plugin |
// language loaded already for HTMLArea. You better make sure that the plugin |
// _has_ that language, otherwise shit might happen ;-) |
// _has_ that language, otherwise shit might happen ;-) |
HTMLArea.loadPlugin = function(pluginName) { |
HTMLArea.loadPlugin = function(pluginName) { |
var editorurl = ''; |
var dir = _editor_url + "plugins/" + pluginName; |
if (typeof _editor_url != "undefined") { |
|
editorurl = _editor_url + "/"; |
|
} |
|
var dir = editorurl + "plugins/" + pluginName; |
|
var plugin = pluginName.replace(/([a-z])([A-Z])([a-z])/g, |
var plugin = pluginName.replace(/([a-z])([A-Z])([a-z])/g, |
function (str, l1, l2, l3) { |
function (str, l1, l2, l3) { |
return l1 + "-" + l2.toLowerCase() + l3; |
return l1 + "-" + l2.toLowerCase() + l3; |
}).toLowerCase() + ".js"; |
}).toLowerCase() + ".js"; |
document.write("<script type='text/javascript' src='" + dir + "/" + plugin + "'></script>"); |
var plugin_file = dir + "/" + plugin; |
document.write("<script type='text/javascript' src='" + dir + "/lang/" + HTMLArea.I18N.lang + ".js'></script>"); |
var plugin_lang = dir + "/lang/" + HTMLArea.I18N.lang + ".js"; |
|
HTMLArea._scripts.push(plugin_file, plugin_lang); |
|
document.write("<script type='text/javascript' src='" + plugin_file + "'></script>"); |
|
document.write("<script type='text/javascript' src='" + plugin_lang + "'></script>"); |
|
}; |
|
|
|
HTMLArea.loadStyle = function(style, plugin) { |
|
var url = _editor_url || ''; |
|
if (typeof plugin != "undefined") { |
|
url += "plugins/" + plugin + "/"; |
|
} |
|
url += style; |
|
document.write("<style type='text/css'>@import url(" + url + ");</style>"); |
}; |
}; |
|
//HTMLArea.loadStyle("htmlarea.css"); |
|
|
/*************************************************** |
/*************************************************** |
* Category: EDITOR UTILITIES |
* Category: EDITOR UTILITIES |
***************************************************/ |
***************************************************/ |
|
|
|
// The following function is a slight variation of the word cleaner code posted |
|
// by Weeezl (user @ InteractiveTools forums). |
|
HTMLArea.prototype._wordClean = function() { |
|
var D = this.getInnerHTML(); |
|
if (D.indexOf('class=Mso') >= 0) { |
|
|
|
// make one line |
|
D = D.replace(/\r\n/g, ' '). |
|
replace(/\n/g, ' '). |
|
replace(/\r/g, ' '). |
|
replace(/\ \;/g,' '); |
|
|
|
// keep tags, strip attributes |
|
D = D.replace(/ class=[^\s|>]*/gi,''). |
|
//replace(/<p [^>]*TEXT-ALIGN: justify[^>]*>/gi,'<p align="justify">'). |
|
replace(/ style=\"[^>]*\"/gi,''). |
|
replace(/ align=[^\s|>]*/gi,''); |
|
|
|
//clean up tags |
|
D = D.replace(/<b [^>]*>/gi,'<b>'). |
|
replace(/<i [^>]*>/gi,'<i>'). |
|
replace(/<li [^>]*>/gi,'<li>'). |
|
replace(/<ul [^>]*>/gi,'<ul>'); |
|
|
|
// replace outdated tags |
|
D = D.replace(/<b>/gi,'<strong>'). |
|
replace(/<\/b>/gi,'</strong>'); |
|
|
|
// mozilla doesn't like <em> tags |
|
D = D.replace(/<em>/gi,'<i>'). |
|
replace(/<\/em>/gi,'</i>'); |
|
|
|
// kill unwanted tags |
|
D = D.replace(/<\?xml:[^>]*>/g, ''). // Word xml |
|
replace(/<\/?st1:[^>]*>/g,''). // Word SmartTags |
|
replace(/<\/?[a-z]\:[^>]*>/g,''). // All other funny Word non-HTML stuff |
|
replace(/<\/?font[^>]*>/gi,''). // Disable if you want to keep font formatting |
|
replace(/<\/?span[^>]*>/gi,' '). |
|
replace(/<\/?div[^>]*>/gi,' '). |
|
replace(/<\/?pre[^>]*>/gi,' '). |
|
replace(/<\/?h[1-6][^>]*>/gi,' '); |
|
|
|
//remove empty tags |
|
//D = D.replace(/<strong><\/strong>/gi,''). |
|
//replace(/<i><\/i>/gi,''). |
|
//replace(/<P[^>]*><\/P>/gi,''); |
|
|
|
// nuke double tags |
|
oldlen = D.length + 1; |
|
while(oldlen > D.length) { |
|
oldlen = D.length; |
|
// join us now and free the tags, we'll be free hackers, we'll be free... ;-) |
|
D = D.replace(/<([a-z][a-z]*)> *<\/\1>/gi,' '). |
|
replace(/<([a-z][a-z]*)> *<([a-z][^>]*)> *<\/\1>/gi,'<$2>'); |
|
} |
|
D = D.replace(/<([a-z][a-z]*)><\1>/gi,'<$1>'). |
|
replace(/<\/([a-z][a-z]*)><\/\1>/gi,'<\/$1>'); |
|
|
|
// nuke double spaces |
|
D = D.replace(/ */gi,' '); |
|
|
|
this.setHTML(D); |
|
this.updateToolbar(); |
|
} |
|
}; |
|
|
HTMLArea.prototype.forceRedraw = function() { |
HTMLArea.prototype.forceRedraw = function() { |
this._doc.body.style.visibility = "hidden"; |
this._doc.body.style.visibility = "hidden"; |
this._doc.body.style.visibility = "visible"; |
this._doc.body.style.visibility = "visible"; |
Line 765 HTMLArea.prototype.focusEditor = functio
|
Line 1010 HTMLArea.prototype.focusEditor = functio
|
return this._doc; |
return this._doc; |
}; |
}; |
|
|
|
// takes a snapshot of the current text (for undo) |
|
HTMLArea.prototype._undoTakeSnapshot = function() { |
|
++this._undoPos; |
|
if (this._undoPos >= this.config.undoSteps) { |
|
// remove the first element |
|
this._undoQueue.shift(); |
|
--this._undoPos; |
|
} |
|
// use the fasted method (getInnerHTML); |
|
var take = true; |
|
var txt = this.getInnerHTML(); |
|
if (this._undoPos > 0) |
|
take = (this._undoQueue[this._undoPos - 1] != txt); |
|
if (take) { |
|
this._undoQueue[this._undoPos] = txt; |
|
} else { |
|
this._undoPos--; |
|
} |
|
}; |
|
|
|
HTMLArea.prototype.undo = function() { |
|
if (this._undoPos > 0) { |
|
var txt = this._undoQueue[--this._undoPos]; |
|
if (txt) this.setHTML(txt); |
|
else ++this._undoPos; |
|
} |
|
}; |
|
|
|
HTMLArea.prototype.redo = function() { |
|
if (this._undoPos < this._undoQueue.length - 1) { |
|
var txt = this._undoQueue[++this._undoPos]; |
|
if (txt) this.setHTML(txt); |
|
else --this._undoPos; |
|
} |
|
}; |
|
|
// updates enabled/disable/active state of the toolbar elements |
// updates enabled/disable/active state of the toolbar elements |
HTMLArea.prototype.updateToolbar = function(noStatus) { |
HTMLArea.prototype.updateToolbar = function(noStatus) { |
var doc = this._doc; |
var doc = this._doc; |
Line 773 HTMLArea.prototype.updateToolbar = funct
|
Line 1054 HTMLArea.prototype.updateToolbar = funct
|
if (!text) { |
if (!text) { |
ancestors = this.getAllAncestors(); |
ancestors = this.getAllAncestors(); |
if (this.config.statusBar && !noStatus) { |
if (this.config.statusBar && !noStatus) { |
this._statusBarTree.innerHTML = ''; // clear |
this._statusBarTree.innerHTML = HTMLArea.I18N.msg["Path"] + ": "; // clear |
for (var i = ancestors.length; --i >= 0;) { |
for (var i = ancestors.length; --i >= 0;) { |
var el = ancestors[i]; |
var el = ancestors[i]; |
if (!el) { |
if (!el) { |
Line 864 HTMLArea.prototype.updateToolbar = funct
|
Line 1145 HTMLArea.prototype.updateToolbar = funct
|
case "fontname": |
case "fontname": |
case "fontsize": |
case "fontsize": |
case "formatblock": |
case "formatblock": |
if (!text) { |
if (!text) try { |
var value = ("" + doc.queryCommandValue(cmd)).toLowerCase(); |
var value = ("" + doc.queryCommandValue(cmd)).toLowerCase(); |
if (!value) { |
if (!value) { |
// FIXME: what do we do here? |
// FIXME: what do we do here? |
Line 886 HTMLArea.prototype.updateToolbar = funct
|
Line 1167 HTMLArea.prototype.updateToolbar = funct
|
} |
} |
++k; |
++k; |
} |
} |
} |
} catch(e) {}; |
break; |
break; |
case "textindicator": |
case "textindicator": |
if (!text) { |
if (!text) { |
Line 907 HTMLArea.prototype.updateToolbar = funct
|
Line 1188 HTMLArea.prototype.updateToolbar = funct
|
} |
} |
break; |
break; |
case "htmlmode": btn.state("active", text); break; |
case "htmlmode": btn.state("active", text); break; |
|
case "lefttoright": |
|
case "righttoleft": |
|
var el = this.getParentElement(); |
|
while (el && !HTMLArea.isBlockElement(el)) |
|
el = el.parentNode; |
|
if (el) |
|
btn.state("active", (el.style.direction == ((cmd == "righttoleft") ? "rtl" : "ltr"))); |
|
break; |
default: |
default: |
try { |
try { |
btn.state("active", (!text && doc.queryCommandState(cmd))); |
btn.state("active", (!text && doc.queryCommandState(cmd))); |
} catch (e) {} |
} catch (e) {} |
} |
} |
} |
} |
|
// take undo snapshots |
|
if (this._customUndo && !this._timerUndo) { |
|
this._undoTakeSnapshot(); |
|
var editor = this; |
|
this._timerUndo = setTimeout(function() { |
|
editor._timerUndo = null; |
|
}, this.config.undoTimeout); |
|
} |
|
// check if any plugins have registered refresh handlers |
|
for (var i in this.plugins) { |
|
var plugin = this.plugins[i].instance; |
|
if (typeof plugin.onUpdateToolbar == "function") |
|
plugin.onUpdateToolbar(); |
|
} |
}; |
}; |
|
|
/** Returns a node after which we can insert other nodes, in the current |
/** Returns a node after which we can insert other nodes, in the current |
Line 968 HTMLArea.prototype.getParentElement = fu
|
Line 1271 HTMLArea.prototype.getParentElement = fu
|
var sel = this._getSelection(); |
var sel = this._getSelection(); |
var range = this._createRange(sel); |
var range = this._createRange(sel); |
if (HTMLArea.is_ie) { |
if (HTMLArea.is_ie) { |
return range.parentElement ? range.parentElement() : this._doc.body; |
switch (sel.type) { |
} else { |
case "Text": |
|
case "None": |
|
// It seems that even for selection of type "None", |
|
// there _is_ a parent element and it's value is not |
|
// only correct, but very important to us. MSIE is |
|
// certainly the buggiest browser in the world and I |
|
// wonder, God, how can Earth stand it? |
|
return range.parentElement(); |
|
case "Control": |
|
return range.item(0); |
|
default: |
|
return this._doc.body; |
|
} |
|
} else try { |
var p = range.commonAncestorContainer; |
var p = range.commonAncestorContainer; |
|
if (!range.collapsed && range.startContainer == range.endContainer && |
|
range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes()) |
|
p = range.startContainer.childNodes[range.startOffset]; |
|
/* |
|
alert(range.startContainer + ":" + range.startOffset + "\n" + |
|
range.endContainer + ":" + range.endOffset); |
|
*/ |
while (p.nodeType == 3) { |
while (p.nodeType == 3) { |
p = p.parentNode; |
p = p.parentNode; |
} |
} |
return p; |
return p; |
|
} catch (e) { |
|
return null; |
} |
} |
}; |
}; |
|
|
Line 1051 HTMLArea.prototype.getSelectedHTML = fun
|
Line 1376 HTMLArea.prototype.getSelectedHTML = fun
|
if (HTMLArea.is_ie) { |
if (HTMLArea.is_ie) { |
existing = range.htmlText; |
existing = range.htmlText; |
} else { |
} else { |
existing = HTMLArea.getHTML(range.cloneContents(), false); |
existing = HTMLArea.getHTML(range.cloneContents(), false, this); |
} |
} |
return existing; |
return existing; |
}; |
}; |
|
|
// Called when the user clicks on "InsertImage" button |
/// Return true if we have some selection |
HTMLArea.prototype._insertImage = function() { |
HTMLArea.prototype.hasSelectedText = function() { |
|
// FIXME: come _on_ mishoo, you can do better than this ;-) |
|
return this.getSelectedHTML() != ''; |
|
}; |
|
|
|
HTMLArea.prototype._createLink = function(link) { |
|
var editor = this; |
|
var outparam = null; |
|
if (typeof link == "undefined") { |
|
link = this.getParentElement(); |
|
if (link && !/^a$/i.test(link.tagName)) |
|
link = null; |
|
} |
|
if (link) outparam = { |
|
f_href : HTMLArea.is_ie ? editor.stripBaseURL(link.href) : link.getAttribute("href"), |
|
f_title : link.title, |
|
f_target : link.target |
|
}; |
|
this._popupDialog("link.html", function(param) { |
|
if (!param) |
|
return false; |
|
var a = link; |
|
if (!a) { |
|
editor._doc.execCommand("createlink", false, param.f_href); |
|
a = editor.getParentElement(); |
|
var sel = editor._getSelection(); |
|
var range = editor._createRange(sel); |
|
if (!HTMLArea.is_ie) { |
|
a = range.startContainer; |
|
if (!/^a$/i.test(a.tagName)) |
|
a = a.nextSibling; |
|
} |
|
} else a.href = param.f_href.trim(); |
|
if (!/^a$/i.test(a.tagName)) |
|
return false; |
|
a.target = param.f_target.trim(); |
|
a.title = param.f_title.trim(); |
|
editor.selectNodeContents(a); |
|
editor.updateToolbar(); |
|
}, outparam); |
|
}; |
|
|
|
// Called when the user clicks on "InsertImage" button. If an image is already |
|
// there, it will just modify it's properties. |
|
HTMLArea.prototype._insertImage = function(image) { |
var editor = this; // for nested functions |
var editor = this; // for nested functions |
|
var outparam = null; |
|
if (typeof image == "undefined") { |
|
image = this.getParentElement(); |
|
if (image && !/^img$/i.test(image.tagName)) |
|
image = null; |
|
} |
|
if (image) outparam = { |
|
f_url : HTMLArea.is_ie ? editor.stripBaseURL(image.src) : image.getAttribute("src"), |
|
f_alt : image.alt, |
|
f_border : image.border, |
|
f_align : image.align, |
|
f_vert : image.vspace, |
|
f_horiz : image.hspace |
|
}; |
this._popupDialog("insert_image.html", function(param) { |
this._popupDialog("insert_image.html", function(param) { |
if (!param) { // user must have pressed Cancel |
if (!param) { // user must have pressed Cancel |
return false; |
return false; |
} |
} |
var sel = editor._getSelection(); |
var img = image; |
var range = editor._createRange(sel); |
if (!img) { |
editor._doc.execCommand("insertimage", false, param["f_url"]); |
var sel = editor._getSelection(); |
var img = null; |
var range = editor._createRange(sel); |
if (HTMLArea.is_ie) { |
editor._doc.execCommand("insertimage", false, param.f_url); |
img = range.parentElement(); |
if (HTMLArea.is_ie) { |
// wonder if this works... |
img = range.parentElement(); |
if (img.tagName.toLowerCase() != "img") { |
// wonder if this works... |
img = img.previousSibling; |
if (img.tagName.toLowerCase() != "img") { |
|
img = img.previousSibling; |
|
} |
|
} else { |
|
img = range.startContainer.previousSibling; |
} |
} |
} else { |
} else { |
img = range.startContainer.previousSibling; |
img.src = param.f_url; |
} |
} |
for (field in param) { |
for (field in param) { |
var value = param[field]; |
var value = param[field]; |
if (!value) { |
|
continue; |
|
} |
|
switch (field) { |
switch (field) { |
case "f_alt" : img.alt = value; break; |
case "f_alt" : img.alt = value; break; |
case "f_border" : img.border = parseInt(value); break; |
case "f_border" : img.border = parseInt(value || "0"); break; |
case "f_align" : img.align = value; break; |
case "f_align" : img.align = value; break; |
case "f_vert" : img.vspace = parseInt(value); break; |
case "f_vert" : img.vspace = parseInt(value || "0"); break; |
case "f_horiz" : img.hspace = parseInt(value); break; |
case "f_horiz" : img.hspace = parseInt(value || "0"); break; |
} |
} |
} |
} |
}, null); |
}, outparam); |
}; |
}; |
|
|
// Called when the user clicks the Insert Table button |
// Called when the user clicks the Insert Table button |
Line 1172 HTMLArea.prototype._comboSelected = func
|
Line 1556 HTMLArea.prototype._comboSelected = func
|
HTMLArea.prototype.execCommand = function(cmdID, UI, param) { |
HTMLArea.prototype.execCommand = function(cmdID, UI, param) { |
var editor = this; // for nested functions |
var editor = this; // for nested functions |
this.focusEditor(); |
this.focusEditor(); |
switch (cmdID.toLowerCase()) { |
cmdID = cmdID.toLowerCase(); |
|
switch (cmdID) { |
case "htmlmode" : this.setMode(); break; |
case "htmlmode" : this.setMode(); break; |
case "hilitecolor": |
case "hilitecolor": |
(HTMLArea.is_ie) && (cmdID = "backcolor"); |
(HTMLArea.is_ie) && (cmdID = "backcolor"); |
Line 1184 HTMLArea.prototype.execCommand = functio
|
Line 1569 HTMLArea.prototype.execCommand = functio
|
}, HTMLArea._colorToRgb(this._doc.queryCommandValue(cmdID))); |
}, HTMLArea._colorToRgb(this._doc.queryCommandValue(cmdID))); |
break; |
break; |
case "createlink": |
case "createlink": |
if (HTMLArea.is_ie || !UI) { |
this._createLink(); |
this._doc.execCommand(cmdID, UI, param); |
|
} else { |
|
// browser is Mozilla & wants UI |
|
var param; |
|
if ((param = prompt("Enter URL"))) { |
|
this._doc.execCommand(cmdID, false, param); |
|
} |
|
} |
|
break; |
break; |
case "popupeditor": |
case "popupeditor": |
|
// this object will be passed to the newly opened window |
|
HTMLArea._object = this; |
if (HTMLArea.is_ie) { |
if (HTMLArea.is_ie) { |
window.open(this.popupURL("fullscreen.html"), "ha_fullscreen", |
//if (confirm(HTMLArea.I18N.msg["IE-sucks-full-screen"])) |
"toolbar=no,location=no,directories=no,status=no,menubar=no," + |
{ |
"scrollbars=no,resizable=yes,width=640,height=480"); |
window.open(this.popupURL("fullscreen.html"), "ha_fullscreen", |
|
"toolbar=no,location=no,directories=no,status=no,menubar=no," + |
|
"scrollbars=no,resizable=yes,width=640,height=480"); |
|
} |
} else { |
} else { |
window.open(this.popupURL("fullscreen.html"), "ha_fullscreen", |
window.open(this.popupURL("fullscreen.html"), "ha_fullscreen", |
"toolbar=no,menubar=no,personalbar=no,width=640,height=480," + |
"toolbar=no,menubar=no,personalbar=no,width=640,height=480," + |
"scrollbars=no,resizable=yes"); |
"scrollbars=no,resizable=yes"); |
} |
} |
// pass this object to the newly opened window |
break; |
HTMLArea._object = this; |
case "undo": |
|
case "redo": |
|
if (this._customUndo) |
|
this[cmdID](); |
|
else |
|
this._doc.execCommand(cmdID, UI, param); |
break; |
break; |
case "inserttable": this._insertTable(); break; |
case "inserttable": this._insertTable(); break; |
case "insertimage": this._insertImage(); break; |
case "insertimage": this._insertImage(); break; |
case "about" : this._popupDialog("about.html", null, null); break; |
case "about" : this._popupDialog("about.html", null, this); break; |
case "showhelp" : window.open("reference.html", "ha_help"); break; |
case "showhelp" : window.open(_editor_url + "reference.html", "ha_help"); break; |
|
|
|
case "killword": this._wordClean(); break; |
|
|
|
case "cut": |
|
case "copy": |
|
case "paste": |
|
try { |
|
if (this.config.killWordOnPaste) |
|
this._wordClean(); |
|
this._doc.execCommand(cmdID, UI, param); |
|
} catch (e) { |
|
if (HTMLArea.is_gecko) { |
|
if (confirm("Unprivileged scripts cannot access Cut/Copy/Paste programatically " + |
|
"for security reasons. Click OK to see a technical note at mozilla.org " + |
|
"which shows you how to allow a script to access the clipboard.")) |
|
window.open("http://mozilla.org/editor/midasdemo/securityprefs.html"); |
|
} |
|
} |
|
break; |
|
case "lefttoright": |
|
case "righttoleft": |
|
var dir = (cmdID == "righttoleft") ? "rtl" : "ltr"; |
|
var el = this.getParentElement(); |
|
while (el && !HTMLArea.isBlockElement(el)) |
|
el = el.parentNode; |
|
if (el) { |
|
if (el.style.direction == dir) |
|
el.style.direction = ""; |
|
else |
|
el.style.direction = dir; |
|
} |
|
break; |
default: this._doc.execCommand(cmdID, UI, param); |
default: this._doc.execCommand(cmdID, UI, param); |
} |
} |
this.updateToolbar(); |
this.updateToolbar(); |
Line 1222 HTMLArea.prototype.execCommand = functio
|
Line 1641 HTMLArea.prototype.execCommand = functio
|
HTMLArea.prototype._editorEvent = function(ev) { |
HTMLArea.prototype._editorEvent = function(ev) { |
var editor = this; |
var editor = this; |
var keyEvent = (HTMLArea.is_ie && ev.type == "keydown") || (ev.type == "keypress"); |
var keyEvent = (HTMLArea.is_ie && ev.type == "keydown") || (ev.type == "keypress"); |
|
if (keyEvent) { |
|
for (var i in editor.plugins) { |
|
var plugin = editor.plugins[i].instance; |
|
if (typeof plugin.onKeyPress == "function") plugin.onKeyPress(ev); |
|
} |
|
} |
if (keyEvent && ev.ctrlKey) { |
if (keyEvent && ev.ctrlKey) { |
var sel = null; |
var sel = null; |
var range = null; |
var range = null; |
Line 1251 HTMLArea.prototype._editorEvent = functi
|
Line 1676 HTMLArea.prototype._editorEvent = functi
|
case 'e': cmd = "justifycenter"; break; |
case 'e': cmd = "justifycenter"; break; |
case 'r': cmd = "justifyright"; break; |
case 'r': cmd = "justifyright"; break; |
case 'j': cmd = "justifyfull"; break; |
case 'j': cmd = "justifyfull"; break; |
|
case 'z': cmd = "undo"; break; |
|
case 'y': cmd = "redo"; break; |
|
case 'v': cmd = "paste"; break; |
|
|
|
case '0': cmd = "killword"; break; |
|
|
// headings |
// headings |
case '1': |
case '1': |
Line 1298 HTMLArea.prototype._editorEvent = functi
|
Line 1728 HTMLArea.prototype._editorEvent = functi
|
// retrieve the HTML |
// retrieve the HTML |
HTMLArea.prototype.getHTML = function() { |
HTMLArea.prototype.getHTML = function() { |
switch (this._editMode) { |
switch (this._editMode) { |
case "wysiwyg" : return HTMLArea.getHTML(this._doc.body, false); |
case "wysiwyg" : |
|
if (!this.config.fullPage) { |
|
return HTMLArea.getHTML(this._doc.body, false, this); |
|
} else |
|
return this.doctype + "\n" + HTMLArea.getHTML(this._doc.documentElement, true, this); |
case "textmode" : return this._textArea.value; |
case "textmode" : return this._textArea.value; |
default : alert("Mode <" + mode + "> not defined!"); |
default : alert("Mode <" + mode + "> not defined!"); |
} |
} |
Line 1308 HTMLArea.prototype.getHTML = function()
|
Line 1742 HTMLArea.prototype.getHTML = function()
|
// retrieve the HTML (fastest version, but uses innerHTML) |
// retrieve the HTML (fastest version, but uses innerHTML) |
HTMLArea.prototype.getInnerHTML = function() { |
HTMLArea.prototype.getInnerHTML = function() { |
switch (this._editMode) { |
switch (this._editMode) { |
case "wysiwyg" : return this._doc.body.innerHTML; |
case "wysiwyg" : |
|
if (!this.config.fullPage) |
|
return this._doc.body.innerHTML; |
|
else |
|
return this.doctype + "\n" + this._doc.documentElement.innerHTML; |
case "textmode" : return this._textArea.value; |
case "textmode" : return this._textArea.value; |
default : alert("Mode <" + mode + "> not defined!"); |
default : alert("Mode <" + mode + "> not defined!"); |
} |
} |
Line 1318 HTMLArea.prototype.getInnerHTML = functi
|
Line 1756 HTMLArea.prototype.getInnerHTML = functi
|
// completely change the HTML inside |
// completely change the HTML inside |
HTMLArea.prototype.setHTML = function(html) { |
HTMLArea.prototype.setHTML = function(html) { |
switch (this._editMode) { |
switch (this._editMode) { |
case "wysiwyg" : this._doc.body.innerHTML = html; break; |
case "wysiwyg" : |
|
if (!this.config.fullPage) |
|
this._doc.body.innerHTML = html; |
|
else |
|
// this._doc.documentElement.innerHTML = html; |
|
this._doc.body.innerHTML = html; |
|
break; |
case "textmode" : this._textArea.value = html; break; |
case "textmode" : this._textArea.value = html; break; |
default : alert("Mode <" + mode + "> not defined!"); |
default : alert("Mode <" + mode + "> not defined!"); |
} |
} |
return false; |
return false; |
}; |
}; |
|
|
|
// sets the given doctype (useful when config.fullPage is true) |
|
HTMLArea.prototype.setDoctype = function(doctype) { |
|
this.doctype = doctype; |
|
}; |
|
|
/*************************************************** |
/*************************************************** |
* Category: UTILITY FUNCTIONS |
* Category: UTILITY FUNCTIONS |
***************************************************/ |
***************************************************/ |
Line 1342 HTMLArea.is_gecko = (navigator.product
|
Line 1791 HTMLArea.is_gecko = (navigator.product
|
// variable used to pass the object to the popup editor window. |
// variable used to pass the object to the popup editor window. |
HTMLArea._object = null; |
HTMLArea._object = null; |
|
|
|
// function that returns a clone of the given object |
|
HTMLArea.cloneObject = function(obj) { |
|
var newObj = new Object; |
|
|
|
// check for array objects |
|
if (obj.constructor.toString().indexOf("function Array(") == 1) { |
|
newObj = obj.constructor(); |
|
} |
|
|
|
// check for function objects (as usual, IE is fucked up) |
|
if (obj.constructor.toString().indexOf("function Function(") == 1) { |
|
newObj = obj; // just copy reference to it |
|
} else for (var n in obj) { |
|
var node = obj[n]; |
|
if (typeof node == 'object') { newObj[n] = HTMLArea.cloneObject(node); } |
|
else { newObj[n] = node; } |
|
} |
|
|
|
return newObj; |
|
}; |
|
|
// FIXME!!! this should return false for IE < 5.5 |
// FIXME!!! this should return false for IE < 5.5 |
HTMLArea.checkSupportedBrowser = function() { |
HTMLArea.checkSupportedBrowser = function() { |
if (HTMLArea.is_gecko) { |
if (HTMLArea.is_gecko) { |
if (navigator.productSub < 20021201) { |
if (navigator.productSub < 20021201) { |
alert("You need at least Mozilla-1.3 Alpha.\n" + |
window.status="WYSIWYG Editor: You need at least Mozilla-1.3 Alpha. " + |
"Sorry, your Gecko is not supported."); |
"Sorry, your Gecko is not supported."; |
return false; |
return false; |
} |
} |
if (navigator.productSub < 20030210) { |
if (navigator.productSub < 20030210) { |
alert("Mozilla < 1.3 Beta is not supported!\n" + |
window.status="WYSIWYG Editor: Mozilla < 1.3 Beta is not supported! " + |
"I'll try, though, but it might not work."); |
"I'll try, though, but it might not work."; |
} |
} |
} |
} |
return HTMLArea.is_gecko || HTMLArea.is_ie; |
return HTMLArea.is_gecko || HTMLArea.is_ie; |
Line 1376 HTMLArea.prototype._createRange = functi
|
Line 1846 HTMLArea.prototype._createRange = functi
|
} else { |
} else { |
this.focusEditor(); |
this.focusEditor(); |
if (typeof sel != "undefined") { |
if (typeof sel != "undefined") { |
return sel.getRangeAt(0); |
try { |
|
return sel.getRangeAt(0); |
|
} catch(e) { |
|
return this._doc.createRange(); |
|
} |
} else { |
} else { |
return this._doc.createRange(); |
return this._doc.createRange(); |
} |
} |
Line 1464 HTMLArea.isBlockElement = function(el) {
|
Line 1938 HTMLArea.isBlockElement = function(el) {
|
}; |
}; |
|
|
HTMLArea.needsClosingTag = function(el) { |
HTMLArea.needsClosingTag = function(el) { |
var closingTags = " script style div span tr td tbody table em strong font a "; |
var closingTags = " head script style div span tr td tbody table em strong font a title "; |
return (closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); |
return (closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); |
}; |
}; |
|
|
Line 1482 HTMLArea.htmlEncode = function(str) {
|
Line 1956 HTMLArea.htmlEncode = function(str) {
|
|
|
// Retrieves the HTML code from the given node. This is a replacement for |
// Retrieves the HTML code from the given node. This is a replacement for |
// getting innerHTML, using standard DOM calls. |
// getting innerHTML, using standard DOM calls. |
HTMLArea.getHTML = function(root, outputRoot) { |
HTMLArea.getHTML = function(root, outputRoot, editor) { |
var html = ""; |
var html = ""; |
switch (root.nodeType) { |
switch (root.nodeType) { |
case 1: // Node.ELEMENT_NODE |
case 1: // Node.ELEMENT_NODE |
case 11: // Node.DOCUMENT_FRAGMENT_NODE |
case 11: // Node.DOCUMENT_FRAGMENT_NODE |
var closed; |
var closed; |
var i; |
var i; |
if (outputRoot) { |
var root_tag = (root.nodeType == 1) ? root.tagName.toLowerCase() : ''; |
|
if (HTMLArea.is_ie && root_tag == "head") { |
|
if (outputRoot) |
|
html += "<head>"; |
|
// lowercasize |
|
var save_multiline = RegExp.multiline; |
|
RegExp.multiline = true; |
|
var txt = root.innerHTML.replace(HTMLArea.RE_tagName, function(str, p1, p2) { |
|
return p1 + p2.toLowerCase(); |
|
}); |
|
RegExp.multiline = save_multiline; |
|
html += txt; |
|
if (outputRoot) |
|
html += "</head>"; |
|
break; |
|
} else if (outputRoot) { |
closed = (!(root.hasChildNodes() || HTMLArea.needsClosingTag(root))); |
closed = (!(root.hasChildNodes() || HTMLArea.needsClosingTag(root))); |
html = "<" + root.tagName.toLowerCase(); |
html = "<" + root.tagName.toLowerCase(); |
var attrs = root.attributes; |
var attrs = root.attributes; |
Line 1499 HTMLArea.getHTML = function(root, output
|
Line 1988 HTMLArea.getHTML = function(root, output
|
continue; |
continue; |
} |
} |
var name = a.nodeName.toLowerCase(); |
var name = a.nodeName.toLowerCase(); |
if (/_moz/.test(name)) { |
if (/_moz|contenteditable|_msh/.test(name)) { |
// Mozilla reports some special tags |
// avoid certain attributes |
// here; we don't need them. |
|
continue; |
continue; |
} |
} |
var value; |
var value; |
Line 1513 HTMLArea.getHTML = function(root, output
|
Line 2001 HTMLArea.getHTML = function(root, output
|
// I'm starting to HATE JavaScript |
// I'm starting to HATE JavaScript |
// development. Browser differences |
// development. Browser differences |
// suck. |
// suck. |
if (typeof root[a.nodeName] != "undefined") { |
// |
|
// Using Gecko the values of href and src are converted to absolute links |
|
// unless we get them using nodeValue() |
|
if (typeof root[a.nodeName] != "undefined" && name != "href" && name != "src") { |
value = root[a.nodeName]; |
value = root[a.nodeName]; |
} else { |
} else { |
value = a.nodeValue; |
value = a.nodeValue; |
|
// IE seems not willing to return the original values - it converts to absolute |
|
// links using a.nodeValue, a.value, a.stringValue, root.getAttribute("href") |
|
// So we have to strip the baseurl manually -/ |
|
if (HTMLArea.is_ie && (name == "href" || name == "src")) { |
|
value = editor.stripBaseURL(value); |
|
} |
} |
} |
} else { // IE fails to put style in attributes list |
} else { // IE fails to put style in attributes list |
// FIXME: cssText reported by IE is UPPERCASE |
// FIXME: cssText reported by IE is UPPERCASE |
value = root.style.cssText; |
value = root.style.cssText; |
} |
} |
if (/_moz/.test(value)) { |
if (/(_moz|^$)/.test(value)) { |
// Mozilla reports some special tags |
// Mozilla reports some special tags |
// here; we don't need them. |
// here; we don't need them. |
continue; |
continue; |
Line 1532 HTMLArea.getHTML = function(root, output
|
Line 2029 HTMLArea.getHTML = function(root, output
|
html += closed ? " />" : ">"; |
html += closed ? " />" : ">"; |
} |
} |
for (i = root.firstChild; i; i = i.nextSibling) { |
for (i = root.firstChild; i; i = i.nextSibling) { |
html += HTMLArea.getHTML(i, true); |
html += HTMLArea.getHTML(i, true, editor); |
} |
} |
if (outputRoot && !closed) { |
if (outputRoot && !closed) { |
html += "</" + root.tagName.toLowerCase() + ">"; |
html += "</" + root.tagName.toLowerCase() + ">"; |
} |
} |
break; |
break; |
case 3: // Node.TEXT_NODE |
case 3: // Node.TEXT_NODE |
html = HTMLArea.htmlEncode(root.data); |
// If a text node is alone in an element and all spaces, replace it with an non breaking one |
|
// This partially undoes the damage done by moz, which translates ' 's into spaces in the data element |
|
// this was but since are document encodings are all over the place it causes random havoc |
|
if ( !root.previousSibling && !root.nextSibling && root.data.match(/^\s*$/i) ) html = ' '; |
|
else html = HTMLArea.htmlEncode(root.data); |
break; |
break; |
case 8: // Node.COMMENT_NODE |
case 8: // Node.COMMENT_NODE |
html = "<!--" + root.data + "-->"; |
html = "<!--" + root.data + "-->"; |
Line 1548 HTMLArea.getHTML = function(root, output
|
Line 2049 HTMLArea.getHTML = function(root, output
|
return html; |
return html; |
}; |
}; |
|
|
|
HTMLArea.prototype.stripBaseURL = function(string) { |
|
var baseurl = this.config.baseURL; |
|
|
|
// strip to last directory in case baseurl points to a file |
|
baseurl = baseurl.replace(/[^\/]+$/, ''); |
|
var basere = new RegExp(baseurl); |
|
string = string.replace(basere, ""); |
|
|
|
// strip host-part of URL which is added by MSIE to links relative to server root |
|
baseurl = baseurl.replace(/^(https?:\/\/[^\/]+)(.*)$/, '$1'); |
|
basere = new RegExp(baseurl); |
|
return string.replace(basere, ""); |
|
}; |
|
|
|
String.prototype.trim = function() { |
|
a = this.replace(/^\s+/, ''); |
|
return a.replace(/\s+$/, ''); |
|
}; |
|
|
// creates a rgb-style color from a number |
// creates a rgb-style color from a number |
HTMLArea._makeColor = function(v) { |
HTMLArea._makeColor = function(v) { |
if (typeof v != "number") { |
if (typeof v != "number") { |
Line 1563 HTMLArea._makeColor = function(v) {
|
Line 2083 HTMLArea._makeColor = function(v) {
|
|
|
// returns hexadecimal color representation from a number or a rgb-style color. |
// returns hexadecimal color representation from a number or a rgb-style color. |
HTMLArea._colorToRgb = function(v) { |
HTMLArea._colorToRgb = function(v) { |
|
if (!v) |
|
return ''; |
|
|
// returns the hex representation of one byte (2 digits) |
// returns the hex representation of one byte (2 digits) |
function hex(d) { |
function hex(d) { |
return (d < 16) ? ("0" + d.toString(16)) : d.toString(16); |
return (d < 16) ? ("0" + d.toString(16)) : d.toString(16); |
Line 1590 HTMLArea._colorToRgb = function(v) {
|
Line 2113 HTMLArea._colorToRgb = function(v) {
|
return null; |
return null; |
} |
} |
|
|
if (v[0] == "#") { |
if (v.substr(0, 1) == "#") { |
// already hex rgb (hopefully :D ) |
// already hex rgb (hopefully :D ) |
return v; |
return v; |
} |
} |
Line 1611 HTMLArea.prototype._popupDialog = functi
|
Line 2134 HTMLArea.prototype._popupDialog = functi
|
// paths |
// paths |
|
|
HTMLArea.prototype.imgURL = function(file, plugin) { |
HTMLArea.prototype.imgURL = function(file, plugin) { |
if (typeof plugin == "undefined") { |
if (typeof plugin == "undefined") |
return this.config.editorURL + file; |
return _editor_url + file; |
} else { |
else |
return this.config.editorURL + "plugins/" + plugin + "/img/" + file; |
return _editor_url + "plugins/" + plugin + "/img/" + file; |
} |
|
}; |
}; |
|
|
HTMLArea.prototype.popupURL = function(file) { |
HTMLArea.prototype.popupURL = function(file) { |
return this.config.editorURL + this.config.popupURL + file; |
var url = ""; |
|
if (file.match(/^plugin:\/\/(.*?)\/(.*)/)) { |
|
var plugin = RegExp.$1; |
|
var popup = RegExp.$2; |
|
if (!/\.html$/.test(popup)) |
|
popup += ".html"; |
|
url = _editor_url + "plugins/" + plugin + "/popups/" + popup; |
|
} else |
|
url = _editor_url + this.config.popupURL + file; |
|
return url; |
}; |
}; |
|
|
|
/** |
|
* FIX: Internet Explorer returns an item having the _name_ equal to the given |
|
* id, even if it's not having any id. This way it can return a different form |
|
* field even if it's not a textarea. This workarounds the problem by |
|
* specifically looking to search only elements having a certain tag name. |
|
*/ |
|
HTMLArea.getElementById = function(tag, id) { |
|
var el, i, objs = document.getElementsByTagName(tag); |
|
for (i = objs.length; --i >= 0 && (el = objs[i]);) |
|
if (el.id == id) |
|
return el; |
|
return null; |
|
}; |
|
|
|
|
|
|
// EOF |
// EOF |
// Local variables: // |
// Local variables: // |
// c-basic-offset:8 // |
// c-basic-offset:8 // |