From 70e7091322d161ad5e2256481886617b9211a07f Mon Sep 17 00:00:00 2001 From: viniciuscb Date: Sun, 19 Jun 2005 13:37:50 +0000 Subject: [PATCH] Fixes in htmlarea... reverting to previous version by now --- phpgwapi/js/htmlarea/examples/core.html | 1 - phpgwapi/js/htmlarea/examples/full-page.html | 6 +- .../js/htmlarea/examples/fully-loaded.html | 20 +- phpgwapi/js/htmlarea/examples/index.html | 2 +- phpgwapi/js/htmlarea/htmlarea.css | 68 +- phpgwapi/js/htmlarea/htmlarea.js | 5688 ++++++----------- phpgwapi/js/htmlarea/index.html | 6 +- phpgwapi/js/htmlarea/lang/de.js | 3 +- phpgwapi/js/htmlarea/lang/en.js | 73 +- phpgwapi/js/htmlarea/lang/es.js | 86 +- phpgwapi/js/htmlarea/lang/nl.js | 7 +- phpgwapi/js/htmlarea/lang/vn.js | 112 +- .../plugins/ContextMenu/context-menu.js | 81 +- .../htmlarea/plugins/ContextMenu/lang/en.js | 6 +- .../plugins/ContextMenu/lang/lang.php | 1 + .../js/htmlarea/plugins/ContextMenu/menu.css | 1 - .../EnterParagraphs/enter-paragraphs.js | 272 +- .../js/htmlarea/plugins/FullPage/full-page.js | 38 +- .../htmlarea/plugins/FullPage/lang/lang.php | 1 + .../plugins/FullPage/popups/docprop.html | 14 +- .../js/htmlarea/plugins/HtmlTidy/html-tidy.js | 2 +- .../htmlarea/plugins/HtmlTidy/lang/lang.php | 1 + .../htmlarea/plugins/ListType/lang/lang.php | 1 + .../htmlarea/plugins/SpellChecker/.htaccess | 2 +- .../plugins/SpellChecker/lang/lang.php | 1 + .../plugins/SpellChecker/spell-check-ui.js | 8 +- .../plugins/SpellChecker/spell-checker.js | 4 +- .../plugins/TableOperations/lang/lang.php | 1 + .../plugins/TableOperations/lang/no.js | 2 +- .../TableOperations/table-operations.js | 20 +- .../plugins/UploadImage/lang/lang.php | 1 + .../popups/ImageManager/config.inc.php | 192 +- phpgwapi/js/htmlarea/popupdiv.js | 2 +- phpgwapi/js/htmlarea/popups/fullscreen.html | 24 +- phpgwapi/js/htmlarea/popups/insert_table.html | 23 +- phpgwapi/js/htmlarea/popups/link.html | 19 +- phpgwapi/js/htmlarea/popups/popup.js | 13 +- phpgwapi/js/htmlarea/popupwin.js | 4 +- 38 files changed, 2278 insertions(+), 4528 deletions(-) diff --git a/phpgwapi/js/htmlarea/examples/core.html b/phpgwapi/js/htmlarea/examples/core.html index 1fc5022501..536be0e954 100755 --- a/phpgwapi/js/htmlarea/examples/core.html +++ b/phpgwapi/js/htmlarea/examples/core.html @@ -12,7 +12,6 @@ _editor_lang = "en"; - \n"; + html += "\n"; + html += "\n"; + html += editor._textArea.value; + html += "\n"; + 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(); + } - switch(this.config.height) - { - // "auto" means the same height as the original textarea - case 'auto' : { height = parseInt(this._ta_size.h); break; } - // otherwise we expect it to be a PIXEL height - default : { height = parseInt(this.config.height); break; } - } + 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; + } - switch(this.config.width) - { - // toolbar means the width is the same as the toolbar - case 'toolbar': {width = parseInt(this._toolbar.offsetWidth); break; } - // auto means the same as the textarea - case 'auto' : {width = parseInt(this._ta_size.w); break; } - // otherwise it is expected to be a PIXEL width - default : {width = parseInt(this.config.width); break; } - } + 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); + }); - if (this.config.sizeIncludesToolbar) - { - // substract toolbar height - height -= this._toolbar.offsetHeight; - height -= this._statusBar.offsetHeight; - } + // 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(); + if (typeof plugin.onGenerateOnce == "function") { + plugin.onGenerateOnce(); + plugin.onGenerateOnce = null; + } + } - // Minimal size = 100x100 - width = Math.max(width, 100); - height = Math.max(height,100); + setTimeout(function() { + editor.updateToolbar(); + }, 250); - this.setInnerSize(width,height); - this.notifyOn('panel_change',function(){editor.setInnerSize();}); - - - // IMPORTANT: we have to allow Mozilla a short time to recognize the - // new frame. Otherwise we get a stupid exception. - - setTimeout(function() { editor.initIframe()}, 50); + if (typeof editor.onGenerate == "function") + editor.onGenerate(); + }; + setTimeout(initIframe, 100); }; - /** Size the htmlArea according to the available space - * Width and Height include toolbar! - **/ - - HTMLArea.prototype.getInnerSize = function() - { - return this._innerSize; - } - - HTMLArea.prototype.setInnerSize = function(width, height) - { - if(typeof width == 'undefined' || width == null) - { - width = this._innerSize.width; - } - - if(typeof height == 'undefined' || height == null) - { - height = this._innerSize.height; - } - - this._innerSize = {'width':width,'height':height}; - - var editorWidth = width; - var editorHeight = height; - var editorLeft = 0; - var editorTop = 0; - var panels = this._panels; - - var panel = panels.right; - if(panel.on && panel.panels.length && HTMLArea.hasDisplayedChildren(panel.div)) - { - panel.div.style.position = 'absolute'; - panel.div.style.width = parseInt(this.config.panel_dimensions.right) + (HTMLArea.ie_ie ? -1 : -2) + 'px'; - panel.div.style.height = height + (HTMLArea.is_ie ? -1 : -1) + 'px'; - panel.div.style.top = '0px'; - panel.div.style.right = (HTMLArea.is_ie ? 1 : 2) + 'px'; - panel.div.style.padding = "0px"; - panel.div.style.overflow = "auto"; - panel.div.style.display = 'block'; - editorWidth -= parseInt(this.config.panel_dimensions.right) + (HTMLArea.is_ie ? 2 : 0); - } - else - { - panel.div.style.display = 'none'; - } - - var panel = panels.left; - if(panel.on && panel.panels.length && HTMLArea.hasDisplayedChildren(panel.div)) - { - panel.div.style.position = 'absolute'; - panel.div.style.width = parseInt(this.config.panel_dimensions.left) + (HTMLArea.ie_ie ? -1 : -1) + 'px'; - panel.div.style.height = height + (HTMLArea.is_ie ? -1 : -1) + 'px'; - panel.div.style.top = '0px'; - panel.div.style.left = (HTMLArea.is_ie ? 0 : 0) + 'px'; - panel.div.style.padding = "0px"; - panel.div.style.overflow = "auto"; - panel.div.style.display = "block"; - editorWidth -= parseInt(this.config.panel_dimensions.left) + (HTMLArea.is_ie ? 2 : 0); - editorLeft = parseInt(this.config.panel_dimensions.left) + (HTMLArea.is_ie ? 2 : 0) + 'px'; - } - else - { - panel.div.style.display = 'none'; - } - - var panel = panels.top; - if(panel.on && panel.panels.length && HTMLArea.hasDisplayedChildren(panel.div)) - { - panel.div.style.position = 'absolute'; - panel.div.style.top = '0px'; - panel.div.style.left = '0px'; - panel.div.style.width = width + 'px'; - panel.div.style.height = parseInt(this.config.panel_dimensions.top) + 'px'; - panel.div.style.padding = "0px"; - panel.div.style.overflow = "auto"; - panel.div.style.display = "block"; - editorHeight -= parseInt(this.config.panel_dimensions.top); - editorTop = parseInt(this.config.panel_dimensions.top) + 'px'; - } - else - { - panel.div.style.display = 'none'; - } - - var panel = panels.bottom; - if(panel.on && panel.panels.length && HTMLArea.hasDisplayedChildren(panel.div)) - { - panel.div.style.position = 'absolute'; - panel.div.style.bottom = '0px'; - panel.div.style.left = '0px'; - panel.div.style.width = width + 'px'; - panel.div.style.height = parseInt(this.config.panel_dimensions.bottom) + 'px'; - panel.div.style.padding = "0px"; - panel.div.style.overflow = "auto"; - panel.div.style.display = "block"; - editorHeight -= parseInt(this.config.panel_dimensions.bottom); - } - else - { - panel.div.style.display = 'none'; - } - - // Set the dimensions of the container - this.innerEditor.style.width = width + 'px'; - this.innerEditor.style.height = height + 'px'; - this.innerEditor.style.position = 'relative'; - - // and the iframe - this._iframe.style.width = editorWidth + 'px'; - this._iframe.style.height = editorHeight + 'px'; - this._iframe.style.position = 'absolute'; - this._iframe.style.left = editorLeft; - this._iframe.style.top = editorTop; - - - // the editor including the toolbar now have the same size as the - // original textarea.. which means that we need to reduce that a bit. - this._textArea.style.width = editorWidth + 'px'; - this._textArea.style.height = editorHeight + 'px'; - this._textArea.style.position = 'absolute'; - this._textArea.style.left = editorLeft; - this._textArea.style.top = editorTop; - - this.notifyOf('resize', {'width':width,'height':height,'editorWidth':editorWidth,'editorHeight':editorHeight,'editorTop':editorTop,'editorLeft':editorLeft}); - } - - HTMLArea.prototype.addPanel = function(side) - { - var div = document.createElement('div'); - div.side = side; - HTMLArea.addClasses(div, 'panel'); - this._panels[side].panels.push(div); - this._panels[side].div.appendChild(div); - - this.notifyOf('panel_change', {'action':'add','panel':div}); - - return div; - } - - HTMLArea.prototype.removePanel = function(panel) - { - panel.side.div.removeChild(panel); - var clean = [ ]; - for(var i = 0; i < panel.side.panels.length; i++) - { - if(panel.side.panels[i] != panel) - { - clean.push(panel.side.panels[i]); - } - } - panel.side.panels = clean; - this.notifyOf('panel_change', {'action':'add','panel':panel}); - } - - HTMLArea.prototype.hidePanel = function(panel) - { - panel.style.display = 'none'; - this.notifyOf('panel_change', {'action':'hide','panel':panel}); - } - - HTMLArea.prototype.showPanel = function(panel) - { - panel.style.display = ''; - this.notifyOf('panel_change', {'action':'show','panel':panel}); - } - - HTMLArea.prototype.hidePanels = function(sides) - { - if(typeof sides == 'undefined') - { - sides = ['left','right','top','bottom']; - } - - var reShow = []; - for(var i = 0; i < sides.length;i++) - { - if(this._panels[sides[i]].on) - { - reShow.push(sides[i]); - this._panels[sides[i]].on = false; - } - } - this.notifyOf('panel_change', {'action':'multi_hide','sides':sides}); - } - - HTMLArea.prototype.showPanels = function(sides) - { - if(typeof sides == 'undefined') - { - sides = ['left','right','top','bottom']; - } - - var reHide = []; - for(var i = 0; i < sides.length;i++) - { - if(!this._panels[sides[i]].on) - { - reHide.push(sides[i]); - this._panels[sides[i]].on = true; - } - } - this.notifyOf('panel_change', {'action':'multi_show','sides':sides}); - } - - HTMLArea.objectProperties = function(obj) - { - var props = [ ]; - for(var x in obj) - { - props[props.length] = x; - } - return props; - } - - HTMLArea.prototype.activateEditor = function() - { - if (HTMLArea.is_gecko && this._doc.designMode != 'on') - { - try{HTMLArea.last_on.designMode = 'off';} catch(e) { } - if(this._iframe.style.display == 'none') - { - this._iframe.style.display = ''; - this._doc.designMode = 'on'; - this._iframe.style.display = 'none'; - } - else - { - - this._doc.designMode = 'on'; - } - } - else - { - this._doc.body.contentEditable = true; - } - HTMLArea.last_on = this._doc; - } - - HTMLArea.prototype.deactivateEditor = function() - { - if(HTMLArea.is_gecko && this._doc.designMode == 'on') - { - this._doc.designMode = 'off'; - HTMLArea.last_on = null; - } - else - { - this._doc.body.contentEditable = false; - } - } - - HTMLArea.prototype.initIframe = function() - { - var doc = null; - var editor = this; - try - { - doc = editor._iframe.contentWindow.document; - if (!doc) { - // Try again.. - // FIXME: don't know what else to do here. Normally - // we'll never reach this point. - if (HTMLArea.is_gecko) { - setTimeout(function() { editor.initIframe()}, 50); - return false; - } else { - alert("ERROR: IFRAME can't be initialized."); - } - } - } - catch(e) - { - setTimeout(function() { editor.initIframe()}, 50); - } - - if (!editor.config.fullPage) { - doc.open(); - var html = "\n"; - html += "\n"; - if(typeof editor.config.baseHref != 'undefined') - { - html += ""; - } - html += "\n"; - html += "\n"; - if(typeof editor.config.pageStyleSheets !== 'undefined') - { - for(style_i = 0; style_i < editor.config.pageStyleSheets.length; style_i++) - { - if(editor.config.pageStyleSheets[style_i].length > 0) - html += ""; - //html += "\n"; - } - } - html += "\n"; - html += "\n"; - html += editor.inwardHtml(editor._textArea.value); - html += "\n"; - html += ""; - doc.write(html); - doc.close(); - } else { - var html = editor.inwardHtml(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(); - } - - this._doc = doc; - - // If we have multiple editors some bug in Mozilla makes some lose editing ability - if(HTMLArea.is_gecko) - { - HTMLArea._addEvents( - editor._iframe.contentWindow, - ["mousedown"], - function() { editor.activateEditor(); } - ); - } - else - { - editor.activateEditor(); - } - - // 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); - }); - - // 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(); - if (typeof plugin.onGenerateOnce == "function") { - plugin.onGenerateOnce(); - plugin.onGenerateOnce = null; - } - } - - if(typeof editor._onGenerate == "function") { editor._onGenerate();} - - setTimeout(function() { - editor.updateToolbar(); - }, 250); - - if (typeof editor.onGenerate == "function") - editor.onGenerate(); - } - // Switches editor mode; parameter can be "textmode" or "wysiwyg". If no // parameter was passed this function toggles between modes. HTMLArea.prototype.setMode = function(mode) { - if (typeof mode == "undefined") { - mode = ((this._editMode == "textmode") ? "wysiwyg" : "textmode"); - } - switch (mode) { - case "textmode": - { - var html = this.outwardHtml(this.getHTML()); - this._textArea.value = html; + if (typeof mode == "undefined") { + mode = ((this._editMode == "textmode") ? "wysiwyg" : "textmode"); + } + switch (mode) { + case "textmode": + this._textArea.value = this.getHTML(); + this._iframe.style.display = "none"; + this._textArea.style.display = "block"; + if (this.config.statusBar) { + this._statusBar.innerHTML = HTMLArea.I18N.msg["TEXT_MODE"]; + } + break; + case "wysiwyg": + if (HTMLArea.is_gecko) { + // disable design mode before changing innerHTML + try { + this._doc.designMode = "off"; + } catch(e) {}; + } + if (!this.config.fullPage) + this._doc.body.innerHTML = this.getHTML(); + else + this.setFullHTML(this.getHTML()); + this._iframe.style.display = "block"; + this._textArea.style.display = "none"; + if (HTMLArea.is_gecko) { + // we need to refresh that info for Moz-1.3a + try { + this._doc.designMode = "on"; + } catch(e) {}; + } + if (this.config.statusBar) { + this._statusBar.innerHTML = ''; + this._statusBar.appendChild(document.createTextNode(HTMLArea.I18N.msg["Path"] + ": ")); + this._statusBar.appendChild(this._statusBarTree); + } + break; + default: + alert("Mode <" + mode + "> not defined!"); + return false; + } + this._editMode = mode; + this.focusEditor(); - // Hide the iframe - this.deactivateEditor(); - this._iframe.style.display = 'none'; - this._textArea.style.display = "block"; - if (this.config.statusBar) - { - this._statusBar.innerHTML = HTMLArea.I18N.msg["TEXT_MODE"]; - } - - this.notifyOf('modechange', {'mode':'text'}); - break; - } - - case "wysiwyg": - { - var html = this.inwardHtml(this.getHTML()); - this.deactivateEditor(); - if (!this.config.fullPage) - { - this._doc.body.innerHTML = html; - } - else - { - this.setFullHTML(html); - } - this._iframe.style.display = ''; - this._textArea.style.display = "none"; - this.activateEditor(); - if (this.config.statusBar) - { - this._statusBar.innerHTML = ''; - this._statusBar.appendChild(this._statusBarTree); - } - - this.notifyOf('modechange', {'mode':'wysiwyg'}); - break; - } - - default: - { - alert("Mode <" + mode + "> not defined!"); - return false; - } - } - this._editMode = mode; - // this.focusEditor(); - - for (var i in this.plugins) { - var plugin = this.plugins[i].instance; - if (typeof plugin.onMode == "function") plugin.onMode(mode); - } + for (var i in this.plugins) { + var plugin = this.plugins[i].instance; + if (typeof plugin.onMode == "function") plugin.onMode(mode); + } }; 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 = /((.|\n)*?)<\/html>/i; - html = html.replace(html_re, "$1"); - this._doc.open(); - this._doc.write(html); - this._doc.close(); - this.activateEditor(); - // this._doc.body.contentEditable = true; - return true; - } + 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 = /((.|\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 ***************************************************/ -// Create the specified plugin and register it with this HTMLArea -HTMLArea.prototype.registerPlugin = function() { - var plugin = arguments[0]; - var args = []; - for (var i = 1; i < arguments.length; ++i) - args.push(arguments[i]); - this.registerPlugin2(plugin, args); -}; - // 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); - if (typeof plugin == "undefined") { - /* FIXME: This should never happen. But why does it do? */ - return false; - } - 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() + "."); + if (typeof plugin == "string") + plugin = eval(plugin); + if (typeof plugin == "undefined") { + /* FIXME: This should never happen. But why does it do? */ + return false; + } + 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 +HTMLArea.prototype.registerPlugin = function() { + 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 // language loaded already for HTMLArea. You better make sure that the plugin // _has_ that language, otherwise shit might happen ;-) -HTMLArea.getPluginDir = function(pluginName) { - return _editor_url + "plugins/" + pluginName; -}; - HTMLArea.loadPlugin = function(pluginName) { - var dir = this.getPluginDir(pluginName); - var plugin = pluginName.replace(/([a-z])([A-Z])([a-z])/g, - function (str, l1, l2, l3) { - return l1 + "-" + l2.toLowerCase() + l3; - }).toLowerCase() + ".js"; - var plugin_file = dir + "/" + plugin; - var plugin_lang = dir + "/lang/" + _editor_lang + ".js"; - document.write(""); - document.write(""); - //this.loadScript(plugin_file); - //this.loadScript(plugin_lang); + var dir = _editor_url + "plugins/" + pluginName; + var plugin = pluginName.replace(/([a-z])([A-Z])([a-z])/g, + function (str, l1, l2, l3) { + return l1 + "-" + l2.toLowerCase() + l3; + }).toLowerCase() + ".js"; + var plugin_file = dir + "/" + plugin; + var plugin_lang = dir + "/lang/" + HTMLArea.I18N.lang + ".js"; + HTMLArea._scripts.push(plugin_file, plugin_lang); + document.write(""); + document.write(""); }; HTMLArea.loadStyle = function(style, plugin) { - var url = _editor_url || ''; - if (typeof plugin != "undefined") { - url += "plugins/" + plugin + "/"; - } - url += style; - if (/^\//.test(style)) - url = style; - var head = document.getElementsByTagName("head")[0]; - var link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = url; - head.appendChild(link); - //document.write(""); + var url = _editor_url || ''; + if (typeof plugin != "undefined") { + url += "plugins/" + plugin + "/"; + } + url += style; + document.write(""); }; -HTMLArea.loadStyle(typeof _editor_css == "string" ? _editor_css : "htmlarea.css"); +HTMLArea.loadStyle("htmlarea.css"); /*************************************************** * Category: EDITOR UTILITIES ***************************************************/ -HTMLArea.prototype.debugTree = function() { - var ta = document.createElement("textarea"); - ta.style.width = "100%"; - ta.style.height = "20em"; - ta.value = ""; - function debug(indent, str) { - for (; --indent >= 0;) - ta.value += " "; - ta.value += str + "\n"; - }; - function _dt(root, level) { - var tag = root.tagName.toLowerCase(), i; - var ns = HTMLArea.is_ie ? root.scopeName : root.prefix; - debug(level, "- " + tag + " [" + ns + "]"); - for (i = root.firstChild; i; i = i.nextSibling) - if (i.nodeType == 1) - _dt(i, level + 2); - }; - _dt(this._doc.body, 0); - document.body.appendChild(ta); -}; - -HTMLArea.getInnerText = function(el) { - var txt = '', i; - for (i = el.firstChild; i; i = i.nextSibling) { - if (i.nodeType == 3) - txt += i.data; - else if (i.nodeType == 1) - txt += HTMLArea.getInnerText(i); - } - return txt; -}; - +// The following function is a slight variation of the word cleaner code posted +// by Weeezl (user @ InteractiveTools forums). HTMLArea.prototype._wordClean = function() { - var - editor = this, - stats = { - empty_tags : 0, - mso_class : 0, - mso_style : 0, - mso_xmlel : 0, - orig_len : this._doc.body.innerHTML.length, - T : (new Date()).getTime() - }, - stats_txt = { - empty_tags : "Empty tags removed: ", - mso_class : "MSO class names removed: ", - mso_style : "MSO inline style removed: ", - mso_xmlel : "MSO XML elements stripped: " - }; - function showStats() { - var txt = "HTMLArea word cleaner stats: \n\n"; - for (var i in stats) - if (stats_txt[i]) - txt += stats_txt[i] + stats[i] + "\n"; - txt += "\nInitial document length: " + stats.orig_len + "\n"; - txt += "Final document length: " + editor._doc.body.innerHTML.length + "\n"; - txt += "Clean-up took " + (((new Date()).getTime() - stats.T) / 1000) + " seconds"; - alert(txt); - }; - function clearClass(node) { - var newc = node.className.replace(/(^|\s)mso.*?(\s|$)/ig, ' '); - if (newc != node.className) { - node.className = newc; - if (!/\S/.test(node.className)) { - node.removeAttribute("className"); - ++stats.mso_class; - } - } - }; - function clearStyle(node) { - var declarations = node.style.cssText.split(/\s*;\s*/); - for (var i = declarations.length; --i >= 0;) - if (/^mso|^tab-stops/i.test(declarations[i]) || - /^margin\s*:\s*0..\s+0..\s+0../i.test(declarations[i])) { - ++stats.mso_style; - declarations.splice(i, 1); - } - node.style.cssText = declarations.join("; "); - }; - function stripTag(el) { - if (HTMLArea.is_ie) - el.outerHTML = HTMLArea.htmlEncode(el.innerText); - else { - var txt = document.createTextNode(HTMLArea.getInnerText(el)); - el.parentNode.insertBefore(txt, el); - el.parentNode.removeChild(el); - } - ++stats.mso_xmlel; - }; - function checkEmpty(el) { - if (/^(a|span|b|strong|i|em|font)$/i.test(el.tagName) && - !el.firstChild) { - el.parentNode.removeChild(el); - ++stats.empty_tags; - } - }; - function parseTree(root) { - var tag = root.tagName.toLowerCase(), i, next; - if ((HTMLArea.is_ie && root.scopeName != 'HTML') || (!HTMLArea.is_ie && /:/.test(tag))) { - stripTag(root); - return false; - } else { - clearClass(root); - clearStyle(root); - for (i = root.firstChild; i; i = next) { - next = i.nextSibling; - if (i.nodeType == 1 && parseTree(i)) - checkEmpty(i); - } - } - return true; - }; - parseTree(this._doc.body); - // showStats(); - // this.debugTree(); - // this.setHTML(this.getHTML()); - // this.setHTML(this.getInnerHTML()); - // this.forceRedraw(); - this.updateToolbar(); + 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(/

]*TEXT-ALIGN: justify[^>]*>/gi,'

'). + replace(/ style=\"[^>]*\"/gi,''). + replace(/ align=[^\s|>]*/gi,''); + + //clean up tags + D = D.replace(/]*>/gi,''). + replace(/]*>/gi,''). + replace(/

  • ]*>/gi,'
  • '). + replace(/
      ]*>/gi,'
        '); + + // replace outdated tags + D = D.replace(//gi,''). + replace(/<\/b>/gi,''); + + // mozilla doesn't like tags + D = D.replace(//gi,''). + replace(/<\/em>/gi,''); + + // 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>/gi,''). + //replace(/<\/i>/gi,''). + //replace(/]*><\/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._clearFonts = function() { - var D = this.getInnerHTML(); - - if(confirm('Would you like to clear font typefaces?')) - { - D = D.replace(/face="[^"]*"/gi, ''); - D = D.replace(/font-family:[^;}"']+;?/gi, ''); - } - - if(confirm('Would you like to clear font sizes?')) - { - D = D.replace(/size="[^"]*"/gi, ''); - D = D.replace(/font-size:[^;}"']+;?/gi, ''); - } - - if(confirm('Would you like to clear font colours?')) - { - D = D.replace(/color="[^"]*"/gi, ''); - D = D.replace(/([^-])color:[^;}"']+;?/gi, '$1'); - } - - D = D.replace(/(style|class)="\s*"/gi, ''); - D = D.replace(/<(font|span)\s*>/gi, ''); - this.setHTML(D); - this.updateToolbar(); -} - -HTMLArea.prototype._splitBlock = function() -{ - this._doc.execCommand('formatblock', false, '
        '); -} - HTMLArea.prototype.forceRedraw = function() { - this._doc.body.style.visibility = "hidden"; - this._doc.body.style.visibility = "visible"; - // this._doc.body.innerHTML = this.getInnerHTML(); + this._doc.body.style.visibility = "hidden"; + this._doc.body.style.visibility = "visible"; + // this._doc.body.innerHTML = this.getInnerHTML(); }; // focuses the iframe window. returns a reference to the editor document. HTMLArea.prototype.focusEditor = function() { - switch (this._editMode) { - // notice the try { ... } catch block to avoid some rare exceptions in FireFox - // (perhaps also in other Gecko browsers). Manual focus by user is required in + switch (this._editMode) { + // notice the try { ... } catch block to avoid some rare exceptions in FireFox + // (perhaps also in other Gecko browsers). Manual focus by user is required in // case of an error. Somebody has an idea? - case "wysiwyg" : - try - { - // We don't want to focus the field unless at least one field has been activated. - if(HTMLArea.last_on) - { - this.activateEditor(); - this._iframe.contentWindow.focus(); - } - - } catch (e) {} break; - case "textmode": try { this._textArea.focus() } catch (e) {} break; - default : alert("ERROR: mode " + this._editMode + " is not defined"); - } - return this._doc; + case "wysiwyg" : try { this._iframe.contentWindow.focus() } catch (e) {} break; + case "textmode": try { this._textArea.focus() } catch (e) {} break; + default : alert("ERROR: mode " + this._editMode + " is not defined"); + } + 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--; - } + ++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; - } + 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; - } + if (this._undoPos < this._undoQueue.length - 1) { + var txt = this._undoQueue[++this._undoPos]; + if (txt) this.setHTML(txt); + else --this._undoPos; + } }; -HTMLArea.prototype.disableToolbar = function(except) -{ - if(typeof except == 'undefined') - { - except = [ ]; - } - else if(typeof except != 'object') - { - except = [except]; - } - - for (var i in this._toolbarObjects) - { - var btn = this._toolbarObjects[i]; - if(except.contains(i)) - { - continue; - } - btn.state("enabled", false); - } -} - -HTMLArea.prototype.enableToolbar = function() -{ - this.updateToolbar(); -} - -if(!Array.prototype.contains) -{ - Array.prototype.contains = function(needle) - { - var haystack = this; - for(var i = 0; i < haystack.length; i++) - { - if(needle == haystack[i]) return true; - } - - return false; - } - -} - - // updates enabled/disable/active state of the toolbar elements HTMLArea.prototype.updateToolbar = function(noStatus) { - var doc = this._doc; - var text = (this._editMode == "textmode"); - var ancestors = null; - if (!text) { - ancestors = this.getAllAncestors(); - if (this.config.statusBar && !noStatus) { - this._statusBarTree.innerHTML = HTMLArea.I18N.msg["Path"] + ": "; // clear - for (var i = ancestors.length; --i >= 0;) { - var el = ancestors[i]; - if (!el) { - // hell knows why we get here; this - // could be a classic example of why - // it's good to check for conditions - // that are impossible to happen ;-) - continue; - } - var a = document.createElement("a"); - a.href = "javascript:void(0)"; - a.el = el; - a.editor = this; - a.onclick = function() { - this.blur(); - this.editor.selectNodeContents(this.el); - this.editor.updateToolbar(true); - return false; - }; - a.oncontextmenu = function() { - // TODO: add context menu here - this.blur(); - var info = "Inline style:\n\n"; - info += this.el.style.cssText.split(/;\s*/).join(";\n"); - alert(info); - return false; - }; - var txt = el.tagName.toLowerCase(); - a.title = el.style.cssText; - if (el.id) { - txt += "#" + el.id; - } - if (el.className) { - txt += "." + el.className; - } - a.appendChild(document.createTextNode(txt)); - this._statusBarTree.appendChild(a); - if (i != 0) { - this._statusBarTree.appendChild(document.createTextNode(String.fromCharCode(0xbb))); - } - } - } - } + var doc = this._doc; + var text = (this._editMode == "textmode"); + var ancestors = null; + if (!text) { + ancestors = this.getAllAncestors(); + if (this.config.statusBar && !noStatus) { + this._statusBarTree.innerHTML = HTMLArea.I18N.msg["Path"] + ": "; // clear + for (var i = ancestors.length; --i >= 0;) { + var el = ancestors[i]; + if (!el) { + // hell knows why we get here; this + // could be a classic example of why + // it's good to check for conditions + // that are impossible to happen ;-) + continue; + } + var a = document.createElement("a"); + a.href = "#"; + a.el = el; + a.editor = this; + a.onclick = function() { + this.blur(); + this.editor.selectNodeContents(this.el); + this.editor.updateToolbar(true); + return false; + }; + a.oncontextmenu = function() { + // TODO: add context menu here + this.blur(); + var info = "Inline style:\n\n"; + info += this.el.style.cssText.split(/;\s*/).join(";\n"); + alert(info); + return false; + }; + var txt = el.tagName.toLowerCase(); + a.title = el.style.cssText; + if (el.id) { + txt += "#" + el.id; + } + if (el.className) { + txt += "." + el.className; + } + a.appendChild(document.createTextNode(txt)); + this._statusBarTree.appendChild(a); + if (i != 0) { + this._statusBarTree.appendChild(document.createTextNode(String.fromCharCode(0xbb))); + } + } + } + } - for (var i in this._toolbarObjects) { - var btn = this._toolbarObjects[i]; - var cmd = i; - var inContext = true; - if (btn.context && !text) { - inContext = false; - var context = btn.context; - var attrs = []; - if (/(.*)\[(.*?)\]/.test(context)) { - context = RegExp.$1; - attrs = RegExp.$2.split(","); - } - context = context.toLowerCase(); - var match = (context == "*"); - for (var k = 0; k < ancestors.length; ++k) { - if (!ancestors[k]) { - // the impossible really happens. - continue; - } - if (match || (ancestors[k].tagName.toLowerCase() == context)) { - inContext = true; - for (var ka = 0; ka < attrs.length; ++ka) { - if (!eval("ancestors[k]." + attrs[ka])) { - inContext = false; - break; - } - } - if (inContext) { - break; - } - } - } - } - btn.state("enabled", (!text || btn.text) && inContext); - if (typeof cmd == "function") { - continue; - } - // look-it-up in the custom dropdown boxes - var dropdown = this.config.customSelects[cmd]; - if ((!text || btn.text) && (typeof dropdown != "undefined")) { - dropdown.refresh(this); - continue; - } - switch (cmd) { - case "fontname": - case "fontsize": - if (!text) try { - var value = ("" + doc.queryCommandValue(cmd)).toLowerCase(); - if (!value) { - btn.element.selectedIndex = 0; - break; - } - // HACK -- retrieve the config option for this - // combo box. We rely on the fact that the - // variable in config has the same name as - // button name in the toolbar. - var options = this.config[cmd]; - var k = 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; - throw "ok"; - } - ++k; - } - btn.element.selectedIndex = 0; - } catch(e) {}; - - // It's better to search for the format block by tag name from the - // current selection upwards, because IE has a tendancy to return - // things like 'heading 1' for 'h1', which breaks things if you want - // to call your heading blocks 'header 1'. Stupid MS. - case "formatblock" : - var blocks = [ ]; - for(var i in this.config['formatblock']) - { - blocks[blocks.length] = this.config['formatblock'][i]; - } - - var deepestAncestor = this._getFirstAncestor(this._getSelection(), blocks); - if(deepestAncestor) - { - for(var x= 0; x < blocks.length; x++) - { - if(blocks[x].toLowerCase() == deepestAncestor.tagName.toLowerCase()) - { - btn.element.selectedIndex = x; - } - } - } - else - { - btn.element.selectedIndex = 0; - } - break; - - break; - case "textindicator": - if (!text) { - try {with (btn.element.style) { - backgroundColor = HTMLArea._makeColor( - doc.queryCommandValue(HTMLArea.is_ie ? "backcolor" : "hilitecolor")); - if (/transparent/i.test(backgroundColor)) { - // Mozilla - 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; - 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: - cmd = cmd.replace(/(un)?orderedlist/i, "insert$1orderedlist"); - try { - btn.state("active", (!text && doc.queryCommandState(cmd))); - } 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); - } - - // Insert a space in certain locations, this is just to make editing a little - // easier (to "get out of" tags), it's not essential. - if(HTMLArea.is_gecko) - { - var s = this._getSelection(); - if(s && s.isCollapsed && s.anchorNode && s.anchorNode.nodeType == 3) - { - if(s.anchorOffset == s.anchorNode.length) - { - if(HTMLArea.isBlockElement(s.anchorNode.parentNode)) - { - if(s.anchorNode.data != '\xA0' && !s.anchorNode.nextSibling) - { - s.anchorNode.parentNode.insertBefore(this._doc.createTextNode('\xA0'), s.anchorNode.nextSibling); - } - } - else - { - if(!s.anchorNode.parentNode.nextSibling) - { - s.anchorNode.parentNode.parentNode.insertBefore(this._doc.createTextNode('\xA0'), s.anchorNode.parentNode.nextSibling); - } - } - } - } - } - - // 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(); - } + for (var i in this._toolbarObjects) { + var btn = this._toolbarObjects[i]; + var cmd = i; + var inContext = true; + if (btn.context && !text) { + inContext = false; + var context = btn.context; + var attrs = []; + if (/(.*)\[(.*?)\]/.test(context)) { + context = RegExp.$1; + attrs = RegExp.$2.split(","); + } + context = context.toLowerCase(); + var match = (context == "*"); + for (var k in ancestors) { + if (!ancestors[k]) { + // the impossible really happens. + continue; + } + if (match || (ancestors[k].tagName.toLowerCase() == context)) { + inContext = true; + for (var ka in attrs) { + if (!eval("ancestors[k]." + attrs[ka])) { + inContext = false; + break; + } + } + if (inContext) { + break; + } + } + } + } + btn.state("enabled", (!text || btn.text) && inContext); + if (typeof cmd == "function") { + continue; + } + // look-it-up in the custom dropdown boxes + var dropdown = this.config.customSelects[cmd]; + if ((!text || btn.text) && (typeof dropdown != "undefined")) { + dropdown.refresh(this); + continue; + } + switch (cmd) { + case "fontname": + case "fontsize": + case "formatblock": + if (!text) try { + var value = ("" + doc.queryCommandValue(cmd)).toLowerCase(); + if (!value) { + // FIXME: what do we do here? + break; + } + // HACK -- retrieve the config option for this + // combo box. We rely on the fact that the + // variable in config has the same name as + // button name in the toolbar. + var options = this.config[cmd]; + 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; + } + } catch(e) {}; + break; + case "textindicator": + if (!text) { + try {with (btn.element.style) { + backgroundColor = HTMLArea._makeColor( + doc.queryCommandValue(HTMLArea.is_ie ? "backcolor" : "hilitecolor")); + if (/transparent/i.test(backgroundColor)) { + // Mozilla + 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; + 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: + cmd = cmd.replace(/(un)?orderedlist/i, "insert$1orderedlist"); + try { + btn.state("active", (!text && doc.queryCommandState(cmd))); + } 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 * 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; - 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 = this._createRange(); - range.setEnd(node, pos + toBeInserted.length); - range.setStart(node, pos + toBeInserted.length); - sel.addRange(range); - } else { - node = node.splitText(pos); - var selnode = toBeInserted; - if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) { - selnode = selnode.firstChild; - } - node.parentNode.insertBefore(toBeInserted, node); - this.selectNodeContents(selnode); - this.updateToolbar(); - } - break; - case 1: // Node.ELEMENT_NODE - var selnode = toBeInserted; - if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) { - selnode = selnode.firstChild; - } - node.insertBefore(toBeInserted, node.childNodes[pos]); - this.selectNodeContents(selnode); - this.updateToolbar(); - break; - } - } else { - return null; // this function not yet used for IE - } + 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; + 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 = this._createRange(); + range.setEnd(node, pos + toBeInserted.length); + range.setStart(node, pos + toBeInserted.length); + sel.addRange(range); + } else { + node = node.splitText(pos); + var selnode = toBeInserted; + if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) { + selnode = selnode.firstChild; + } + node.parentNode.insertBefore(toBeInserted, node); + this.selectNodeContents(selnode); + this.updateToolbar(); + } + break; + case 1: // Node.ELEMENT_NODE + var selnode = toBeInserted; + if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) { + selnode = selnode.firstChild; + } + node.insertBefore(toBeInserted, node.childNodes[pos]); + this.selectNodeContents(selnode); + this.updateToolbar(); + break; + } + } else { + return null; // this function not yet used for IE + } }; // Returns the deepest node that contains both endpoints of the selection. -HTMLArea.prototype.getParentElement = function(sel) { - if(typeof sel == 'undefined') - { - sel = this._getSelection(); - } - var range = this._createRange(sel); - if (HTMLArea.is_ie) { - switch (sel.type) { - 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; - 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) { - p = p.parentNode; - } - return p; - } catch (e) { - return null; - } +HTMLArea.prototype.getParentElement = function() { + var sel = this._getSelection(); + var range = this._createRange(sel); + if (HTMLArea.is_ie) { + switch (sel.type) { + 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; + 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) { + p = p.parentNode; + } + return p; + } catch (e) { + return null; + } }; // Returns an array with all the ancestor nodes of the selection. HTMLArea.prototype.getAllAncestors = function() { - var p = this.getParentElement(); - var a = []; - while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) { - a.push(p); - p = p.parentNode; - } - a.push(this._doc.body); - return a; + var p = this.getParentElement(); + var a = []; + while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) { + a.push(p); + p = p.parentNode; + } + a.push(this._doc.body); + return a; }; -// Returns the deepest ancestor of the selection that is of the current type -HTMLArea.prototype._getFirstAncestor = function(sel, types) -{ - var prnt = this._activeElement(sel); - if(prnt == null) - { - try - { - prnt = (HTMLArea.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer); - } - catch(e) - { - return null; - } - } - - if(typeof types == 'string') - { - types = [types]; - } - - while(prnt) - { - if(prnt.nodeType == 1) - { - if(types == null) return prnt; - if(types.contains(prnt.tagName.toLowerCase())) - { - - return prnt; - } - if(prnt.tagName.toLowerCase() == 'body') break; - if(prnt.tagName.toLowerCase() == 'table') break; - } - prnt = prnt.parentNode; - } - - return null; -} - -/** - * Returns the selected element, if any. That is, - * the element that you have last selected in the "path" - * at the bottom of the editor, or a "control" (eg image) - * - * @returns null | element - */ -HTMLArea.prototype._activeElement = function(sel) -{ - if(sel == null) return null; - if(this._selectionEmpty(sel)) return null; - - if(HTMLArea.is_ie) - { - if(sel.type.toLowerCase() == "control") - { - return sel.createRange().item(0); - } - else - { - - // If it's not a control, then we need to see if - // the selection is the _entire_ text of a parent node - // (this happens when a node is clicked in the tree) - var range = sel.createRange(); - var p_elm = this.getParentElement(sel); - if(p_elm.innerHTML == range.htmlText) - { - return p_elm; - } - /* - if(p_elm) - { - var p_rng = this._doc.body.createTextRange(); - p_rng.moveToElementText(p_elm); - if(p_rng.isEqual(range)) - { - return p_elm; - } - } - - if(range.parentElement()) - { - var prnt_range = this._doc.body.createTextRange(); - prnt_range.moveToElementText(range.parentElement()); - if(prnt_range.isEqual(range)) - { - return range.parentElement(); - } - } - */ - return null; - } - } - else - { - // For Mozilla we just see if the selection is not collapsed (something is selected) - // and that the anchor (start of selection) is an element. This might not be totally - // correct, we possibly should do a simlar check to IE? - if(! sel.isCollapsed) - { - if(sel.anchorNode.nodeType == 1) - { - return sel.anchorNode; - } - } - return null; - } -} - - -HTMLArea.prototype._selectionEmpty = function(sel) -{ - if(!sel) return true; - - if(HTMLArea.is_ie) - { - return this._createRange(sel).htmlText == ''; - } - else if(typeof sel.isCollapsed != 'undefined') - { - return sel.isCollapsed; - } - - return true; -} - -HTMLArea.prototype._getAncestorBlock = function(sel) -{ - // Scan upwards to find a block level element that we can change or apply to - var prnt = (HTMLArea.is_ie ? this._createRange(sel).parentElement : this._createRange(sel).commonAncestorContainer); - - while(prnt && (prnt.nodeType == 1)) - { - switch(prnt.tagName.toLowerCase()) - { - case 'div' : - case 'p' : - case 'address' : - case 'blockquote' : - case 'center' : - case 'del' : - case 'ins' : - case 'pre' : - case 'h1' : - case 'h2' : - case 'h3' : - case 'h4' : - case 'h5' : - case 'h6' : - case 'h7' : - // Block Element - return prnt; - - case 'body' : - case 'noframes' : - case 'dd' : - case 'li' : - case 'th' : - case 'td' : - case 'noscript' : - // Halting element (stop searching) - return null; - - default : - // Keep lookin - break; - } - } - - return null; -} - -HTMLArea.prototype._createImplicitBlock = function(type) -{ - // expand it until we reach a block element in either direction - // then wrap the selection in a block and return - var sel = this._getSelection(); - if(HTMLArea.is_ie) - { - sel.empty(); - } - else - { - sel.collapseToStart(); - } - - var rng = this._createRange(sel); - - // Expand UP - - // Expand DN -} - -HTMLArea.prototype._formatBlock = function(block_format) -{ - var ancestors = this.getAllAncestors(); - var apply_to = null; - - // Block format can be a tag followed with class defs - // eg div.blue.left - var target_tag = null; - var target_classNames = [ ]; - - if(block_format.indexOf('.') >= 0) - { - target_tag = block_format.substr(0, block_format.indexOf('.')).toLowerCase();; - - target_classNames = block_format.substr(block_format.indexOf('.'), block_format.length - block_format.indexOf('.')).replace(/\./g, '').replace(/^\s*/, '').replace(/\s*$/, '').split(' '); - } - else - { - target_tag = block_format.toLowerCase(); - } - - var sel = this._getSelection(); - var rng = this._createRange(sel); - var apply_to = null; - - if(HTMLArea.is_gecko) - { - if(sel.isCollapsed) - { - // With no selection we want to apply to the whole contents of the ancestor block - apply_to = this._getAncestorBlock(sel); - if(apply_to == null) - { - // If there wasn't an ancestor, make one. - apply_to = this._createImplicitBlock(sel, target_tag); - } - } - else - { - // With a selection it's more tricky - switch(target_tag) - { - - case 'h1' : - case 'h2' : - case 'h3' : - case 'h4' : - case 'h5' : - case 'h6' : - case 'h7' : - apply_to = [ ]; - var search_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']; - for(var y = 0; y < search_tags.length; y++) - { - var headers = this._doc.getElementsByTagName(search_tag[y]); - for(var x = 0; x < headers.length; x++) - { - if(sel.containsNode(headers[x])) - { - apply_to[apply_to.length] = headers[x]; - } - } - } - if(apply_to.length > 0) break; - // If there wern't any in the selection drop through - case 'div' : - apply_to = this._doc.createElement(target_tag); - apply_to.appendChild(rng.extractContents()); - rng.insertNode(apply_to); - break; - - case 'p' : - case 'center' : - case 'pre' : - case 'ins' : - case 'del' : - case 'blockquote' : - case 'address' : - apply_to = [ ]; - var paras = this._doc.getElementsByTagName(target_tag); - for(var x = 0; x < paras.length; x++) - { - if(sel.containsNode(paras[x])) - { - apply_to[apply_to.length] = paras[x]; - } - } - - if(apply_to.length == 0) - { - sel.collapseToStart(); - return this._formatBlock(block_format); - } - break; - } - } - } - -} - // Selects the contents inside the given node HTMLArea.prototype.selectNodeContents = function(node, pos) { - this.focusEditor(); - this.forceRedraw(); - var range; - var collapsed = (typeof pos != "undefined"); - if (HTMLArea.is_ie) { - // Tables and Images get selected as "objects" rather than the text contents - if(!collapsed && node.tagName && node.tagName.toLowerCase().match(/table|img/)) - { - range = this._doc.body.createControlRange(); - range.add(node); - } - else - { - range = this._doc.body.createTextRange(); - range.moveToElementText(node); - (collapsed) && range.collapse(pos); - } - range.select(); - } else { - var sel = this._getSelection(); - range = this._doc.createRange(); - // Tables and Images get selected as "objects" rather than the text contents - if(!collapsed && node.tagName && node.tagName.toLowerCase().match(/table|img/)) - { - range.selectNode(node); - (collapsed) && range.collapse(pos); - } - else - { - range.selectNodeContents(node); - (collapsed) && range.collapse(pos); - } - sel.removeAllRanges(); - sel.addRange(range); - } + this.focusEditor(); + this.forceRedraw(); + var range; + var collapsed = (typeof pos != "undefined"); + if (HTMLArea.is_ie) { + range = this._doc.body.createTextRange(); + range.moveToElementText(node); + (collapsed) && range.collapse(pos); + range.select(); + } else { + var sel = this._getSelection(); + range = this._doc.createRange(); + range.selectNodeContents(node); + (collapsed) && range.collapse(pos); + sel.removeAllRanges(); + sel.addRange(range); + } }; /** Call this function to insert HTML code at the current position. It deletes * the selection, if any. */ HTMLArea.prototype.insertHTML = function(html) { - var sel = this._getSelection(); - var range = this._createRange(sel); - if (HTMLArea.is_ie) { - range.pasteHTML(html); - } else { - // construct a new document fragment with the given HTML - var fragment = this._doc.createDocumentFragment(); - var div = this._doc.createElement("div"); - div.innerHTML = html; - while (div.firstChild) { - // the following call also removes the node from div - fragment.appendChild(div.firstChild); - } - // this also removes the selection - var node = this.insertNodeAtSelection(fragment); - } + var sel = this._getSelection(); + var range = this._createRange(sel); + if (HTMLArea.is_ie) { + range.pasteHTML(html); + } else { + // construct a new document fragment with the given HTML + var fragment = this._doc.createDocumentFragment(); + var div = this._doc.createElement("div"); + div.innerHTML = html; + while (div.firstChild) { + // the following call also removes the node from div + fragment.appendChild(div.firstChild); + } + // this also removes the selection + var node = this.insertNodeAtSelection(fragment); + } }; /** @@ -2543,213 +1394,182 @@ HTMLArea.prototype.insertHTML = function(html) { * your tags. FIXME: buggy! This function will be deprecated "soon". */ HTMLArea.prototype.surroundHTML = function(startTag, endTag) { - var html = this.getSelectedHTML(); - // the following also deletes the selection - this.insertHTML(startTag + html + endTag); + var html = this.getSelectedHTML(); + // the following also deletes the selection + this.insertHTML(startTag + html + endTag); }; /// Retrieve the selected block HTMLArea.prototype.getSelectedHTML = function() { - var sel = this._getSelection(); - var range = this._createRange(sel); - var existing = null; - if (HTMLArea.is_ie) { - existing = range.htmlText; - } else { - existing = HTMLArea.getHTML(range.cloneContents(), false, this); - } - return existing; + var sel = this._getSelection(); + var range = this._createRange(sel); + var existing = null; + if (HTMLArea.is_ie) { + existing = range.htmlText; + } else { + existing = HTMLArea.getHTML(range.cloneContents(), false, this); + } + return existing; }; /// Return true if we have some selection HTMLArea.prototype.hasSelectedText = function() { - // FIXME: come _on_ mishoo, you can do better than this ;-) - return this.getSelectedHTML() != ''; + // 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) { - if (/^img$/i.test(link.tagName)) - link = link.parentNode; - if (!/^a$/i.test(link.tagName)) - link = null; - } - } - if (!link) { - var sel = editor._getSelection(); - var range = editor._createRange(sel); - var compare = 0; - if (HTMLArea.is_ie) { - compare = range.compareEndPoints("StartToEnd", range); - } else { - compare = range.compareBoundaryPoints(range.START_TO_END, range); - } - if (compare == 0) { - alert("You need to select some text before creating a link"); - return; - } - outparam = { - f_href : '', - f_title : '', - f_target : '', - f_usetarget : editor.config.makeLinkShowsTarget - }; - } else - outparam = { - f_href : HTMLArea.is_ie ? editor.stripBaseURL(link.href) : link.getAttribute("href"), - f_title : link.title, - f_target : link.target, - f_usetarget : editor.config.makeLinkShowsTarget - }; - this._popupDialog("link.html", function(param) { - if (!param) - return false; - var a = link; - if (!a) try { - 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; - if (a == null) - a = range.startContainer.parentNode; - } - } - } catch(e) {} - else { - var href = param.f_href.trim(); - editor.selectNodeContents(a); - if (href == "") { - editor._doc.execCommand("unlink", false, null); - editor.updateToolbar(); - return false; - } - else { - a.href = href; - } - } - if (!(a && /^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); + 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) try { + 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; + if (a == null) + a = range.startContainer.parentNode; + } + } + } catch(e) {} + else { + var href = param.f_href.trim(); + editor.selectNodeContents(a); + if (href == "") { + editor._doc.execCommand("unlink", false, null); + editor.updateToolbar(); + return false; + } + else { + a.href = href; + } + } + if (!(a && /^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 outparam = null; - if (typeof image == "undefined") { - image = this.getParentElement(); - if (image && !/^img$/i.test(image.tagName)) - image = null; - } - if (image) outparam = { - f_base : editor.config.baseURL, - 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) { - if (!param) { // user must have pressed Cancel - return false; - } - var img = image; - if (!img) { - var sel = editor._getSelection(); - var range = editor._createRange(sel); - editor._doc.execCommand("insertimage", false, param.f_url); - if (HTMLArea.is_ie) { - img = range.parentElement(); - // wonder if this works... - if (img.tagName.toLowerCase() != "img") { - img = img.previousSibling; - } - } else { - img = range.startContainer.previousSibling; - } - } else { - img.src = param.f_url; - } + 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) { + if (!param) { // user must have pressed Cancel + return false; + } + var img = image; + if (!img) { + var sel = editor._getSelection(); + var range = editor._createRange(sel); + editor._doc.execCommand("insertimage", false, param.f_url); + if (HTMLArea.is_ie) { + img = range.parentElement(); + // wonder if this works... + if (img.tagName.toLowerCase() != "img") { + img = img.previousSibling; + } + } else { + img = range.startContainer.previousSibling; + } + } else { + img.src = param.f_url; + } - for (var field in param) { - var value = param[field]; - switch (field) { - case "f_alt" : img.alt = value; break; - case "f_border" : img.border = parseInt(value || "0"); break; - case "f_align" : img.align = value; break; - case "f_vert" : img.vspace = parseInt(value || "0"); break; - case "f_horiz" : img.hspace = parseInt(value || "0"); break; - } - } - }, outparam); + for (field in param) { + var value = param[field]; + switch (field) { + case "f_alt" : img.alt = value; break; + case "f_border" : img.border = parseInt(value || "0"); break; + case "f_align" : img.align = value; break; + case "f_vert" : img.vspace = parseInt(value || "0"); break; + case "f_horiz" : img.hspace = parseInt(value || "0"); break; + } + } + }, outparam); }; // Called when the user clicks the Insert Table button HTMLArea.prototype._insertTable = function() { - var sel = this._getSelection(); - var range = this._createRange(sel); - var editor = this; // for nested functions - this._popupDialog("insert_table.html", function(param) { - if (!param) { // user must have pressed Cancel - return false; - } - var doc = editor._doc; - // create the table element - var table = doc.createElement("table"); - // assign the given arguments + var sel = this._getSelection(); + var range = this._createRange(sel); + var editor = this; // for nested functions + this._popupDialog("insert_table.html", function(param) { + if (!param) { // user must have pressed Cancel + return false; + } + var doc = editor._doc; + // create the table element + var table = doc.createElement("table"); + // assign the given arguments - for (var field in param) { - var value = param[field]; - if (!value) { - continue; - } - switch (field) { - case "f_width" : table.style.width = value + param["f_unit"]; break; - case "f_align" : table.align = value; break; - case "f_border" : table.border = parseInt(value); break; - case "f_spacing" : table.cellSpacing = parseInt(value); break; - case "f_padding" : table.cellPadding = parseInt(value); break; - } - } - var cellwidth = 0; - if (param.f_fixed) - cellwidth = Math.floor(100 / parseInt(param.f_cols)); - var tbody = doc.createElement("tbody"); - table.appendChild(tbody); - for (var i = 0; i < param["f_rows"]; ++i) { - var tr = doc.createElement("tr"); - tbody.appendChild(tr); - for (var j = 0; j < param["f_cols"]; ++j) { - var td = doc.createElement("td"); - if (cellwidth) - td.style.width = cellwidth + "%"; - tr.appendChild(td); - // Mozilla likes to see something inside the cell. - (HTMLArea.is_gecko) && td.appendChild(doc.createElement("br")); - } - } - if (HTMLArea.is_ie) { - range.pasteHTML(table.outerHTML); - } else { - // insert the table - editor.insertNodeAtSelection(table); - } - return true; - }, null); + for (var field in param) { + var value = param[field]; + if (!value) { + continue; + } + switch (field) { + case "f_width" : table.style.width = value + param["f_unit"]; break; + case "f_align" : table.align = value; break; + case "f_border" : table.border = parseInt(value); break; + case "f_spacing" : table.cellSpacing = parseInt(value); break; + case "f_padding" : table.cellPadding = parseInt(value); break; + } + } + var tbody = doc.createElement("tbody"); + table.appendChild(tbody); + for (var i = 0; i < param["f_rows"]; ++i) { + var tr = doc.createElement("tr"); + tbody.appendChild(tr); + for (var j = 0; j < param["f_cols"]; ++j) { + var td = doc.createElement("td"); + tr.appendChild(td); + // Mozilla likes to see something inside the cell. + (HTMLArea.is_gecko) && td.appendChild(doc.createElement("br")); + } + } + if (HTMLArea.is_ie) { + range.pasteHTML(table.outerHTML); + } else { + // insert the table + editor.insertNodeAtSelection(table); + } + return true; + }, null); }; /*************************************************** @@ -2759,1113 +1579,613 @@ HTMLArea.prototype._insertTable = function() { // el is reference to the SELECT object // txt is the name of the select field, as in config.toolbar HTMLArea.prototype._comboSelected = function(el, txt) { - this.focusEditor(); - var value = el.options[el.selectedIndex].value; - switch (txt) { - case "fontname": - case "fontsize": this.execCommand(txt, false, value); break; - case "formatblock": - // (HTMLArea.is_ie) && (value = "<" + value + ">"); - value = "<" + value + ">" - this.execCommand(txt, false, value); - break; - default: - // try to look it up in the registered dropdowns - var dropdown = this.config.customSelects[txt]; - if (typeof dropdown != "undefined") { - dropdown.action(this); - } else { - alert("FIXME: combo box " + txt + " not implemented"); - } - } + this.focusEditor(); + var value = el.options[el.selectedIndex].value; + switch (txt) { + case "fontname": + case "fontsize": this.execCommand(txt, false, value); break; + case "formatblock": + (HTMLArea.is_ie) && (value = "<" + value + ">"); + this.execCommand(txt, false, value); + break; + default: + // try to look it up in the registered dropdowns + var dropdown = this.config.customSelects[txt]; + if (typeof dropdown != "undefined") { + dropdown.action(this); + } else { + alert("FIXME: combo box " + txt + " not implemented"); + } + } }; // the execCommand function (intercepts some commands and replaces them with // our own implementation) HTMLArea.prototype.execCommand = function(cmdID, UI, param) { - var editor = this; // for nested functions - this.focusEditor(); - cmdID = cmdID.toLowerCase(); - if (HTMLArea.is_gecko) try { this._doc.execCommand('useCSS', false, true); } catch (e) {}; - switch (cmdID) { - case "htmlmode" : this.setMode(); break; - case "hilitecolor": - (HTMLArea.is_ie) && (cmdID = "backcolor"); - case "forecolor": - this._popupDialog("select_color.html", function(color) { - if (color) { // selection not canceled - editor._doc.execCommand(cmdID, false, "#" + color); - } - }, HTMLArea._colorToRgb(this._doc.queryCommandValue(cmdID))); - break; - case "createlink": - this._createLink(); - break; - case "popupeditor": - // this object will be passed to the newly opened window - HTMLArea._object = this; - if (HTMLArea.is_ie) { - //if (confirm(HTMLArea.I18N.msg["IE-sucks-full-screen"])) - { - 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 { - window.open(this.popupURL("fullscreen.html"), "ha_fullscreen", - "toolbar=no,menubar=no,personalbar=no,width=640,height=480," + - "scrollbars=no,resizable=yes"); - } - break; - case "undo": - case "redo": - if (this._customUndo) - this[cmdID](); - else - this._doc.execCommand(cmdID, UI, param); - break; - case "inserttable": this._insertTable(); break; - case "insertimage": this._insertImage(); break; - case "about" : this._popupDialog("about.html", null, this); break; - case "showhelp" : window.open(_editor_url + "reference.html", "ha_help"); break; + var editor = this; // for nested functions + this.focusEditor(); + cmdID = cmdID.toLowerCase(); + switch (cmdID) { + case "htmlmode" : this.setMode(); break; + case "hilitecolor": + (HTMLArea.is_ie) && (cmdID = "backcolor"); + case "forecolor": + this._popupDialog("select_color.html", function(color) { + if (color) { // selection not canceled + editor._doc.execCommand(cmdID, false, "#" + color); + } + }, HTMLArea._colorToRgb(this._doc.queryCommandValue(cmdID))); + break; + case "createlink": + this._createLink(); + break; + case "popupeditor": + // this object will be passed to the newly opened window + HTMLArea._object = this; + if (HTMLArea.is_ie) { + //if (confirm(HTMLArea.I18N.msg["IE-sucks-full-screen"])) + { + 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 { + window.open(this.popupURL("fullscreen.html"), "ha_fullscreen", + "toolbar=no,menubar=no,personalbar=no,width=640,height=480," + + "scrollbars=no,resizable=yes"); + } + break; + case "undo": + case "redo": + if (this._customUndo) + this[cmdID](); + else + this._doc.execCommand(cmdID, UI, param); + break; + case "inserttable": this._insertTable(); break; + case "insertimage": this._insertImage(); break; + case "about" : this._popupDialog("about.html", null, this); break; + case "showhelp" : window.open(_editor_url + "reference.html", "ha_help"); break; - case "killword": this._wordClean(); break; + case "killword": this._wordClean(); break; - case "cut": - case "copy": - case "paste": - try { - this._doc.execCommand(cmdID, UI, param); - if (this.config.killWordOnPaste) - this._wordClean(); - } catch (e) { - if (HTMLArea.is_gecko) { - if (typeof HTMLArea.I18N.msg["Moz-Clipboard"] == "undefined") { - HTMLArea.I18N.msg["Moz-Clipboard"] = - "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.\n\n" + - "[FIXME: please translate this message in your language definition file.]"; - } - if (confirm(HTMLArea.I18N.msg["Moz-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: try { this._doc.execCommand(cmdID, UI, param); } - catch(e) { if (this.config.debug) { alert(e + "\n\nby execCommand(" + cmdID + ");"); } } - } - this.updateToolbar(); - return false; + 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 (typeof HTMLArea.I18N.msg["Moz-Clipboard"] == "undefined") { + HTMLArea.I18N.msg["Moz-Clipboard"] = + "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.\n\n" + + "[FIXME: please translate this message in your language definition file.]"; + } + if (confirm(HTMLArea.I18N.msg["Moz-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); + } + this.updateToolbar(); + return false; }; /** A generic event handler for things that happen in the IFRAME's document. * This function also handles key bindings. */ HTMLArea.prototype._editorEvent = function(ev) { - var editor = this; - var keyEvent = (HTMLArea.is_ie && ev.type == "keydown") || (!HTMLArea.is_ie && ev.type == "keypress"); + var editor = this; + 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") - if (plugin.onKeyPress(ev)) - return false; - } - if (keyEvent && ev.ctrlKey && !ev.altKey) { - var sel = null; - var range = null; - var key = String.fromCharCode(HTMLArea.is_ie ? ev.keyCode : ev.charCode).toLowerCase(); - var cmd = null; - var value = null; - switch (key) { - case 'a': - if (!HTMLArea.is_ie) { - // KEY select all - sel = this._getSelection(); - sel.removeAllRanges(); - range = this._createRange(); - range.selectNodeContents(this._doc.body); - sel.addRange(range); - HTMLArea._stopEvent(ev); - } - break; + 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 && !ev.altKey) { + var sel = null; + var range = null; + var key = String.fromCharCode(HTMLArea.is_ie ? ev.keyCode : ev.charCode).toLowerCase(); + var cmd = null; + var value = null; + switch (key) { + case 'a': + if (!HTMLArea.is_ie) { + // KEY select all + sel = this._getSelection(); + sel.removeAllRanges(); + range = this._createRange(); + range.selectNodeContents(this._doc.body); + sel.addRange(range); + HTMLArea._stopEvent(ev); + } + break; - // simple key commands follow + // simple key commands follow - case 'b': cmd = "bold"; break; - case 'i': cmd = "italic"; break; - case 'u': cmd = "underline"; break; - case 's': cmd = "strikethrough"; break; - case 'l': cmd = "justifyleft"; break; - case 'e': cmd = "justifycenter"; break; - case 'r': cmd = "justifyright"; break; - case 'j': cmd = "justifyfull"; break; - case 'z': cmd = "undo"; break; - case 'y': cmd = "redo"; break; - case 'v': if (HTMLArea.is_ie || editor.config.htmlareaPaste) { cmd = "paste"; } break; - case 'n': cmd = "formatblock"; value = HTMLArea.is_ie ? "

        " : "p"; break; + case 'b': cmd = "bold"; break; + case 'i': cmd = "italic"; break; + case 'u': cmd = "underline"; break; + case 's': cmd = "strikethrough"; break; + case 'l': cmd = "justifyleft"; break; + case 'e': cmd = "justifycenter"; break; + case 'r': cmd = "justifyright"; 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; + case '0': cmd = "killword"; break; - // headings - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - cmd = "formatblock"; - value = "h" + key; - if (HTMLArea.is_ie) - value = "<" + value + ">"; - break; - } - if (cmd) { - // execute simple command - this.execCommand(cmd, false, value); - HTMLArea._stopEvent(ev); - } - } - else if (keyEvent) { - // other keys here - switch (ev.keyCode) { - case 13: // KEY enter - if (HTMLArea.is_gecko && !ev.shiftKey) { - this.dom_checkInsertP(); - HTMLArea._stopEvent(ev); - } - break; - case 8: // KEY backspace - case 46: // KEY delete - if (HTMLArea.is_gecko && !ev.shiftKey) { - if (this.dom_checkBackspace()) - HTMLArea._stopEvent(ev); - } else if (HTMLArea.is_ie) { - if (this.ie_checkBackspace()) - HTMLArea._stopEvent(ev); - } - break; - } - } - - // update the toolbar state after some time - if (editor._timerToolbar) { - clearTimeout(editor._timerToolbar); - } - editor._timerToolbar = setTimeout(function() { - editor.updateToolbar(); - editor._timerToolbar = null; - }, 100); + // headings + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + cmd = "formatblock"; + value = "h" + key; + if (HTMLArea.is_ie) { + value = "<" + value + ">"; + } + break; + } + if (cmd) { + // execute simple command + this.execCommand(cmd, false, value); + HTMLArea._stopEvent(ev); + } + } + /* + else if (keyEvent) { + // other keys here + switch (ev.keyCode) { + case 13: // KEY enter + // if (HTMLArea.is_ie) { + this.insertHTML("
        "); + HTMLArea._stopEvent(ev); + // } + break; + } + } + */ + // update the toolbar state after some time + if (editor._timerToolbar) { + clearTimeout(editor._timerToolbar); + } + editor._timerToolbar = setTimeout(function() { + editor.updateToolbar(); + editor._timerToolbar = null; + }, 50); }; -HTMLArea.prototype.convertNode = function(el, newTagName) { - var newel = this._doc.createElement(newTagName); - while (el.firstChild) - newel.appendChild(el.firstChild); - return newel; -}; - -HTMLArea.prototype.ie_checkBackspace = function() { - var sel = this._getSelection(); - var range = this._createRange(sel); - var r2 = range.duplicate(); - r2.moveStart("character", -1); - var a = r2.parentElement(); - if (a != range.parentElement() && - /^a$/i.test(a.tagName)) { - r2.collapse(true); - r2.moveEnd("character", 1); - r2.pasteHTML(''); - r2.select(); - return true; - } -}; - -HTMLArea.prototype.dom_checkBackspace = function() { - var self = this; - setTimeout(function() { - var sel = self._getSelection(); - var range = self._createRange(sel); - var SC = range.startContainer; - var SO = range.startOffset; - var EC = range.endContainer; - var EO = range.endOffset; - var newr = SC.nextSibling; - if (SC.nodeType == 3) - SC = SC.parentNode; - if (!/\S/.test(SC.tagName)) { - var p = document.createElement("p"); - while (SC.firstChild) - p.appendChild(SC.firstChild); - SC.parentNode.insertBefore(p, SC); - SC.parentNode.removeChild(SC); - var r = range.cloneRange(); - r.setStartBefore(newr); - r.setEndAfter(newr); - r.extractContents(); - sel.removeAllRanges(); - sel.addRange(r); - } - }, 10); -}; - -/** The idea here is - * 1. See if we are in a block element - * 2. If we are not, then wrap the current "block" of text into a paragraph - * 3. Now that we have a block element, select all the text between the insertion point - * and just AFTER the end of the block - * eg

        The quick |brown fox jumped over the lazy dog.

        | - * --------------------------------------- - * 4. Extract that from the document, making - *

        The quick

        - * and a document fragment with - *

        brown fox jumped over the lazy dog.

        - * 5. Reinsert it just after the block element - *

        The quick

        brown fox jumped over the lazy dog.

        - * - * Along the way, allow inserting blank paragraphs, which will look like


        - */ - -HTMLArea.prototype.dom_checkInsertP = function() { - - // Get the insertion point, we'll scrub any highlighted text the user wants rid of while we are there. - var sel = this._getSelection(); - var range = this._createRange(sel); - if (!range.collapsed) - { - range.deleteContents(); - } - this.deactivateEditor(); - //sel.removeAllRanges(); - //sel.addRange(range); - - var SC = range.startContainer; - var SO = range.startOffset; - var EC = range.endContainer; - var EO = range.endOffset; - - // If the insertion point is character 0 of the - // document, then insert a space character that we will wrap into a paragraph - // in a bit. - if (SC == EC && SC == body && !SO && !EO) - { - p = this._doc.createTextNode(" "); - body.insertBefore(p, body.firstChild); - range.selectNodeContents(p); - SC = range.startContainer; - SO = range.startOffset; - EC = range.endContainer; - EO = range.endOffset; - } - - // See if we are in a block element, if so, great. - var p = this.getAllAncestors(); - - var block = null; - var body = this._doc.body; - for (var i = 0; i < p.length; ++i) - { - if(HTMLArea.isParaContainer(p[i])) - { - break; - } - else if (HTMLArea.isBlockElement(p[i]) && !/body|html/i.test(p[i].tagName)) - { - block = p[i]; - break; - } - } - - // If not in a block element, we'll have to turn some stuff into a paragraph - if (!block) - { - // We want to wrap as much stuff as possible into the paragraph in both directions - // from the insertion point. We start with the start container and walk back up to the - // node just before any of the paragraph containers. - var wrap = range.startContainer; - while(wrap.parentNode && !HTMLArea.isParaContainer(wrap.parentNode)) - { - wrap = wrap.parentNode; - } - var start = wrap; - var end = wrap; - - // Now we walk up the sibling list until we hit the top of the document - // or an element that we shouldn't put in a p (eg other p, div, ul, ol, table) - while(start.previousSibling) - { - if(start.previousSibling.tagName) - { - if(!HTMLArea.isBlockElement(start.previousSibling)) - { - start = start.previousSibling; - } - else - { - break; - } - } - else - { - start = start.previousSibling; - } - } - - // Same down the list - while(end.nextSibling) - { - if(end.nextSibling.tagName) - { - if(!HTMLArea.isBlockElement(end.nextSibling)) - { - end = end.nextSibling; - } - else - { - break; - } - } - else - { - end = end.nextSibling; - } - } - - // Select the entire block - range.setStartBefore(start); - range.setEndAfter(end); - - // Make it a paragraph - range.surroundContents(this._doc.createElement('p')); - - // Which becomes the block element - block = range.startContainer.firstChild; - - // And finally reset the insertion point to where it was originally - range.setStart(SC, SO); - } - - // The start point is the insertion point, so just move the end point to immediatly - // after the block - range.setEndAfter(block); - - // Extract the range, to split the block - // If we just did range.extractContents() then Mozilla does wierd stuff - // with selections, but if we clone, then remove the original range and extract - // the clone, it's quite happy. - var r2 = range.cloneRange(); - sel.removeRange(range); - var df = r2.extractContents(); - - if(df.childNodes.length == 0) - { - df.appendChild(this._doc.createElement('p')); - df.firstChild.appendChild(this._doc.createElement('br')); - } - - if(df.childNodes.length > 1) - { - var nb = this._doc.createElement('p'); - while(df.firstChild) - { - var s = df.firstChild; - df.removeChild(s); - nb.appendChild(s); - } - df.appendChild(nb); - } - - // If the original block is empty, put a nsbp in it. - if (!/\S/.test(block.innerHTML)) - block.innerHTML = " "; - - p = df.firstChild; - if (!/\S/.test(p.innerHTML)) - p.innerHTML = "
        "; - - // If the new block is empty and it's a heading, make it a paragraph - // note, the new block is empty when you are hitting enter at the end of the existing block - if (/^\s*\s*$/.test(p.innerHTML) && /^h[1-6]$/i.test(p.tagName)) - { - df.appendChild(this.convertNode(p, "p")); - df.removeChild(p); - } - - var newblock = block.parentNode.insertBefore(df.firstChild, block.nextSibling); - - /* - if(block.nextSibling) - { - block.parentNode.insertBefore(df, block.nextSibling); - } - else - { - block.parentNode.appendChild(df); - } - */ - - // Select the range (to set the insertion) - // collapse to the start of the new block - // (remember the block might be


        , so if we collapsed to the end the
        would be noticable) - - //range.selectNode(newblock.firstChild); - //range.collapse(true); - - this.activateEditor(); - - var sel = this._getSelection(); - sel.removeAllRanges(); - sel.collapse(newblock,0); - - // scroll into view - this.scrollToElement(newblock); - - //this.forceRedraw(); - -}; - -HTMLArea.prototype.scrollToElement = function(e) -{ - if(HTMLArea.is_gecko) - { - var top = 0; - var left = 0; - while(e) - { - top += e.offsetTop; - left += e.offsetLeft; - if(e.offsetParent && e.offsetParent.tagName.toLowerCase() != 'body') - { - e = e.offsetParent; - } - else - { - e = null; - } - } - this._iframe.contentWindow.scrollTo(left, top); - } -} - // retrieve the HTML HTMLArea.prototype.getHTML = function() { - var html = ''; - switch (this._editMode) { - case "wysiwyg" : - { - if (!this.config.fullPage) - html = HTMLArea.getHTML(this._doc.body, false, this); - else - html = this.doctype + "\n" + HTMLArea.getHTML(this._doc.documentElement, true, this); - break; - } - case "textmode" : - { - html = this._textArea.value; - break; - } - default : - { - alert("Mode <" + mode + "> not defined!"); - return false; - } - } - return html; + switch (this._editMode) { + 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; + default : alert("Mode <" + mode + "> not defined!"); + } + return false; }; -HTMLArea.prototype.outwardHtml = function(html) -{ - html = html.replace(/<(\/?)b(\s|>|\/)/ig, "<$1strong$2"); - html = html.replace(/<(\/?)i(\s|>|\/)/ig, "<$1em$2"); - - // Figure out what our server name is, and how it's referenced - var serverBase = location.href.replace(/(https?:\/\/[^\/]*)\/.*/, '$1') + '/'; - - // IE puts this in can't figure out why - html = html.replace(/https?:\/\/null\//g, serverBase); - - // Make semi-absolute links to be truely absolute - // we do this just to standardize so that special replacements knows what - // to expect - html = html.replace(/((href|src|background)=[\'\"])\/+/ig, '$1' + serverBase); - - html = this.outwardSpecialReplacements(html); - - html = this.fixRelativeLinks(html); - return html; -} - -HTMLArea.prototype.inwardHtml = function(html) -{ - // Midas uses b and i instead of strong and em, um, hello, - // mozilla, this is the 21st century calling! - if (HTMLArea.is_gecko) { - html = html.replace(/<(\/?)strong(\s|>|\/)/ig, "<$1b$2"); - html = html.replace(/<(\/?)em(\s|>|\/)/ig, "<$1i$2"); - } - html = this.inwardSpecialReplacements(html); - - // For IE's sake, make any URLs that are semi-absolute (="/....") to be - // truely absolute - var nullRE = new RegExp('((href|src|background)=[\'"])/+', 'gi'); - html = html.replace(nullRE, '$1' + location.href.replace(/(https?:\/\/[^\/]*)\/.*/, '$1') + '/'); - - html = this.fixRelativeLinks(html); - return html; -} - -HTMLArea.prototype.outwardSpecialReplacements = function(html) -{ - for(var i in this.config.specialReplacements) - { - var from = this.config.specialReplacements[i]; - var to = i; - // alert('out : ' + from + '=>' + to); - var reg = new RegExp(from.replace(HTMLArea.RE_Specials, '\\$1'), 'g'); - html = html.replace(reg, to.replace(/\$/g, '$$$$')); - //html = html.replace(from, to); - } - return html; -} - -HTMLArea.prototype.inwardSpecialReplacements = function(html) -{ - // alert("inward"); - for(var i in this.config.specialReplacements) - { - var from = i; - var to = this.config.specialReplacements[i]; - // alert('in : ' + from + '=>' + to); - // - // html = html.replace(reg, to); - // html = html.replace(from, to); - var reg = new RegExp(from.replace(HTMLArea.RE_Specials, '\\$1'), 'g'); - html = html.replace(reg, to.replace(/\$/g, '$$$$')); // IE uses doubled dollar signs to escape backrefs, also beware that IE also implements $& $_ and $' like perl. - } - return html; -} - - -HTMLArea.prototype.fixRelativeLinks = function(html) -{ - - if(typeof this.config.stripSelfNamedAnchors != 'undefined' && this.config.stripSelfNamedAnchors) - { - var stripRe = new RegExp(document.location.href.replace(HTMLArea.RE_Specials, '\\$1') + '(#.*)', 'g'); - html = html.replace(stripRe, '$1'); - } - - - if(typeof this.config.stripBaseHref != 'undefined' && this.config.stipBaseHref) - { - var baseRe = null - if(typeof this.config.baseHref != 'undefined' && this.config.baseHref != null) - { - baseRe = new RegExp(this.config.baseHref.replace(HTMLArea.RE_Specials, '\\$1'), 'g'); - } - else - { - baseRe = new RegExp(document.location.href.replace(/([^\/]*\/?)$/, '').replace(HTMLArea.RE_Specials, '\\$1'), 'g'); - } - - html = html.replace(baseRe, ''); - } - - if(HTMLArea.is_ie) - { - // This is now done in inward & outward - // Don't know why but IE is doing this (putting http://null/ on links?! - // alert(html); - // var nullRE = new RegExp('https?:\/\/null\/', 'g'); - // html = html.replace(nullRE, location.href.replace(/(https?:\/\/[^\/]*\/).*/, '$1')); - // alert(html); - } - - return html; -} - // retrieve the HTML (fastest version, but uses innerHTML) HTMLArea.prototype.getInnerHTML = function() { - if(!this._doc.body) return ''; - switch (this._editMode) { - case "wysiwyg" : - if (!this.config.fullPage) - // return this._doc.body.innerHTML; - html = this._doc.body.innerHTML; - else - html = this.doctype + "\n" + this._doc.documentElement.innerHTML; - break; - case "textmode" : - html = this._textArea.value; - break; - default : - alert("Mode <" + mode + "> not defined!"); - return false; - } - - return html; + switch (this._editMode) { + 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; + default : alert("Mode <" + mode + "> not defined!"); + } + return false; }; // completely change the HTML inside HTMLArea.prototype.setHTML = function(html) { - switch (this._editMode) { - 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; - default : alert("Mode <" + mode + "> not defined!"); - } - return false; + switch (this._editMode) { + 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; + default : alert("Mode <" + mode + "> not defined!"); + } + return false; }; // sets the given doctype (useful when config.fullPage is true) HTMLArea.prototype.setDoctype = function(doctype) { - this.doctype = doctype; + this.doctype = doctype; }; /*************************************************** * Category: UTILITY FUNCTIONS ***************************************************/ +// browser identification + +HTMLArea.agt = navigator.userAgent.toLowerCase(); +HTMLArea.is_ie = ((HTMLArea.agt.indexOf("msie") != -1) && (HTMLArea.agt.indexOf("opera") == -1)); +HTMLArea.is_opera = (HTMLArea.agt.indexOf("opera") != -1); +HTMLArea.is_mac = (HTMLArea.agt.indexOf("mac") != -1); +HTMLArea.is_mac_ie = (HTMLArea.is_ie && HTMLArea.is_mac); +HTMLArea.is_win_ie = (HTMLArea.is_ie && !HTMLArea.is_mac); +HTMLArea.is_gecko = (navigator.product == "Gecko"); + // variable used to pass the object to the popup editor window. HTMLArea._object = null; // function that returns a clone of the given object HTMLArea.cloneObject = function(obj) { - if (!obj) return null; - var newObj = new Object; + var newObj = new Object; - // check for array objects - if (obj.constructor.toString().indexOf("function Array(") == 1) { - newObj = obj.constructor(); - } + // 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; } - } + // 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; + return newObj; }; // FIXME!!! this should return false for IE < 5.5 HTMLArea.checkSupportedBrowser = function() { - if (HTMLArea.is_gecko) { - if (navigator.productSub < 20021201) { - alert("You need at least Mozilla-1.3 Alpha.\n" + - "Sorry, your Gecko is not supported."); - return false; - } - if (navigator.productSub < 20030210) { - alert("Mozilla < 1.3 Beta is not supported!\n" + - "I'll try, though, but it might not work."); - } - } - return HTMLArea.is_gecko || HTMLArea.is_ie; + if (HTMLArea.is_gecko) { + if (navigator.productSub < 20021201) { + alert("You need at least Mozilla-1.3 Alpha.\n" + + "Sorry, your Gecko is not supported."); + return false; + } + if (navigator.productSub < 20030210) { + alert("Mozilla < 1.3 Beta is not supported!\n" + + "I'll try, though, but it might not work."); + } + } + return HTMLArea.is_gecko || HTMLArea.is_ie; }; // selection & ranges // returns the current selection object HTMLArea.prototype._getSelection = function() { - if (HTMLArea.is_ie) { - return this._doc.selection; - } else { - return this._iframe.contentWindow.getSelection(); - } + if (HTMLArea.is_ie) { + return this._doc.selection; + } else { + return this._iframe.contentWindow.getSelection(); + } }; // returns a range for the current selection HTMLArea.prototype._createRange = function(sel) { - if (HTMLArea.is_ie) { - return sel.createRange(); - } else { - this.focusEditor(); - if (typeof sel != "undefined") { - try { - return sel.getRangeAt(0); - } catch(e) { - return this._doc.createRange(); - } - } else { - return this._doc.createRange(); - } - } + if (HTMLArea.is_ie) { + return sel.createRange(); + } else { + this.focusEditor(); + if (typeof sel != "undefined") { + try { + return sel.getRangeAt(0); + } catch(e) { + return this._doc.createRange(); + } + } else { + return this._doc.createRange(); + } + } }; // event handling HTMLArea._addEvent = function(el, evname, func) { - if (HTMLArea.is_ie) { - el.attachEvent("on" + evname, func); - } else { - el.addEventListener(evname, func, true); - } + if (HTMLArea.is_ie) { + el.attachEvent("on" + evname, func); + } else { + el.addEventListener(evname, func, true); + } }; HTMLArea._addEvents = function(el, evs, func) { - for (var i = evs.length; --i >= 0;) { - HTMLArea._addEvent(el, evs[i], func); - } + for (var i in evs) { + HTMLArea._addEvent(el, evs[i], func); + } }; HTMLArea._removeEvent = function(el, evname, func) { - if (HTMLArea.is_ie) { - el.detachEvent("on" + evname, func); - } else { - el.removeEventListener(evname, func, true); - } + if (HTMLArea.is_ie) { + el.detachEvent("on" + evname, func); + } else { + el.removeEventListener(evname, func, true); + } }; HTMLArea._removeEvents = function(el, evs, func) { - for (var i = evs.length; --i >= 0;) { - HTMLArea._removeEvent(el, evs[i], func); - } + for (var i in evs) { + HTMLArea._removeEvent(el, evs[i], func); + } }; HTMLArea._stopEvent = function(ev) { - if (HTMLArea.is_ie) { - ev.cancelBubble = true; - ev.returnValue = false; - } else { - ev.preventDefault(); - ev.stopPropagation(); - } + if (HTMLArea.is_ie) { + ev.cancelBubble = true; + ev.returnValue = false; + } else { + ev.preventDefault(); + ev.stopPropagation(); + } }; - -HTMLArea.prototype.notifyOn = function(ev, fn) -{ - if(typeof this._notifyListeners[ev] == 'undefined') - { - this._notifyListeners[ev] = [ ]; - } - - this._notifyListeners[ev].push(fn); -} - -HTMLArea.prototype.notifyOf = function(ev, args) -{ - - if(this._notifyListeners[ev]) - { - - for(var i = 0; i < this._notifyListeners[ev].length; i++) - { - this._notifyListeners[ev][i](ev, args); - } - } -} - - HTMLArea._removeClass = function(el, className) { - if (!(el && el.className)) { - return; - } - var cls = el.className.split(" "); - var ar = new Array(); - for (var i = cls.length; i > 0;) { - if (cls[--i] != className) { - ar[ar.length] = cls[i]; - } - } - el.className = ar.join(" "); + if (!(el && el.className)) { + return; + } + var cls = el.className.split(" "); + var ar = new Array(); + for (var i = cls.length; i > 0;) { + if (cls[--i] != className) { + ar[ar.length] = cls[i]; + } + } + el.className = ar.join(" "); }; HTMLArea._addClass = function(el, className) { - // remove the class first, if already there - HTMLArea._removeClass(el, className); - el.className += " " + className; + // remove the class first, if already there + HTMLArea._removeClass(el, className); + el.className += " " + className; }; HTMLArea._hasClass = function(el, className) { - if (!(el && el.className)) { - return false; - } - var cls = el.className.split(" "); - for (var i = cls.length; i > 0;) { - if (cls[--i] == className) { - return true; - } - } - return false; + if (!(el && el.className)) { + return false; + } + var cls = el.className.split(" "); + for (var i = cls.length; i > 0;) { + if (cls[--i] == className) { + return true; + } + } + return false; }; -HTMLArea._blockTags = " body form textarea fieldset ul ol dl li div " + -"p h1 h2 h3 h4 h5 h6 quote pre table thead " + -"tbody tfoot tr td th iframe address blockquote"; HTMLArea.isBlockElement = function(el) { - return el && el.nodeType == 1 && (HTMLArea._blockTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); + var blockTags = " body form textarea fieldset ul ol dl li div " + + "p h1 h2 h3 h4 h5 h6 quote pre table thead " + + "tbody tfoot tr td iframe address "; + return (blockTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); }; -HTMLArea._paraContainerTags = " body td th caption fieldset div"; -HTMLArea.isParaContainer = function(el) -{ - return el && el.nodeType == 1 && (HTMLArea._paraContainerTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); -} - -HTMLArea._closingTags = " head script style div span tr td tbody table em strong b i code cite dfn abbr acronym font a title "; HTMLArea.needsClosingTag = function(el) { - return el && el.nodeType == 1 && (HTMLArea._closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); + var closingTags = " head script style div span tr td tbody table em strong font a title "; + return (closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); }; // performs HTML encoding of some given string HTMLArea.htmlEncode = function(str) { - if(typeof str.replace == 'undefined') str = str.toString(); - // we don't need regexp for that, but.. so be it for now. - str = str.replace(/&/ig, "&"); - str = str.replace(//ig, ">"); - str = str.replace(/\xA0/g, " "); // Decimal 160, non-breaking-space - str = str.replace(/\x22/g, """); - // \x22 means '"' -- we use hex reprezentation so that we don't disturb - // JS compressors (well, at least mine fails.. ;) - return str; + // we don't need regexp for that, but.. so be it for now. + str = str.replace(/&/ig, "&"); + str = str.replace(//ig, ">"); + str = str.replace(/\x22/ig, """); + // \x22 means '"' -- we use hex reprezentation so that we don't disturb + // JS compressors (well, at least mine fails.. ;) + return str; }; // Retrieves the HTML code from the given node. This is a replacement for // getting innerHTML, using standard DOM calls. -// Wrapper catch a Mozilla-Exception with non well formed html source code -HTMLArea.getHTML = function(root, outputRoot, editor){ - try{ - return HTMLArea.getHTMLWrapper(root,outputRoot,editor); - } - catch(e){ - alert('Your Document is not well formed. Check JavaScript console for details.'); - return editor._iframe.contentWindow.document.body.innerHTML; - } -} - -HTMLArea.getHTMLWrapper = function(root, outputRoot, editor) { - var html = ""; - switch (root.nodeType) { - case 10:// Node.DOCUMENT_TYPE_NODE - case 6: // Node.ENTITY_NODE - case 12:// Node.NOTATION_NODE - // this all are for the document type, probably not necessary - break; - - case 2: // Node.ATTRIBUTE_NODE - // Never get here, this has to be handled in the ELEMENT case because - // of IE crapness requring that some attributes are grabbed directly from - // the attribute (nodeValue doesn't return correct values), see - //http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=3porgu4mc4ofcoa1uqkf7u8kvv064kjjb4%404ax.com - // for information - break; - - case 4: // Node.CDATA_SECTION_NODE - // Mozilla seems to convert CDATA into a comment when going into wysiwyg mode, - // don't know about IE - html += ''; - break; - - case 5: // Node.ENTITY_REFERENCE_NODE - html += '&' + root.nodeValue + ';'; - break; - - case 7: // Node.PROCESSING_INSTRUCTION_NODE - // PI's don't seem to survive going into the wysiwyg mode, (at least in moz) - // so this is purely academic - html += ''; - break; - - - case 1: // Node.ELEMENT_NODE - case 11: // Node.DOCUMENT_FRAGMENT_NODE - case 9: // Node.DOCUMENT_NODE - { - var closed; - var i; - var root_tag = (root.nodeType == 1) ? root.tagName.toLowerCase() : ''; - if (root_tag == 'br' && !root.nextSibling) - break; - if (outputRoot) - outputRoot = !(editor.config.htmlRemoveTags && editor.config.htmlRemoveTags.test(root_tag)); - if (HTMLArea.is_ie && root_tag == "head") { - if (outputRoot) - html += ""; - // 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 += ""; - break; - } else if (outputRoot) { - closed = (!(root.hasChildNodes() || HTMLArea.needsClosingTag(root))); - html = "<" + root.tagName.toLowerCase(); - var attrs = root.attributes; - for (i = 0; i < attrs.length; ++i) { - var a = attrs.item(i); - if (!a.specified) { - continue; - } - var name = a.nodeName.toLowerCase(); - if (/_moz_editor_bogus_node/.test(name)) { - html = ""; - break; - } - if (/(_moz)|(contenteditable)|(_msh)/.test(name)) { - // avoid certain attributes - continue; - } - var value; - if (name != "style") { - // IE5.5 reports 25 when cellSpacing is - // 1; other values might be doomed too. - // For this reason we extract the - // values directly from the root node. - // I'm starting to HATE JavaScript - // development. Browser differences - // suck. - // - // 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" && !/^on/.test(name)) { - value = root[a.nodeName]; - } else { - 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 - // FIXME: cssText reported by IE is UPPERCASE - value = root.style.cssText; - } - if (/^(_moz)?$/.test(value)) { - // Mozilla reports some special tags - // here; we don't need them. - continue; - } - html += " " + name + '="' + HTMLArea.htmlEncode(value) + '"'; - } - if (html != "") { - html += closed ? " />" : ">"; - } - } - for (i = root.firstChild; i; i = i.nextSibling) { - html += HTMLArea.getHTMLWrapper(i, true, editor); - } - if (outputRoot && !closed) { - html += ""; - } - break; - } - case 3: // Node.TEXT_NODE - - // 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 - - html = /^script|style$/i.test(root.parentNode.tagName) ? root.data : HTMLArea.htmlEncode(root.data); - break; - - case 8: // Node.COMMENT_NODE - html = ""; - break; // skip comments, for now. - } - return html; +HTMLArea.getHTML = function(root, outputRoot, editor) { + var html = ""; + switch (root.nodeType) { + case 1: // Node.ELEMENT_NODE + case 11: // Node.DOCUMENT_FRAGMENT_NODE + var closed; + var i; + var root_tag = (root.nodeType == 1) ? root.tagName.toLowerCase() : ''; + if (HTMLArea.is_ie && root_tag == "head") { + if (outputRoot) + html += ""; + // 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 += ""; + break; + } else if (outputRoot) { + closed = (!(root.hasChildNodes() || HTMLArea.needsClosingTag(root))); + html = "<" + root.tagName.toLowerCase(); + var attrs = root.attributes; + for (i = 0; i < attrs.length; ++i) { + var a = attrs.item(i); + if (!a.specified) { + continue; + } + var name = a.nodeName.toLowerCase(); + if (/_moz_editor_bogus_node/.test(name)) { + html = ""; + break; + } + if (/_moz|contenteditable|_msh/.test(name)) { + // avoid certain attributes + continue; + } + var value; + if (name != "style") { + // IE5.5 reports 25 when cellSpacing is + // 1; other values might be doomed too. + // For this reason we extract the + // values directly from the root node. + // I'm starting to HATE JavaScript + // development. Browser differences + // suck. + // + // 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]; + } else { + 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 + // FIXME: cssText reported by IE is UPPERCASE + value = root.style.cssText; + } + if (/(_moz|^$)/.test(value)) { + // Mozilla reports some special tags + // here; we don't need them. + continue; + } + html += " " + name + '="' + value + '"'; + } + if (html != "") { + html += closed ? " />" : ">"; + } + } + for (i = root.firstChild; i; i = i.nextSibling) { + html += HTMLArea.getHTML(i, true, editor); + } + if (outputRoot && !closed) { + html += ""; + } + break; + case 3: // Node.TEXT_NODE + // 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 + if ( !root.previousSibling && !root.nextSibling && root.data.match(/^\s*$/i) ) html = ' '; + else html = /^script|style$/i.test(root.parentNode.tagName) ? root.data : HTMLArea.htmlEncode(root.data); + break; + case 4: // Node.CDATA_SECTION_NODE + // FIXME: it seems we never get here, but I believe we should.. + // maybe a browser problem?--CDATA sections are converted to plain text nodes and normalized + // CDATA sections should go "as is" without further encoding + html = ""; + break; + case 8: // Node.COMMENT_NODE + html = ""; + break; // skip comments, for now. + } + return html; }; HTMLArea.prototype.stripBaseURL = function(string) { - var baseurl = this.config.baseURL; + 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 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, ""); + // 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() { - return this.replace(/^\s+/, '').replace(/\s+$/, ''); + a = this.replace(/^\s+/, ''); + return a.replace(/\s+$/, ''); }; // creates a rgb-style color from a number HTMLArea._makeColor = function(v) { - if (typeof v != "number") { - // already in rgb (hopefully); IE doesn't get here. - return v; - } - // IE sends number; convert to rgb. - var r = v & 0xFF; - var g = (v >> 8) & 0xFF; - var b = (v >> 16) & 0xFF; - return "rgb(" + r + "," + g + "," + b + ")"; + if (typeof v != "number") { + // already in rgb (hopefully); IE doesn't get here. + return v; + } + // IE sends number; convert to rgb. + var r = v & 0xFF; + var g = (v >> 8) & 0xFF; + var b = (v >> 16) & 0xFF; + return "rgb(" + r + "," + g + "," + b + ")"; }; // returns hexadecimal color representation from a number or a rgb-style color. HTMLArea._colorToRgb = function(v) { - if (!v) - return ''; + if (!v) + return ''; - // returns the hex representation of one byte (2 digits) - function hex(d) { - return (d < 16) ? ("0" + d.toString(16)) : d.toString(16); - }; + // returns the hex representation of one byte (2 digits) + function hex(d) { + return (d < 16) ? ("0" + d.toString(16)) : d.toString(16); + }; - if (typeof v == "number") { - // we're talking to IE here - var r = v & 0xFF; - var g = (v >> 8) & 0xFF; - var b = (v >> 16) & 0xFF; - return "#" + hex(r) + hex(g) + hex(b); - } + if (typeof v == "number") { + // we're talking to IE here + var r = v & 0xFF; + var g = (v >> 8) & 0xFF; + var b = (v >> 16) & 0xFF; + return "#" + hex(r) + hex(g) + hex(b); + } - if (v.substr(0, 3) == "rgb") { - // in rgb(...) form -- Mozilla - var re = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/; - if (v.match(re)) { - var r = parseInt(RegExp.$1); - var g = parseInt(RegExp.$2); - var b = parseInt(RegExp.$3); - return "#" + hex(r) + hex(g) + hex(b); - } - // doesn't match RE?! maybe uses percentages or float numbers - // -- FIXME: not yet implemented. - return null; - } + if (v.substr(0, 3) == "rgb") { + // in rgb(...) form -- Mozilla + var re = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/; + if (v.match(re)) { + var r = parseInt(RegExp.$1); + var g = parseInt(RegExp.$2); + var b = parseInt(RegExp.$3); + return "#" + hex(r) + hex(g) + hex(b); + } + // doesn't match RE?! maybe uses percentages or float numbers + // -- FIXME: not yet implemented. + return null; + } - if (v.substr(0, 1) == "#") { - // already hex rgb (hopefully :D ) - return v; - } + if (v.substr(0, 1) == "#") { + // already hex rgb (hopefully :D ) + return v; + } - // if everything else fails ;) - return null; + // if everything else fails ;) + return null; }; // modal dialogs for Mozilla (for IE we're using the showModalDialog() call). @@ -3874,29 +2194,29 @@ HTMLArea._colorToRgb = function(v) { // this function will get called after the dialog is closed, with the return // value of the dialog. HTMLArea.prototype._popupDialog = function(url, action, init) { - Dialog(this.popupURL(url), action, init); + Dialog(this.popupURL(url), action, init); }; // paths HTMLArea.prototype.imgURL = function(file, plugin) { - if (typeof plugin == "undefined") - return _editor_url + file; - else - return _editor_url + "plugins/" + plugin + "/img/" + file; + if (typeof plugin == "undefined") + return _editor_url + file; + else + return _editor_url + "plugins/" + plugin + "/img/" + file; }; HTMLArea.prototype.popupURL = function(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; + 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; }; /** @@ -3906,369 +2226,15 @@ HTMLArea.prototype.popupURL = function(file) { * 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; + var el, i, objs = document.getElementsByTagName(tag); + for (i = objs.length; --i >= 0 && (el = objs[i]);) + if (el.id == id) + return el; + return null; }; -/** Use some CSS trickery to toggle borders on tables */ -HTMLArea.prototype._toggleBorders = function() -{ - tables = this._doc.getElementsByTagName('TABLE'); - if(tables.length != 0) - { - if(!this.borders) - { - name = "bordered"; - this.borders = true; - } - else - { - name = ""; - this.borders = false; - } - - for (var ix=0;ix < tables.length;ix++) - { - if(this.borders) - { - HTMLArea._addClass(tables[ix], 'htmtableborders'); - } - else - { - HTMLArea._removeClass(tables[ix], 'htmtableborders'); - } - } - } - return true; -} - - -HTMLArea.addClasses = function(el, classes) - { - if(el != null) - { - var thiers = el.className.trim().split(' '); - var ours = classes.split(' '); - for(var x = 0; x < ours.length; x++) - { - var exists = false; - for(var i = 0; exists == false && i < thiers.length; i++) - { - if(thiers[i] == ours[x]) - { - exists = true; - } - } - if(exists == false) - { - thiers[thiers.length] = ours[x]; - } - } - el.className = thiers.join(' ').trim(); - } - } - -HTMLArea.removeClasses = function(el, classes) -{ - var existing = el.className.trim().split(); - var new_classes = [ ]; - var remove = classes.trim().split(); - - for(var i = 0; i < existing.length; i++) - { - var found = false; - for(var x = 0; x < remove.length && !found; x++) - { - if(existing[i] == remove[x]) - { - found = true; - } - } - if(!found) - { - new_classes[new_classes.length] = existing[i]; - } - } - return new_classes.join(' '); -} - -/** Alias these for convenience */ -HTMLArea.addClass = HTMLArea._addClass; -HTMLArea.removeClass = HTMLArea._removeClass; -HTMLArea._addClasses = HTMLArea.addClasses; -HTMLArea._removeClasses = HTMLArea.removeClasses; - -/** Use XML HTTPRequest to post some data back to the server and do something - * with the response (asyncronously!), this is used by such things as the tidy functions - */ -HTMLArea._postback = function(url, data, handler) -{ - var req = null; - if(HTMLArea.is_ie) - { - req = new ActiveXObject("Microsoft.XMLHTTP"); - } - else - { - req = new XMLHttpRequest(); - } - - var content = ''; - for(var i in data) - { - content += (content.length ? '&' : '') + i + '=' + escape(data[i]); - } - - function callBack() - { - if(req.readyState == 4) - { - if(req.status == 200) - { - handler(req.responseText, req); - } - else - { - alert('An error has occurred: ' + req.statusText); - } - } - } - - req.onreadystatechange = callBack; - - req.open('POST', url, true); - req.setRequestHeader - ( - 'Content-Type', - 'application/x-www-form-urlencoded; charset=UTF-8' - ); - //alert(content); - req.send(content); -} - -HTMLArea._getback = function(url, handler) -{ - var req = null; - if(HTMLArea.is_ie) - { - req = new ActiveXObject("Microsoft.XMLHTTP"); - } - else - { - req = new XMLHttpRequest(); - } - - function callBack() - { - if(req.readyState == 4) - { - if(req.status == 200) - { - handler(req.responseText, req); - } - else - { - alert('An error has occurred: ' + req.statusText); - } - } - } - - req.onreadystatechange = callBack; - req.open('GET', url, true); - req.send(null); -} - -HTMLArea._geturlcontent = function(url) -{ - var req = null; - if(HTMLArea.is_ie) - { - req = new ActiveXObject("Microsoft.XMLHTTP"); - } - else - { - req = new XMLHttpRequest(); - } - - // Synchronous! - req.open('GET', url, false); - req.send(null); - if(req.status == 200) - { - return req.responseText; - } - else - { - return ''; - } - -} - -/** - * Unless somebody already has, make a little function to debug things - */ -if(typeof dump == 'undefined') -{ - function dump(o) { - var s = ''; - for (var prop in o) { - s += prop + ' = ' + o[prop] + '\n'; - } - - x = window.open("", "debugger"); - x.document.write('
        ' + s + '
        '); - } -} - - -HTMLArea.arrayContainsArray = function(a1, a2) -{ - var all_found = true; - for(var x = 0; x < a2.length; x++) - { - var found = false; - for(var i = 0; i < a1.length; i++) - { - if(a1[i] == a2[x]) - { - found = true; - break; - } - } - if(!found) - { - all_found = false; - break; - } - } - return all_found; -} - -HTMLArea.arrayFilter = function(a1, filterfn) -{ - var new_a = [ ]; - for(var x = 0; x < a1.length; x++) - { - if(filterfn(a1[x])) - new_a[new_a.length] = a1[x]; - } - - return new_a; -} - -HTMLArea.uniq_count = 0; -HTMLArea.uniq = function(prefix) -{ - return prefix + HTMLArea.uniq_count++; -} - -/** New language handling functions **/ - - -/** Load a language file. - * This function should not be used directly, HTMLArea._lc will use it when necessary. - * @param context Case sensitive context name, eg 'HTMLArea', 'TableOperations', ... - * @TODO Make this useful. - */ -HTMLArea._loadlang = function(context) -{ - return { }; -} - -/** Return a localised string. - * @param string English language string - * @param context Case sensitive context name, eg 'HTMLArea' (default), 'TableOperations'... - */ -HTMLArea._lc = function(string, context) -{ - if(typeof HTMLArea._lc_catalog == 'undefined') - { - HTMLArea._lc_catalog = [ ]; - } - - if(typeof context == 'undefined') - { - context = 'HTMLArea'; - } - - if(typeof HTMLArea._lc_catalog[context] == 'undefined') - { - HTMLArea._lc_catalog[context] = HTMLArea._loadlang(context); - } - - if(typeof HTMLArea._lc_catalog[context][string] == 'undefined') - { - return string; // Indicate it's untranslated - } - else - { - return HTMLArea._lc_catalog[context][string]; - } -} - -HTMLArea.hasDisplayedChildren = function(el) -{ - var children = el.childNodes; - for(var i =0; i < children.length;i++) - { - if(children[i].tagName) - { - if(children[i].style.display != 'none') - { - return true; - } - } - } - return false; -} - - -HTMLArea._loadback = function(src, callback) -{ - var head = document.getElementsByTagName("head")[0]; - var evt = HTMLArea.is_ie ? "onreadystatechange" : "onload"; - - var script = document.createElement("script"); - script.type = "text/javascript"; - script.src = src; - script[evt] = function() - { - if(HTMLArea.is_ie && !/loaded|complete/.test(window.event.srcElement.readyState)) return; - callback(); - } - head.appendChild(script); -}; - -HTMLArea.collectionToArray = function(collection) -{ - var array = [ ]; - for(var i = 0; i < collection.length; i++) - { - array.push(collection.item(i)); - } - return array; -} - -if(!Array.prototype.append) -{ - Array.prototype.append = function(a) - { - for(var i = 0; i -

        Online demos

        +

        Online demos

          @@ -184,7 +184,7 @@ find htmlarea/ -name "*.cgi" -exec chmod 755 {} \;
        -

        You can contact me directly +

        You can contact me directly only if you want to pay me for implementing custom features to HTMLArea. If you want to sponsor these features (that is, allow them to get back into the public HTMLArea distribution) I'll be cheaper. ;-)

        @@ -192,7 +192,7 @@ find htmlarea/ -name "*.cgi" -exec chmod 755 {} \;
        Mihai Bazon
        - Last modified: Wed Jul 14 13:20:53 CEST 2004 + Last modified: Wed Jan 28 11:54:47 EET 2004 diff --git a/phpgwapi/js/htmlarea/lang/de.js b/phpgwapi/js/htmlarea/lang/de.js index 8b4474b415..7cb00b3a20 100644 --- a/phpgwapi/js/htmlarea/lang/de.js +++ b/phpgwapi/js/htmlarea/lang/de.js @@ -43,8 +43,7 @@ HTMLArea.I18N = { copy: "Kopieren", paste: "Einfügen aus der Zwischenablage", lefttoright: "Textrichtung von Links nach Rechts", - righttoleft: "Textrichtung von Rechts nach Links", - removeformat: "Formatierung entfernen" + righttoleft: "Textrichtung von Rechts nach Links" }, buttons: { diff --git a/phpgwapi/js/htmlarea/lang/en.js b/phpgwapi/js/htmlarea/lang/en.js index e49e89c78a..90a7649a86 100644 --- a/phpgwapi/js/htmlarea/lang/en.js +++ b/phpgwapi/js/htmlarea/lang/en.js @@ -50,10 +50,7 @@ HTMLArea.I18N = { copy: "Copy selection", paste: "Paste from clipboard", lefttoright: "Direction left to right", - righttoleft: "Direction right to left", - removeformat: "Remove formatting", - print: "Print document", - killword: "Clear MSOffice tags" + righttoleft: "Direction right to left" }, buttons: { @@ -73,74 +70,24 @@ HTMLArea.I18N = { "it's very likely that you'll get a 'General Protection Fault' and need to reboot.\n\n" + "You have been warned. Please press OK if you still want to try the full screen editor.", - "MOZ-security-clipboard" : - // Translate Here - "The Paste button does not work in Mozilla based web browsers (technical security reasons). Press CTRL-V on your keyboard to paste directly." + "Moz-Clipboard" : + "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." }, dialogs: { - // Common - "OK" : "OK", "Cancel" : "Cancel", - - "Alignment:" : "Alignment:", - "Not set" : "Not set", - "Left" : "Left", - "Right" : "Right", - "Texttop" : "Texttop", - "Absmiddle" : "Absmiddle", - "Baseline" : "Baseline", - "Absbottom" : "Absbottom", - "Bottom" : "Bottom", - "Middle" : "Middle", - "Top" : "Top", - - "Layout" : "Layout", - "Spacing" : "Spacing", - "Horizontal:" : "Horizontal:", - "Horizontal padding" : "Horizontal padding", - "Vertical:" : "Vertical:", - "Vertical padding" : "Vertical padding", - "Border thickness:" : "Border thickness:", - "Leave empty for no border" : "Leave empty for no border", - - // Insert Link "Insert/Modify Link" : "Insert/Modify Link", - "None (use implicit)" : "None (use implicit)", "New window (_blank)" : "New window (_blank)", - "Same frame (_self)" : "Same frame (_self)", - "Top frame (_top)" : "Top frame (_top)", + "None (use implicit)" : "None (use implicit)", + "OK" : "OK", "Other" : "Other", + "Same frame (_self)" : "Same frame (_self)", "Target:" : "Target:", "Title (tooltip):" : "Title (tooltip):", + "Top frame (_top)" : "Top frame (_top)", "URL:" : "URL:", - "You must enter the URL where this link points to" : "You must enter the URL where this link points to", - // Insert Table - "Insert Table" : "Insert Table", - "Rows:" : "Rows:", - "Number of rows" : "Number of rows", - "Cols:" : "Cols:", - "Number of columns" : "Number of columns", - "Width:" : "Width:", - "Width of the table" : "Width of the table", - "Percent" : "Percent", - "Pixels" : "Pixels", - "Em" : "Em", - "Width unit" : "Width unit", - "Positioning of this table" : "Positioning of this table", - "Cell spacing:" : "Cell spacing:", - "Space between adjacent cells" : "Space between adjacent cells", - "Cell padding:" : "Cell padding:", - "Space between content and border in cell" : "Space between content and border in cell", - // Insert Image - "Insert Image" : "Insert Image", - "Image URL:" : "Image URL:", - "Enter the image URL here" : "Enter the image URL here", - "Preview" : "Preview", - "Preview the image in a new window" : "Preview the image in a new window", - "Alternate text:" : "Alternate text:", - "For browsers that don't support images" : "For browsers that don't support images", - "Positioning of this image" : "Positioning of this image", - "Image Preview:" : "Image Preview:" + "You must enter the URL where this link points to" : "You must enter the URL where this link points to" } }; diff --git a/phpgwapi/js/htmlarea/lang/es.js b/phpgwapi/js/htmlarea/lang/es.js index 8d0594bd3b..5a1e86fdda 100644 --- a/phpgwapi/js/htmlarea/lang/es.js +++ b/phpgwapi/js/htmlarea/lang/es.js @@ -2,50 +2,50 @@ HTMLArea.I18N = { - // the following should be the filename without .js extension - // it will be used for automatically load plugin language. - lang: "es", + // the following should be the filename without .js extension + // it will be used for automatically load plugin language. + lang: "es", - tooltips: { - bold: "Negrita", - italic: "Cursiva", - underline: "Subrayado", - strikethrough: "Tachado", - subscript: "Sub?ndice", - superscript: "Super?ndice", - justifyleft: "Alinear a la Izquierda", - justifycenter: "Centrar", - justifyright: "Alinear a la Derecha", - justifyfull: "Justificar", - orderedlist: "Lista Ordenada", - unorderedlist: "Lista No Ordenada", - outdent: "Aumentar Sangr?a", - indent: "Disminuir Sangr?a", - forecolor: "Color del Texto", - hilitecolor: "Color del Fondo", - inserthorizontalrule: "L?nea Horizontal", - createlink: "Insertar Enlace", - insertimage: "Insertar Imagen", - inserttable: "Insertar Tabla", - htmlmode: "Ver Documento en HTML", - popupeditor: "Ampliar Editor", - about: "Acerca del Editor", - showhelp: "Ayuda", - textindicator: "Estilo Actual", - undo: "Deshacer", - redo: "Rehacer", - cut: "Cortar selecci?n", - copy: "Copiar selecci?n", - paste: "Pegar desde el portapapeles" - }, + tooltips: { + bold: "Negrita", + italic: "Cursiva", + underline: "Subrayado", + strikethrough: "Tachado", + subscript: "Subíndice", + superscript: "Superíndice", + justifyleft: "Alinear a la Izquierda", + justifycenter: "Centrar", + justifyright: "Alinear a la Derecha", + justifyfull: "Justificar", + orderedlist: "Lista Ordenada", + unorderedlist: "Lista No Ordenada", + outdent: "Aumentar Sangría", + indent: "Disminuir Sangría", + forecolor: "Color del Texto", + hilitecolor: "Color del Fondo", + inserthorizontalrule: "Línea Horizontal", + createlink: "Insertar Enlace", + insertimage: "Insertar Imagen", + inserttable: "Insertar Tabla", + htmlmode: "Ver Documento en HTML", + popupeditor: "Ampliar Editor", + about: "Acerca del Editor", + showhelp: "Ayuda", + textindicator: "Estilo Actual", + undo: "Deshacer", + redo: "Rehacer", + cut: "Cortar selección", + copy: "Copiar selección", + paste: "Pegar desde el portapapeles" + }, - buttons: { - "ok": "Aceptar", - "cancel": "Cancelar" - }, + buttons: { + "ok": "Aceptar", + "cancel": "Cancelar" + }, - msg: { - "Path": "Ruta", - "TEXT_MODE": "Esta en modo TEXTO. Use el boton [<>] para cambiar a WYSIWIG" - } + msg: { + "Path": "Ruta", + "TEXT_MODE": "Esta en modo TEXTO. Use el boton [<>] para cambiar a WYSIWIG", + } }; diff --git a/phpgwapi/js/htmlarea/lang/nl.js b/phpgwapi/js/htmlarea/lang/nl.js index 320d38c72d..aa2229a243 100644 --- a/phpgwapi/js/htmlarea/lang/nl.js +++ b/phpgwapi/js/htmlarea/lang/nl.js @@ -47,7 +47,7 @@ HTMLArea.I18N = { undo: "Ongedaan maken", redo: "Herhalen", cut: "Knippen", - copy: "Kopi?ren", + copy: "Kopiëren", paste: "Plakken", lefttoright: "Tekstrichting links naar rechts", righttoleft: "Tekstrichting rechts naar links" @@ -61,7 +61,7 @@ HTMLArea.I18N = { msg: { "Path": "Pad", "TEXT_MODE": "Je bent in TEKST-mode. Gebruik de [<>] knop om terug te keren naar WYSIWYG-mode.", - + "IE-sucks-full-screen" : // translate here "Fullscreen-mode veroorzaakt problemen met Internet Explorer door bugs in de webbrowser " + @@ -86,4 +86,5 @@ HTMLArea.I18N = { "URL:" : "URL:", "You must enter the URL where this link points to" : "Geef de URL in waar de link naar verwijst" } -}; \ No newline at end of file +}; + diff --git a/phpgwapi/js/htmlarea/lang/vn.js b/phpgwapi/js/htmlarea/lang/vn.js index a391dd3ee4..77424965b6 100644 --- a/phpgwapi/js/htmlarea/lang/vn.js +++ b/phpgwapi/js/htmlarea/lang/vn.js @@ -1,77 +1,51 @@ // I18N constants : Vietnamese // LANG: "en", ENCODING: UTF-8 // Author: Nguyá»…n Äình Nam, -// Modified 21/07/2004 by Phạm Mai Quân HTMLArea.I18N = { - // the following should be the filename without .js extension - // it will be used for automatically load plugin language. - lang: "vn", + // the following should be the filename without .js extension + // it will be used for automatically load plugin language. + lang: "vn", - tooltips: { - bold: "Äậm", - italic: "Nghiêng", - underline: "Gạch Chân", - strikethrough: "Gạch Xóa", - subscript: "Viết Xuống DÆ°á»›i", - superscript: "Viết Lên Trên", - justifyleft: "Căn Trái", - justifycenter: "Căn Giữa", - justifyright: "Căn Phải", - justifyfull: "Căn Äá»u", - insertorderedlist: "Danh Sách Có Thứ Tá»± (1, 2, 3)", - insertunorderedlist: "Danh Sách Phi Thứ Tá»± (Chấm đầu dòng)", - outdent: "Lùi Ra Ngoài", - indent: "Thụt Vào Trong", - forecolor: "Màu Chữ", - hilitecolor: "Màu Ná»n", - inserthorizontalrule: "Dòng Kẻ Ngang", - createlink: "Tạo Liên Kết", - insertimage: "Chèn Ảnh", - inserttable: "Chèn Bảng", - htmlmode: "Chế Äá»™ Mã HTML", - popupeditor: "Phóng To Ô Soạn Thảo", - about: "Tá»± Giá»›i Thiệu", - showhelp: "Giúp Äỡ", - textindicator: "Äịnh Dạng Hiện Thá»i", - undo: "Hủy thao tác trÆ°á»›c", - redo: "Lấy lại thao tác vừa bá»", - cut: "Cắt", - copy: "Sao chép", - paste: "Dán", - lefttoright: "Viết từ trái sang phải", - righttoleft: "Viết từ phải sang trái" - }, - buttons: { - "ok": "Äồng ý", - "cancel": "Hủy", - - "IE-sucks-full-screen" : - // translate here - "Chế Ä‘á»™ phóng to ô soạn thảo có thể gây lá»—i vá»›i Internet Explorer vì má»™t số lá»—i của trình duyệt này," + - " vì thế chế Ä‘á»™ này có thể sẽ không chạy. Hiển thị không đúng, lá»™n xá»™n, không có đầy đủ chức năng," + - " và cÅ©ng có thể làm trình duyệt của bạn bị tắt ngang. Nếu bạn Ä‘ang sá»­ dụng Windows 9x " + - "bạn có thể bị báo lá»—i 'General Protection Fault' và máy tính của bạn buá»™c phải khởi Ä‘á»™ng lại.\n\n" + - "Chúng tôi đã cảnh báo bạn. Nhấn nút 'Äồng ý' nếu bạn vẫn muốn sá»­ dụng tính năng này." - }, - msg: { - "Path": "ÄÆ°á»ng Dẫn", - "TEXT_MODE": "Bạn Ä‘ang ở chế Ä‘á»™ text. Sá»­ dụng nút [<>] để chuyển lại chế Ä‘á»™ WYSIWIG." - }, - - dialogs: { - "Cancel" : "Hủy", - "Insert/Modify Link" : "Thêm/Chỉnh sá»­a Ä‘Æ°á»ng dẫn", - "New window (_blank)" : "Cá»­a sổ má»›i (_blank)", - "None (use implicit)" : "Không (sá»­ dụng implicit)", - "OK" : "Äồng ý", - "Other" : "Khác", - "Same frame (_self)" : "Trên cùng khung (_self)", - "Target:" : "NÆ¡i hiện thị:", - "Title (tooltip):" : "Tiêu Ä‘á» (của hÆ°á»›ng dẫn):", - "Top frame (_top)" : "Khung trên cùng (_top)", - "URL:" : "URL:", - "You must enter the URL where this link points to" : "Bạn phải Ä‘iá»n địa chỉ (URL) mà Ä‘Æ°á»ng dẫn sẽ liên kết tá»›i" - } + tooltips: { + bold: "Äậm", + italic: "Nghiêng", + underline: "Gạch Chân", + strikethrough: "Gạch Xóa", + subscript: "Viết Xuống DÆ°á»›i", + superscript: "Viết Lên Trên", + justifyleft: "Căn Trái", + justifycenter: "Căn Giữa", + justifyright: "Căn Phải", + justifyfull: "Căn Äá»u", + orderedlist: "Danh Sách Có Thứ Tá»±", + unorderedlist: "Danh Sách Phi Thứ Tá»±", + outdent: "Lùi Ra Ngoài", + indent: "Thụt Vào Trong", + forecolor: "Màu Chữ", + backcolor: "Màu Ná»n", + horizontalrule: "Dòng Kẻ Ngang", + createlink: "Tạo Liên Kết", + insertimage: "Chèn Ảnh", + inserttable: "Chèn Bảng", + htmlmode: "Chế Äá»™ Mã HTML", + popupeditor: "Phóng To Ô Soạn Thảo", + about: "Tá»± Giá»›i Thiệu", + showhelp: "Giúp Äỡ", + textindicator: "Äịnh Dạng Hiện Thá»i", + undo: "Undo", + redo: "Redo", + cut: "Cắt", + copy: "Copy", + paste: "Dán" + }, + buttons: { + "ok": "OK", + "cancel": "Hủy" + }, + msg: { + "Path": "ÄÆ°á»ng Dẫn", + "TEXT_MODE": "Bạn Ä‘ang ở chế Ä‘á»™ text. Sá»­ dụng nút [<>] để chuyển lại chế Ä‘á»™ WYSIWIG." + } }; diff --git a/phpgwapi/js/htmlarea/plugins/ContextMenu/context-menu.js b/phpgwapi/js/htmlarea/plugins/ContextMenu/context-menu.js index d31808fd56..3d2e8233eb 100755 --- a/phpgwapi/js/htmlarea/plugins/ContextMenu/context-menu.js +++ b/phpgwapi/js/htmlarea/plugins/ContextMenu/context-menu.js @@ -63,26 +63,6 @@ ContextMenu.prototype.getContextMenu = function(target) { tbo.buttonPress(editor, opcode); }; - function insertPara(after) { - var el = currentTarget; - var par = el.parentNode; - var p = editor._doc.createElement("p"); - p.appendChild(editor._doc.createElement("br")); - par.insertBefore(p, after ? el.nextSibling : el); - var sel = editor._getSelection(); - var range = editor._createRange(sel); - if (!HTMLArea.is_ie) { - sel.removeAllRanges(); - range.selectNodeContents(p); - range.collapse(true); - sel.addRange(range); - } else { - range.moveToElementText(p); - range.collapse(true); - range.select(); - } - }; - for (; target; target = target.parentNode) { var tag = target.tagName; if (!tag) @@ -209,41 +189,32 @@ ContextMenu.prototype.getContextMenu = function(target) { i18n["Create a link"], config.btnList["createlink"][1] ]); - for (var i = 0; i < elmenus.length; ++i) + for (var i in elmenus) menu.push(elmenus[i]); - if (!/html|body/i.test(currentTarget.tagName)) - menu.push(null, - [ i18n["Remove the"] + " <" + currentTarget.tagName + "> " + i18n["Element"], - function() { - if (confirm(i18n["Please confirm that you want to remove this element:"] + " " + - currentTarget.tagName)) { - var el = currentTarget; - var p = el.parentNode; - p.removeChild(el); - if (HTMLArea.is_gecko) { - if (p.tagName.toLowerCase() == "td" && !p.hasChildNodes()) - p.appendChild(editor._doc.createElement("br")); - editor.forceRedraw(); - editor.focusEditor(); - editor.updateToolbar(); - if (table) { - var save_collapse = table.style.borderCollapse; - table.style.borderCollapse = "collapse"; - table.style.borderCollapse = "separate"; - table.style.borderCollapse = save_collapse; - } + menu.push(null, + [ i18n["Remove the"] + " <" + currentTarget.tagName + "> " + i18n["Element"], + function() { + if (confirm(i18n["Please confirm that you want to remove this element:"] + " " + currentTarget.tagName)) { + var el = currentTarget; + var p = el.parentNode; + p.removeChild(el); + if (HTMLArea.is_gecko) { + if (p.tagName.toLowerCase() == "td" && !p.hasChildNodes()) + p.appendChild(editor._doc.createElement("br")); + editor.forceRedraw(); + editor.focusEditor(); + editor.updateToolbar(); + if (table) { + var save_collapse = table.style.borderCollapse; + table.style.borderCollapse = "collapse"; + table.style.borderCollapse = "separate"; + table.style.borderCollapse = save_collapse; } } - }, - i18n["Remove this node from the document"] ], - [ i18n["Insert paragraph before"], - function() { insertPara(false); }, - i18n["Insert a paragraph before the current node"] ], - [ i18n["Insert paragraph after"], - function() { insertPara(true); }, - i18n["Insert a paragraph after the current node"] ] - ); + } + }, + i18n["Remove this node from the document"] ]); return menu; }; @@ -414,8 +385,12 @@ ContextMenu.prototype.popupMenu = function(ev) { } if (!HTMLArea.is_ie) { - var dx = x + div.offsetWidth - window.innerWidth + 4; - var dy = y + div.offsetHeight - window.innerHeight + 4; +// var dx = x + div.offsetWidth - window.innerWidth + 4; +// var dy = y + div.offsetHeight - window.innerHeight + 4; + + var dx = x + div.offsetWidth - window.innerWidth - window.pageXOffset + 4; + var dy = y + div.offsetHeight - window.innerHeight - window.pageYOffset + 4; + if (dx > 0) x -= dx; if (dy > 0) y -= dy; div.style.left = x + "px"; diff --git a/phpgwapi/js/htmlarea/plugins/ContextMenu/lang/en.js b/phpgwapi/js/htmlarea/plugins/ContextMenu/lang/en.js index 98b35728a6..8d15914d82 100755 --- a/phpgwapi/js/htmlarea/plugins/ContextMenu/lang/en.js +++ b/phpgwapi/js/htmlarea/plugins/ContextMenu/lang/en.js @@ -40,8 +40,6 @@ ContextMenu.I18N = { "Make link" : "Make lin_k...", "Remove the" : "Remove the", "Element" : "Element...", - "Insert paragraph before" : "Insert paragraph before", - "Insert paragraph after" : "Insert paragraph after", // Other labels (tooltips and alert/confirm box messages) @@ -64,7 +62,5 @@ ContextMenu.I18N = { "Insert a new column before the current one" : "Insert a new column before the current one", "Insert a new column after the current one" : "Insert a new column after the current one", "Delete the current column" : "Delete the current column", - "Create a link" : "Create a link", - "Insert a paragraph before the current node" : "Insert a paragraph before the current node", - "Insert a paragraph after the current node" : "Insert a paragraph after the current node" + "Create a link" : "Create a link" }; diff --git a/phpgwapi/js/htmlarea/plugins/ContextMenu/lang/lang.php b/phpgwapi/js/htmlarea/plugins/ContextMenu/lang/lang.php index f49f456c3e..b74c82ca57 100644 --- a/phpgwapi/js/htmlarea/plugins/ContextMenu/lang/lang.php +++ b/phpgwapi/js/htmlarea/plugins/ContextMenu/lang/lang.php @@ -24,6 +24,7 @@ $GLOBALS['phpgw_info']['flags'] = Array( ); include('../../../../../../header.inc.php'); +header('Content-type: text/javascript; charset='.$GLOBALS['phpgw']->translation->charset()); $GLOBALS['phpgw']->translation->add_app('htmlarea-ContextMenu'); // I18N constants diff --git a/phpgwapi/js/htmlarea/plugins/ContextMenu/menu.css b/phpgwapi/js/htmlarea/plugins/ContextMenu/menu.css index 35b17a81de..70626b5045 100644 --- a/phpgwapi/js/htmlarea/plugins/ContextMenu/menu.css +++ b/phpgwapi/js/htmlarea/plugins/ContextMenu/menu.css @@ -7,7 +7,6 @@ div.htmlarea-context-menu { border: 1px solid #aca899; padding: 2px; background-color: #fff; - color: #000; cursor: default; z-index: 1000; } diff --git a/phpgwapi/js/htmlarea/plugins/EnterParagraphs/enter-paragraphs.js b/phpgwapi/js/htmlarea/plugins/EnterParagraphs/enter-paragraphs.js index 2b901b679f..c9a768da12 100755 --- a/phpgwapi/js/htmlarea/plugins/EnterParagraphs/enter-paragraphs.js +++ b/phpgwapi/js/htmlarea/plugins/EnterParagraphs/enter-paragraphs.js @@ -6,20 +6,20 @@ // This notice MUST stay intact for use (see license.txt). function EnterParagraphs(editor, params) { - this.editor = editor; - // activate only if we're talking to Gecko - if (HTMLArea.is_gecko) - this.onKeyPress = this.__onKeyPress; + this.editor = editor; + // activate only if we're talking to Gecko + if (HTMLArea.is_gecko) + this.onKeyPress = this.__onKeyPress; }; EnterParagraphs._pluginInfo = { - name : "EnterParagraphs", - version : "1.0", - developer : "Adam Wright", - developer_url : "http://blog.hipikat.org/", - sponsor : "The University of Western Australia", - sponsor_url : "http://www.uwa.edu.au/", - license : "htmlArea" + name : "EnterParagraphs", + version : "1.0", + developer : "Adam Wright", + developer_url : "http://blog.hipikat.org/", + sponsor : "The University of Western Australia", + sponsor_url : "http://www.uwa.edu.au/", + license : "htmlArea" }; // An array of elements who, in html4, by default, have an inline display and can have children @@ -28,177 +28,177 @@ EnterParagraphs.prototype._html4_inlines_re = /^(a|abbr|acronym|b|bdo|big|cite|c // Finds the first parent element of a given node whose display is probably not inline EnterParagraphs.prototype.parentBlock = function(node) { - while (node.parentNode && (node.nodeType != 1 || this._html4_inlines_re.test(node.tagName))) - node = node.parentNode; - return node; + while (node.parentNode && (node.nodeType != 1 || this._html4_inlines_re.test(node.tagName))) + node = node.parentNode; + return node; }; // Internal function for recursively itterating over a all nodes in a fragment // If a callback function returns a non-null value, that is returned and the crawl is therefore broken EnterParagraphs.prototype.walkNodeChildren = function(me, callback) { - if (me.firstChild) { - var myChild = me.firstChild; - var retVal; - while (myChild) { - if ((retVal = callback(this, myChild)) != null) - return retVal; - if ((retVal = this.walkNodeChildren(myChild, callback)) != null) - return retVal; - myChild = myChild.nextSibling; - } - } + if (me.firstChild) { + var myChild = me.firstChild; + var retVal; + while (myChild) { + if ((retVal = callback(this, myChild)) != null) + return retVal; + if ((retVal = this.walkNodeChildren(myChild, callback)) != null) + return retVal; + myChild = myChild.nextSibling; + } + } }; // Callback function to be performed on each node in the hierarchy // Sets flag to true if we find actual text or an element that's not usually displayed inline EnterParagraphs.prototype._isFilling = function(self, node) { - if (node.nodeType == 1 && !self._html4_inlines_re.test(node.nodeName)) - return true; - else if (node.nodeType == 3 && node.nodeValue != '') - return true; - return null; - //alert(node.nodeName); + if (node.nodeType == 1 && !self._html4_inlines_re.test(node.nodeName)) + return true; + else if (node.nodeType == 3 && node.nodeValue != '') + return true; + return null; + //alert(node.nodeName); }; // Inserts a node deeply on the left of a hierarchy of nodes EnterParagraphs.prototype.insertDeepLeftText = function(target, toInsert) { - var falling = target; - while (falling.firstChild && falling.firstChild.nodeType == 1) - falling = falling.firstChild; - //var refNode = falling.firstChild ? falling.firstChild : null; - //falling.insertBefore(toInsert, refNode); - falling.innerHTML = toInsert; + var falling = target; + while (falling.firstChild && falling.firstChild.nodeType == 1) + falling = falling.firstChild; + //var refNode = falling.firstChild ? falling.firstChild : null; + //falling.insertBefore(toInsert, refNode); + falling.innerHTML = toInsert; }; // Kind of like a macros, for a frequent query... EnterParagraphs.prototype.isElem = function(node, type) { - return node.nodeName.toLowerCase() == type.toLowerCase(); + return node.nodeName.toLowerCase() == type.toLowerCase(); }; // The onKeyPress even that does all the work - nicely breaks the line into paragraphs EnterParagraphs.prototype.__onKeyPress = function(ev) { - if (ev.keyCode == 13 && !ev.shiftKey && this.editor._iframe.contentWindow.getSelection) { + if (ev.keyCode == 13 && !ev.shiftKey && this.editor._iframe.contentWindow.getSelection) { - var editor = this.editor; + var editor = this.editor; - // Get the selection and solid references to what we're dealing with chopping - var sel = editor._iframe.contentWindow.getSelection(); + // Get the selection and solid references to what we're dealing with chopping + var sel = editor._iframe.contentWindow.getSelection(); - // Set the start and end points such that they're going /forward/ through the document - var rngLeft = editor._doc.createRange(); var rngRight = editor._doc.createRange(); - rngLeft.setStart(sel.anchorNode, sel.anchorOffset); rngRight.setStart(sel.focusNode, sel.focusOffset); - rngLeft.collapse(true); rngRight.collapse(true); + // Set the start and end points such that they're going /forward/ through the document + var rngLeft = editor._doc.createRange(); var rngRight = editor._doc.createRange(); + rngLeft.setStart(sel.anchorNode, sel.anchorOffset); rngRight.setStart(sel.focusNode, sel.focusOffset); + rngLeft.collapse(true); rngRight.collapse(true); - var direct = rngLeft.compareBoundaryPoints(rngLeft.START_TO_END, rngRight) < 0; + var direct = rngLeft.compareBoundaryPoints(rngLeft.START_TO_END, rngRight) < 0; - var startNode = direct ? sel.anchorNode : sel.focusNode; - var startOffset = direct ? sel.anchorOffset : sel.focusOffset; - var endNode = direct ? sel.focusNode : sel.anchorNode; - var endOffset = direct ? sel.focusOffset : sel.anchorOffset; + var startNode = direct ? sel.anchorNode : sel.focusNode; + var startOffset = direct ? sel.anchorOffset : sel.focusOffset; + var endNode = direct ? sel.focusNode : sel.anchorNode; + var endOffset = direct ? sel.focusOffset : sel.anchorOffset; - // Find the parent blocks of nodes at either end, and their attributes if they're paragraphs - var startBlock = this.parentBlock(startNode); var endBlock = this.parentBlock(endNode); - var attrsLeft = new Array(); var attrsRight = new Array(); + // Find the parent blocks of nodes at either end, and their attributes if they're paragraphs + var startBlock = this.parentBlock(startNode); var endBlock = this.parentBlock(endNode); + var attrsLeft = new Array(); var attrsRight = new Array(); - // If a list, let the browser take over, if we're in a paragraph, gather it's attributes - if (this.isElem(startBlock, 'li') || this.isElem(endBlock, 'li')) - return; + // If a list, let the browser take over, if we're in a paragraph, gather it's attributes + if (this.isElem(startBlock, 'li') || this.isElem(endBlock, 'li')) + return; - if (this.isElem(startBlock, 'p')) { - for (var i = 0; i < startBlock.attributes.length; i++) { - attrsLeft[startBlock.attributes[i].nodeName] = startBlock.attributes[i].nodeValue; - } - } - if (this.isElem(endBlock, 'p')) { - for (var i = 0; i < endBlock.attributes.length; i++) { - // If we start and end within one paragraph, don't duplicate the 'id' - if (endBlock != startBlock || endBlock.attributes[i].nodeName.toLowerCase() != 'id') - attrsRight[endBlock.attributes[i].nodeName] = endBlock.attributes[i].nodeValue; - } - } + if (this.isElem(startBlock, 'p')) { + for (var i = 0; i < startBlock.attributes.length; i++) { + attrsLeft[startBlock.attributes[i].nodeName] = startBlock.attributes[i].nodeValue; + } + } + if (this.isElem(endBlock, 'p')) { + for (var i = 0; i < endBlock.attributes.length; i++) { + // If we start and end within one paragraph, don't duplicate the 'id' + if (endBlock != startBlock || endBlock.attributes[i].nodeName.toLowerCase() != 'id') + attrsRight[endBlock.attributes[i].nodeName] = endBlock.attributes[i].nodeValue; + } + } - // Look for where to start and end our chopping - within surrounding paragraphs - // if they exist, or at the edges of the containing block, otherwise - var startChop = startNode; var endChop = endNode; + // Look for where to start and end our chopping - within surrounding paragraphs + // if they exist, or at the edges of the containing block, otherwise + var startChop = startNode; var endChop = endNode; - while ((startChop.previousSibling && !this.isElem(startChop.previousSibling, 'p')) - || (startChop.parentNode && startChop.parentNode != startBlock && startChop.parentNode.nodeType != 9)) - startChop = startChop.previousSibling ? startChop.previousSibling : startChop.parentNode; + while ((startChop.previousSibling && !this.isElem(startChop.previousSibling, 'p')) + || (startChop.parentNode && startChop.parentNode != startBlock && startChop.parentNode.nodeType != 9)) + startChop = startChop.previousSibling ? startChop.previousSibling : startChop.parentNode; - while ((endChop.nextSibling && !this.isElem(endChop.nextSibling, 'p')) - || (endChop.parentNode && endChop.parentNode != endBlock && endChop.parentNode.nodeType != 9)) - endChop = endChop.nextSibling ? endChop.nextSibling : endChop.parentNode; + while ((endChop.nextSibling && !this.isElem(endChop.nextSibling, 'p')) + || (endChop.parentNode && endChop.parentNode != endBlock && endChop.parentNode.nodeType != 9)) + endChop = endChop.nextSibling ? endChop.nextSibling : endChop.parentNode; - // Set up new paragraphs - var pLeft = editor._doc.createElement('p'); var pRight = editor._doc.createElement('p'); + // Set up new paragraphs + var pLeft = editor._doc.createElement('p'); var pRight = editor._doc.createElement('p'); - for (var attrName in attrsLeft) { - var thisAttr = editor._doc.createAttribute(attrName); - thisAttr.value = attrsLeft[attrName]; - pLeft.setAttributeNode(thisAttr); - } - for (var attrName in attrsRight) { - var thisAttr = editor._doc.createAttribute(attrName); - thisAttr.value = attrsRight[attrName]; - pRight.setAttributeNode(thisAttr); - } + for (var attrName in attrsLeft) { + var thisAttr = editor._doc.createAttribute(attrName); + thisAttr.value = attrsLeft[attrName]; + pLeft.setAttributeNode(thisAttr); + } + for (var attrName in attrsRight) { + var thisAttr = editor._doc.createAttribute(attrName); + thisAttr.value = attrsRight[attrName]; + pRight.setAttributeNode(thisAttr); + } - // Get the ranges destined to be stuffed into new paragraphs - rngLeft.setStartBefore(startChop); - rngLeft.setEnd(startNode,startOffset); - pLeft.appendChild(rngLeft.cloneContents()); // Copy into pLeft + // Get the ranges destined to be stuffed into new paragraphs + rngLeft.setStartBefore(startChop); + rngLeft.setEnd(startNode,startOffset); + pLeft.appendChild(rngLeft.cloneContents()); // Copy into pLeft - rngRight.setEndAfter(endChop); - rngRight.setStart(endNode,endOffset); - pRight.appendChild(rngRight.cloneContents()); // Copy into pRight + rngRight.setEndAfter(endChop); + rngRight.setStart(endNode,endOffset); + pRight.appendChild(rngRight.cloneContents()); // Copy into pRight - // If either paragraph is empty, fill it with a nonbreakable space - var foundBlock = false; - foundBlock = this.walkNodeChildren(pLeft, this._isFilling); - if (foundBlock != true) - this.insertDeepLeftText(pLeft, ' '); + // If either paragraph is empty, fill it with a nonbreakable space + var foundBlock = false; + foundBlock = this.walkNodeChildren(pLeft, this._isFilling); + if (foundBlock != true) + this.insertDeepLeftText(pLeft, ' '); - foundBlock = false; - foundBlock = this.walkNodeChildren(pRight, this._isFilling); - if (foundBlock != true) - this.insertDeepLeftText(pRight, ' '); + foundBlock = false; + foundBlock = this.walkNodeChildren(pRight, this._isFilling); + if (foundBlock != true) + this.insertDeepLeftText(pRight, ' '); - // Get a range for everything to be replaced and replace it - var rngAround = editor._doc.createRange(); + // Get a range for everything to be replaced and replace it + var rngAround = editor._doc.createRange(); - if (!startChop.previousSibling && this.isElem(startChop.parentNode, 'p')) - rngAround.setStartBefore(startChop.parentNode); - else - rngAround.setStart(rngLeft.startContainer, rngLeft.startOffset); + if (!startChop.previousSibling && this.isElem(startChop.parentNode, 'p')) + rngAround.setStartBefore(startChop.parentNode); + else + rngAround.setStart(rngLeft.startContainer, rngLeft.startOffset); - if (!endChop.nextSibling && this.isElem(endChop.parentNode, 'p')) - rngAround.setEndAfter(endChop.parentNode); - else - rngAround.setEnd(rngRight.endContainer, rngRight.endOffset); + if (!endChop.nextSibling && this.isElem(endChop.parentNode, 'p')) + rngAround.setEndAfter(endChop.parentNode); + else + rngAround.setEnd(rngRight.endContainer, rngRight.endOffset); - rngAround.deleteContents(); - rngAround.insertNode(pRight); - rngAround.insertNode(pLeft); + rngAround.deleteContents(); + rngAround.insertNode(pRight); + rngAround.insertNode(pLeft); - // Set the selection to the start of the (second) new paragraph - if (pRight.firstChild) { - while (pRight.firstChild && this._html4_inlines_re.test(pRight.firstChild.nodeName)) - pRight = pRight.firstChild; - // Slip into any inline tags - if (pRight.firstChild && pRight.firstChild.nodeType == 3) - pRight = pRight.firstChild; // and text, if they've got it + // Set the selection to the start of the (second) new paragraph + if (pRight.firstChild) { + while (pRight.firstChild && this._html4_inlines_re.test(pRight.firstChild.nodeName)) + pRight = pRight.firstChild; + // Slip into any inline tags + if (pRight.firstChild && pRight.firstChild.nodeType == 3) + pRight = pRight.firstChild; // and text, if they've got it - var rngCaret = editor._doc.createRange(); - rngCaret.setStart(pRight, 0); - rngCaret.collapse(true); + var rngCaret = editor._doc.createRange(); + rngCaret.setStart(pRight, 0); + rngCaret.collapse(true); - sel = editor._iframe.contentWindow.getSelection(); - sel.removeAllRanges(); - sel.addRange(rngCaret); - } + sel = editor._iframe.contentWindow.getSelection(); + sel.removeAllRanges(); + sel.addRange(rngCaret); + } - // Stop the bubbling - HTMLArea._stopEvent(ev); - } + // Stop the bubbling + HTMLArea._stopEvent(ev); + } }; diff --git a/phpgwapi/js/htmlarea/plugins/FullPage/full-page.js b/phpgwapi/js/htmlarea/plugins/FullPage/full-page.js index 7806ccfb89..ad024cee2b 100755 --- a/phpgwapi/js/htmlarea/plugins/FullPage/full-page.js +++ b/phpgwapi/js/htmlarea/plugins/FullPage/full-page.js @@ -49,7 +49,6 @@ FullPage.prototype.buttonPress = function(editor, id) { var links = doc.getElementsByTagName("link"); var style1 = ''; var style2 = ''; - var charset = ''; for (var i = links.length; --i >= 0;) { var link = links[i]; if (/stylesheet/i.test(link.rel)) { @@ -59,14 +58,6 @@ FullPage.prototype.buttonPress = function(editor, id) { style1 = link.href; } } - var metas = doc.getElementsByTagName("meta"); - for (var i = metas.length; --i >= 0;) { - var meta = metas[i]; - if (/content-type/i.test(meta.httpEquiv)) { - r = /^text\/html; *charset=(.*)$/i.exec(meta.content); - charset = r[1]; - } - } var title = doc.getElementsByTagName("title")[0]; title = title ? title.innerHTML : ''; var init = { @@ -76,7 +67,7 @@ FullPage.prototype.buttonPress = function(editor, id) { f_body_fgcolor : HTMLArea._colorToRgb(doc.body.style.color), f_base_style : style1, f_alt_style : style2, - f_charset : charset, + editor : editor }; editor._popupDialog("plugin://FullPage/docprop", function(params) { @@ -91,11 +82,8 @@ FullPage.prototype.setDocProp = function(params) { var doc = this.editor._doc; var head = doc.getElementsByTagName("head")[0]; var links = doc.getElementsByTagName("link"); - var metas = doc.getElementsByTagName("meta"); var style1 = null; var style2 = null; - var charset = null; - var charset_meta = null; for (var i = links.length; --i >= 0;) { var link = links[i]; if (/stylesheet/i.test(link.rel)) { @@ -105,27 +93,12 @@ FullPage.prototype.setDocProp = function(params) { style1 = link; } } - for (var i = metas.length; --i >= 0;) { - var meta = metas[i]; - if (/content-type/i.test(meta.httpEquiv)) { - r = /^text\/html; *charset=(.*)$/i.exec(meta.content); - charset = r[1]; - charset_meta = meta; - } - } function createLink(alt) { var link = doc.createElement("link"); link.rel = alt ? "alternate stylesheet" : "stylesheet"; head.appendChild(link); return link; }; - function createMeta(name, content) { - var meta = doc.createElement("meta"); - meta.httpEquiv = name; - meta.content = content; - head.appendChild(meta); - return meta; - }; if (!style1 && params.f_base_style) style1 = createLink(false); @@ -141,14 +114,7 @@ FullPage.prototype.setDocProp = function(params) { else if (style2) head.removeChild(style2); - if (charset_meta) { - head.removeChild(charset_meta); - charset_meta = null; - } - if (!charset_meta && params.f_charset) - charset_meta = createMeta("Content-Type", "text/html; charset="+params.f_charset); - - for (var i in params) { + for (var i in params) { var val = params[i]; switch (i) { case "f_title": diff --git a/phpgwapi/js/htmlarea/plugins/FullPage/lang/lang.php b/phpgwapi/js/htmlarea/plugins/FullPage/lang/lang.php index ef5a0d9fdc..f7d91d205a 100644 --- a/phpgwapi/js/htmlarea/plugins/FullPage/lang/lang.php +++ b/phpgwapi/js/htmlarea/plugins/FullPage/lang/lang.php @@ -24,6 +24,7 @@ $GLOBALS['phpgw_info']['flags'] = Array( ); include('../../../../../../header.inc.php'); +header('Content-type: text/javascript; charset='.$GLOBALS['phpgw']->translation->charset()); $GLOBALS['phpgw']->translation->add_app('htmlarea-FullPage'); // I18N for the FullPage plugin diff --git a/phpgwapi/js/htmlarea/plugins/FullPage/popups/docprop.html b/phpgwapi/js/htmlarea/plugins/FullPage/popups/docprop.html index eab9a9c288..ee00e2d563 100755 --- a/phpgwapi/js/htmlarea/plugins/FullPage/popups/docprop.html +++ b/phpgwapi/js/htmlarea/plugins/FullPage/popups/docprop.html @@ -16,8 +16,7 @@ window.resizeTo(400, 100); f_body_bgcolor : true, f_body_fgcolor : true, f_base_style : true, - f_alt_style : true, - f_charset : true + f_alt_style : true }; var editor = null; @@ -121,17 +120,6 @@ border-bottom: 1px solid black; letter-spacing: 2px; Text color: - - Character set: - -
        diff --git a/phpgwapi/js/htmlarea/plugins/HtmlTidy/html-tidy.js b/phpgwapi/js/htmlarea/plugins/HtmlTidy/html-tidy.js index 71a2027f3c..7fc52521c0 100755 --- a/phpgwapi/js/htmlarea/plugins/HtmlTidy/html-tidy.js +++ b/phpgwapi/js/htmlarea/plugins/HtmlTidy/html-tidy.js @@ -16,7 +16,7 @@ function HtmlTidy(editor) { // register the toolbar buttons provided by this plugin var toolbar = []; - for (var i = 0; i < bl.length; ++i) { + for (var i in bl) { var btn = bl[i]; if (btn == "html-tidy") { var id = "HT-html-tidy"; diff --git a/phpgwapi/js/htmlarea/plugins/HtmlTidy/lang/lang.php b/phpgwapi/js/htmlarea/plugins/HtmlTidy/lang/lang.php index d9bc8a5abb..8c429427e9 100644 --- a/phpgwapi/js/htmlarea/plugins/HtmlTidy/lang/lang.php +++ b/phpgwapi/js/htmlarea/plugins/HtmlTidy/lang/lang.php @@ -24,6 +24,7 @@ $GLOBALS['phpgw_info']['flags'] = Array( ); include('../../../../../../header.inc.php'); +header('Content-type: text/javascript; charset='.$GLOBALS['phpgw']->translation->charset()); $GLOBALS['phpgw']->translation->add_app('htmlarea-HtmlTidy'); // I18N constants diff --git a/phpgwapi/js/htmlarea/plugins/ListType/lang/lang.php b/phpgwapi/js/htmlarea/plugins/ListType/lang/lang.php index ca38f0bfdb..6b5a1dbb7b 100644 --- a/phpgwapi/js/htmlarea/plugins/ListType/lang/lang.php +++ b/phpgwapi/js/htmlarea/plugins/ListType/lang/lang.php @@ -24,6 +24,7 @@ $GLOBALS['phpgw_info']['flags'] = Array( ); include('../../../../../../header.inc.php'); +header('Content-type: text/javascript; charset='.$GLOBALS['phpgw']->translation->charset()); $GLOBALS['phpgw']->translation->add_app('htmlarea-ListType'); // I18N constants diff --git a/phpgwapi/js/htmlarea/plugins/SpellChecker/.htaccess b/phpgwapi/js/htmlarea/plugins/SpellChecker/.htaccess index 5505990855..2f341a6448 100644 --- a/phpgwapi/js/htmlarea/plugins/SpellChecker/.htaccess +++ b/phpgwapi/js/htmlarea/plugins/SpellChecker/.htaccess @@ -1 +1 @@ -Options +ExecCGI \ No newline at end of file +Options +ExecCGI diff --git a/phpgwapi/js/htmlarea/plugins/SpellChecker/lang/lang.php b/phpgwapi/js/htmlarea/plugins/SpellChecker/lang/lang.php index 72cd33dee9..09be0aa762 100644 --- a/phpgwapi/js/htmlarea/plugins/SpellChecker/lang/lang.php +++ b/phpgwapi/js/htmlarea/plugins/SpellChecker/lang/lang.php @@ -24,6 +24,7 @@ $GLOBALS['phpgw_info']['flags'] = Array( ); include('../../../../../../header.inc.php'); +header('Content-type: text/javascript; charset='.$GLOBALS['phpgw']->translation->charset()); $GLOBALS['phpgw']->translation->add_app('htmlarea-SpellChecker'); // I18N constants diff --git a/phpgwapi/js/htmlarea/plugins/SpellChecker/spell-check-ui.js b/phpgwapi/js/htmlarea/plugins/SpellChecker/spell-check-ui.js index 6bb2e68b40..52a79d05e4 100644 --- a/phpgwapi/js/htmlarea/plugins/SpellChecker/spell-check-ui.js +++ b/phpgwapi/js/htmlarea/plugins/SpellChecker/spell-check-ui.js @@ -126,7 +126,7 @@ function replaceAllClicked() { } */ if (ok) { - for (var i = 0; i < spans.length; ++i) { + for (var i in spans) { if (spans[i] != currentElement) { replaceWord(spans[i]); } @@ -156,7 +156,7 @@ function learnClicked() { function internationalizeWindow() { var types = ["div", "span", "button"]; - for (var i = 0; i < types.length; ++i) { + for (var i in types) { var tag = types[i]; var els = document.getElementsByTagName(tag); for (var j = els.length; --j >= 0;) { @@ -237,7 +237,7 @@ function wordClicked(scroll) { if (currentElement) { var a = allWords[currentElement.__msh_origWord]; currentElement.className = currentElement.className.replace(/\s*HA-spellcheck-current\s*/g, " "); - for (var i = 0; i < a.length; ++i) { + for (var i in a) { var el = a[i]; if (el != currentElement) { el.className = el.className.replace(/\s*HA-spellcheck-same\s*/g, " "); @@ -247,7 +247,7 @@ function wordClicked(scroll) { currentElement = this; this.className += " HA-spellcheck-current"; var a = allWords[currentElement.__msh_origWord]; - for (var i = 0; i < a.length; ++i) { + for (var i in a) { var el = a[i]; if (el != currentElement) { el.className += " HA-spellcheck-same"; diff --git a/phpgwapi/js/htmlarea/plugins/SpellChecker/spell-checker.js b/phpgwapi/js/htmlarea/plugins/SpellChecker/spell-checker.js index 7e7529b94c..7e274f7b37 100644 --- a/phpgwapi/js/htmlarea/plugins/SpellChecker/spell-checker.js +++ b/phpgwapi/js/htmlarea/plugins/SpellChecker/spell-checker.js @@ -18,7 +18,7 @@ function SpellChecker(editor) { // register the toolbar buttons provided by this plugin var toolbar = []; - for (var i = 0; i < bl.length; ++i) { + for (var i in bl) { var btn = bl[i]; if (!btn) { toolbar.push("separator"); @@ -33,7 +33,7 @@ function SpellChecker(editor) { } } - for (var i = 0; i < toolbar.length; ++i) { + for (var i in toolbar) { cfg.toolbar[0].push(toolbar[i]); } }; diff --git a/phpgwapi/js/htmlarea/plugins/TableOperations/lang/lang.php b/phpgwapi/js/htmlarea/plugins/TableOperations/lang/lang.php index d58ae8ab0e..56b370f3fe 100644 --- a/phpgwapi/js/htmlarea/plugins/TableOperations/lang/lang.php +++ b/phpgwapi/js/htmlarea/plugins/TableOperations/lang/lang.php @@ -24,6 +24,7 @@ $GLOBALS['phpgw_info']['flags'] = Array( ); include('../../../../../../header.inc.php'); +header('Content-type: text/javascript; charset='.$GLOBALS['phpgw']->translation->charset()); $GLOBALS['phpgw']->translation->add_app('htmlarea-TableOperations'); // I18N constants diff --git a/phpgwapi/js/htmlarea/plugins/TableOperations/lang/no.js b/phpgwapi/js/htmlarea/plugins/TableOperations/lang/no.js index 91fc5e5725..a29e9034eb 100644 --- a/phpgwapi/js/htmlarea/plugins/TableOperations/lang/no.js +++ b/phpgwapi/js/htmlarea/plugins/TableOperations/lang/no.js @@ -1,7 +1,7 @@ // I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 -// Author: Mihai Bazon, +// Author: Mihai Bazon, // translated into Norwegia: ses@online.no 11.11.03 // FOR TRANSLATORS: diff --git a/phpgwapi/js/htmlarea/plugins/TableOperations/table-operations.js b/phpgwapi/js/htmlarea/plugins/TableOperations/table-operations.js index 1b5b0566ec..a376f3a488 100644 --- a/phpgwapi/js/htmlarea/plugins/TableOperations/table-operations.js +++ b/phpgwapi/js/htmlarea/plugins/TableOperations/table-operations.js @@ -24,7 +24,7 @@ function TableOperations(editor) { // register the toolbar buttons provided by this plugin var toolbar = ["linebreak"]; - for (var i = 0; i < bl.length; ++i) { + for (var i in bl) { var btn = bl[i]; if (!btn) { toolbar.push("separator"); @@ -65,7 +65,7 @@ TableOperations.prototype.getClosest = function(tagName) { var ancestors = editor.getAllAncestors(); var ret = null; tagName = ("" + tagName).toLowerCase(); - for (var i = 0; i < ancestors.length; ++i) { + for (var i in ancestors) { var el = ancestors[i]; if (el.tagName.toLowerCase() == tagName) { ret = el; @@ -502,17 +502,11 @@ TableOperations.prototype.buttonPress = function(editor, button_id) { var rows = td.parentNode.parentNode.rows; var index = td.cellIndex; for (var i = rows.length; --i >= 0;) { - /* - var tr = rows; - var otd = tr.insertCell(index + (/after/.test(button_id) ? 1 : 0)); - otd.innerHTML = mozbr; - */ var tr = rows[i]; var ref = tr.cells[index + (/after/.test(button_id) ? 1 : 0)]; var otd = editor._doc.createElement("td"); otd.innerHTML = mozbr; tr.insertBefore(otd, ref); - } editor.focusEditor(); break; @@ -874,7 +868,7 @@ TableOperations.createStyleLayoutFieldset = function(doc, editor, el) { td.appendChild(select); select.name = "f_st_float"; options = ["None", "Left", "Right"]; - for (var i = 0; i < options.length; ++i) { + for (i in options) { var Val = options[i]; var val = options[i].toLowerCase(); option = doc.createElement("option"); @@ -929,7 +923,7 @@ TableOperations.createStyleLayoutFieldset = function(doc, editor, el) { input.size = "1"; input.style.fontFamily = "monospace"; td.appendChild(input); - for (var i = 0; i < options.length; ++i) { + for (i in options) { var Val = options[i]; var val = Val.toLowerCase(); option = doc.createElement("option"); @@ -984,7 +978,7 @@ TableOperations.createStyleLayoutFieldset = function(doc, editor, el) { select.style.marginLeft = "0.5em"; td.appendChild(select); options = ["Top", "Middle", "Bottom", "Baseline"]; - for (var i = 0; i < options.length; ++i) { + for (i in options) { var Val = options[i]; var val = Val.toLowerCase(); option = doc.createElement("option"); @@ -1076,7 +1070,7 @@ TableOperations.createStyleFieldset = function(doc, editor, el) { // That is, "top right bottom left" -- we only consider the first // value. (currentBorderStyle.match(/([^\s]*)\s/)) && (currentBorderStyle = RegExp.$1); - for (var i in options) { + for (i in options) { var val = options[i]; option = doc.createElement("option"); option.value = val; @@ -1086,7 +1080,7 @@ TableOperations.createStyleFieldset = function(doc, editor, el) { } select.style.marginRight = "0.5em"; function setBorderFieldsStatus(value) { - for (var i = 0; i < borderFields.length; ++i) { + for (i in borderFields) { var el = borderFields[i]; el.style.visibility = value ? "hidden" : "visible"; if (!value && (el.tagName.toLowerCase() == "input")) { diff --git a/phpgwapi/js/htmlarea/plugins/UploadImage/lang/lang.php b/phpgwapi/js/htmlarea/plugins/UploadImage/lang/lang.php index 6984e872d1..0b2445723c 100644 --- a/phpgwapi/js/htmlarea/plugins/UploadImage/lang/lang.php +++ b/phpgwapi/js/htmlarea/plugins/UploadImage/lang/lang.php @@ -24,6 +24,7 @@ $GLOBALS['phpgw_info']['flags'] = Array( ); include('../../../../../../header.inc.php'); +header('Content-type: text/javascript; charset='.$GLOBALS['phpgw']->translation->charset()); $GLOBALS['phpgw']->translation->add_app('htmlarea-SpellChecker'); // I18N for the FullPage plugin diff --git a/phpgwapi/js/htmlarea/plugins/UploadImage/popups/ImageManager/config.inc.php b/phpgwapi/js/htmlarea/plugins/UploadImage/popups/ImageManager/config.inc.php index 0045788e5e..a2eb83de33 100755 --- a/phpgwapi/js/htmlarea/plugins/UploadImage/popups/ImageManager/config.inc.php +++ b/phpgwapi/js/htmlarea/plugins/UploadImage/popups/ImageManager/config.inc.php @@ -1,87 +1,111 @@ * - * Modified for eGW by and (c) by Pim Snel * - * -------------------------------------------- * - * This program is free software; you can redistribute it and/or modify it * - * under the terms of the GNU General Public License as published by the * - * Free Software Foundation; version 2 of the License. * - \**************************************************************************/ - - /* $id$ */ - - // FIXME: remove imageMagick shit, we only use gdlib - // FIXME: autodetect safe_mode - // FIXME set current app to the calling app - // FIXME include header nicer - - $phpgw_flags = Array( - 'currentapp' => 'jinn', - 'noheader' => True, - 'nonavbar' => True, - 'noappheader' => True, - 'noappfooter' => True, - 'nofooter' => True - ); - - $GLOBALS['phpgw_info']['flags'] = $phpgw_flags; - - if(@include('../../../../../../header.inc.php')) - { - // I know this is very ugly - } - else - { - @include('../../../../../../../header.inc.php'); - } - - define('IMAGE_CLASS', 'GD'); - - //In safe mode, directory creation is not permitted. - $SAFE_MODE = false; - - $sessdata = $GLOBALS['phpgw']->session->appsession('UploadImage','phpgwapi'); - - $BASE_DIR = $sessdata[UploadImageBaseDir]; - $BASE_URL = $sessdata[UploadImageBaseURL]; - $MAX_HEIGHT = $sessdata[UploadImageMaxHeight]; - $MAX_WIDTH = $sessdata[UploadImageMaxWidth]; - - if(!$MAX_HEIGHT) $MAX_HEIGHT = 10000; - if(!$MAX_WIDTH) $MAX_WIDTH = 10000; -// _debug_array($sessdata); - //die(); - - - //After defining which library to use, if it is NetPBM or IM, you need to - //specify where the binary for the selected library are. And of course - //your server and PHP must be able to execute them (i.e. safe mode is OFF). - //If you have safe mode ON, or don't have the binaries, your choice is - //GD only. GD does not require the following definition. - //define('IMAGE_TRANSFORM_LIB_PATH', '/usr/bin/netpbm/'); - //define('IMAGE_TRANSFORM_LIB_PATH', '"D:\\Program Files\\ImageMagick\\'); - - $BASE_ROOT = ''; - $IMG_ROOT = $BASE_ROOT; - - if(strrpos($BASE_DIR, '/')!= strlen($BASE_DIR)-1) - $BASE_DIR .= '/'; - - if(strrpos($BASE_URL, '/')!= strlen($BASE_URL)-1) - $BASE_URL .= '/'; - - //Built in function of dirname is faulty - //It assumes that the directory nane can not contain a . (period) - function dir_name($dir) - { - $lastSlash = intval(strrpos($dir, '/')); - if($lastSlash == strlen($dir)-1){ - return substr($dir, 0, $lastSlash); - } - else - return dirname($dir); - } + /**************************************************************************\ + * eGroupWare - UploadImage-plugin for htmlArea * + * http://www.eGroupWare.org * + * Written and (c) by Xiang Wei ZHUO * + * Modified for eGW by and (c) by Pim Snel * + * -------------------------------------------- * + * This program is free software; you can redistribute it and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; version 2 of the License. * + \**************************************************************************/ + + /* $id$ */ + + // FIXME: remove imageMagick shit, we only use gdlib + // FIXME: autodetect safe_mode + // FIXME include header nicer + + $phpgw_flags = Array( + 'currentapp' => 'home', + 'noheader' => True, + 'nonavbar' => True, + 'noappheader' => True, + 'noappfooter' => True, + 'nofooter' => True + ); + + $GLOBALS['phpgw_info']['flags'] = $phpgw_flags; + + if(@include('../../../../../../header.inc.php')) + { + // I know this is very ugly + } + else + { + @include('../../../../../../../header.inc.php'); + } + + $sessdata = $GLOBALS['phpgw']->session->appsession('UploadImage','phpgwapi'); + $phpgw_flags['currentapp'] = $sessdata['app'] ? $sessdata['app'] : 'jinn'; + + define('IMAGE_CLASS', 'GD'); + + //In safe mode, directory creation is not permitted. + $SAFE_MODE = false; + + switch ($phpgw_flags['currentapp']) + { + case 'jinn' : + $BASE_DIR = $sessdata[UploadImageBaseDir]; + $BASE_URL = $sessdata[UploadImageBaseURL]; + $MAX_HEIGHT = $sessdata[UploadImageMaxHeight]; + $MAX_WIDTH = $sessdata[UploadImageMaxWidth]; + // _debug_array($sessdata); + //die(); + break; + case 'sitemgr' : + if(is_writeable($sessdata['upload_dir'])) + { + $BASE_DIR = $sessdata['upload_dir']; + $BASE_URL = str_replace($GLOBALS['_SERVER']['DOCUMENT_ROOT'],'',$sessdata['upload_dir']); + } + else + { + echo '

        Error

        '; + echo '

        Upload directory does not exist, or is not writeable by webserver

        '; + echo $GLOBALS['egw_info']['user']['apps']['admin'] ? + 'Choose an other directory
        + or make "'. $sessdata['upload_dir']. '" writeable by webserver' : + 'Notify your Administrator to correct this Situation'; + die(); + } + default : + break; + } + + if(!$MAX_HEIGHT) $MAX_HEIGHT = 10000; + if(!$MAX_WIDTH) $MAX_WIDTH = 10000; + + + //After defining which library to use, if it is NetPBM or IM, you need to + //specify where the binary for the selected library are. And of course + //your server and PHP must be able to execute them (i.e. safe mode is OFF). + //If you have safe mode ON, or don't have the binaries, your choice is + //GD only. GD does not require the following definition. + //define('IMAGE_TRANSFORM_LIB_PATH', '/usr/bin/netpbm/'); + //define('IMAGE_TRANSFORM_LIB_PATH', '"D:\\Program Files\\ImageMagick\\'); + + $BASE_ROOT = ''; + $IMG_ROOT = $BASE_ROOT; + + if(strrpos($BASE_DIR, '/')!= strlen($BASE_DIR)-1) + $BASE_DIR .= '/'; + + if(strrpos($BASE_URL, '/')!= strlen($BASE_URL)-1) + $BASE_URL .= '/'; + + //Built in function of dirname is faulty + //It assumes that the directory nane can not contain a . (period) + function dir_name($dir) + { + $lastSlash = intval(strrpos($dir, '/')); + if($lastSlash == strlen($dir)-1){ + return substr($dir, 0, $lastSlash); + } + else + return dirname($dir); + } ?> diff --git a/phpgwapi/js/htmlarea/popupdiv.js b/phpgwapi/js/htmlarea/popupdiv.js index c2f8d3be94..084ff8e10c 100644 --- a/phpgwapi/js/htmlarea/popupdiv.js +++ b/phpgwapi/js/htmlarea/popupdiv.js @@ -191,7 +191,7 @@ PopupDiv.prototype.getForm = function() { PopupDiv.prototype.callHandler = function() { var tags = ["input", "textarea", "select"]; var params = new Object(); - for (var ti = tags.length; --ti >= 0;) { + for (var ti in tags) { var tag = tags[ti]; var els = this.content.getElementsByTagName(tag); for (var j = 0; j < els.length; ++j) { diff --git a/phpgwapi/js/htmlarea/popups/fullscreen.html b/phpgwapi/js/htmlarea/popups/fullscreen.html index 6291d8e0a8..8a9f27fd18 100644 --- a/phpgwapi/js/htmlarea/popups/fullscreen.html +++ b/phpgwapi/js/htmlarea/popups/fullscreen.html @@ -3,9 +3,8 @@ Fullscreen HTMLArea - + + @@ -36,7 +33,7 @@ var editor = null; // to be initialized later [ function init() ] \* ---------------------------------------------------------------------- */ function _CloseOnEsc(ev) { - ev || (ev = window.event) || (ev = editor._iframe.contentWindow.event); + ev || (ev = window.event); if (ev.keyCode == 27) { // update_parent(); window.close(); @@ -62,7 +59,7 @@ function resize_editor() { // resize editor to fix window if (editor.config.statusBar) { newHeight -= editor._statusBar.offsetHeight; } - editor._textArea.style.height = editor._iframe.style.height = newHeight - (HTMLArea.is_gecko ? 8 : 0) + "px"; + editor._textArea.style.height = editor._iframe.style.height = newHeight + "px"; } /* ---------------------------------------------------------------------- *\ @@ -86,10 +83,7 @@ function init() { // register the plugins, if any for (var i in parent_object.plugins) { var plugin = parent_object.plugins[i]; - try { - eval(plugin.name); - editor.registerPlugin2(plugin.name, plugin.args); - } catch(e) {}; + editor.registerPlugin2(plugin.name, plugin.args); } // and restore the original toolbar config.toolbar = parent_object.config.toolbar; @@ -131,7 +125,7 @@ function update_parent() { - +
        diff --git a/phpgwapi/js/htmlarea/popups/insert_table.html b/phpgwapi/js/htmlarea/popups/insert_table.html index 05db221dfe..508dbf8e15 100644 --- a/phpgwapi/js/htmlarea/popups/insert_table.html +++ b/phpgwapi/js/htmlarea/popups/insert_table.html @@ -10,8 +10,6 @@ window.resizeTo(400, 100); function Init() { - i18n = window.opener.HTMLArea.I18N.dialogs; // load the HTMLArea plugin and lang file - __dlg_translate(i18n); __dlg_init(); document.getElementById("f_rows").focus(); }; @@ -29,13 +27,13 @@ function onOK() { return false; } } - var fields = ["f_rows", "f_cols", "f_width", "f_unit", "f_fixed", + var fields = ["f_rows", "f_cols", "f_width", "f_unit", "f_align", "f_border", "f_spacing", "f_padding"]; var param = new Object(); for (var i in fields) { var id = fields[i]; var el = document.getElementById(id); - param[id] = (el.type == "checkbox") ? el.checked : el.value; + param[id] = el.value; } __dlg_close(param); return false; @@ -90,6 +88,13 @@ form { padding: 0px; margin: 0px; } Rows: + + + + + + Cols: + Width: - - Cols: - - - - + @@ -117,7 +116,7 @@ form { padding: 0px; margin: 0px; }
        Alignment:
        - Target: + Target: