X-Git-Url: http://git.roojs.org/?a=blobdiff_plain;f=docs%2Fsrc%2FRoo_HtmlEditorCore.js.html;h=806a0ecf8f5acf877dd2d6918d7589f5e2af46a6;hb=1fabf2900a91b646b5406619aac5cf18e1550d53;hp=c9100c612a1eebcd52248341e6c70dcba42d068c;hpb=e968e7a74bed1c1be5ab9049fccb72272b141502;p=roojs1 diff --git a/docs/src/Roo_HtmlEditorCore.js.html b/docs/src/Roo_HtmlEditorCore.js.html index c9100c612a..806a0ecf8f 100644 --- a/docs/src/Roo_HtmlEditorCore.js.html +++ b/docs/src/Roo_HtmlEditorCore.js.html @@ -73,6 +73,7 @@ */ editorevent: true + }); // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements @@ -107,15 +108,30 @@ * @cfg {Number} width (in pixels) */ width: 500, + /** + * @cfg {boolean} autoClean - default true - loading and saving will remove quite a bit of formating, + * if you are doing an email editor, this probably needs disabling, it's designed + */ + autoClean: true, + /** + * @cfg {boolean} enableBlocks - default true - if the block editor (table and figure should be enabled) + */ + enableBlocks : true, /** * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets. * */ stylesheets: false, + /** + * @cfg {String} language default en - language of text (usefull for rtl languages) + * + */ + language: 'en', /** - * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this. + * @cfg {boolean} allowComments - default false - allow comments in HTML source + * - by default they are stripped - if you are editing email you may need this. */ allowComments: false, // id of frame.. @@ -139,6 +155,8 @@ bodyCls : '', + + undoManager : false, /** * Protected method that will not generally be called directly. It * is called when the editor initializes the iframe with HTML contents. Override this method if you @@ -178,13 +196,15 @@ 'IMG { cursor: pointer } ' + '</style>'; - var cls = 'roo-htmleditor-body'; + st += '<meta name="google" content="notranslate">' + + var cls = 'notranslate roo-htmleditor-body'; if(this.bodyCls.length){ cls += ' ' + this.bodyCls; } - return '<html><head>' + st + + return '<html class="notranslate" translate="no"><head>' + st + //<style type="text/css">' + //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' + //'</style>' + @@ -227,7 +247,7 @@ this.iframe = iframe.dom; - this.assignDocWin(); + this.assignDocWin(); this.doc.designMode = 'on'; @@ -243,6 +263,7 @@ if(this.doc.body || this.doc.readyState == 'complete'){ try { this.doc.designMode="on"; + } catch (e) { return; } @@ -290,10 +311,10 @@ if(this.sourceEditMode){ - Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these + Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']); //FIXME - what's the BS styles for these }else{ - Roo.get(this.iframe).removeClass(['x-hidden','hide']); + Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']); //this.iframe.className = ''; this.deferFocus(); } @@ -310,7 +331,8 @@ * @param {String} html The HTML to be cleaned * return {String} The cleaned HTML */ - cleanHtml : function(html){ + cleanHtml : function(html) + { html = String(html); if(html.length > 5){ if(Roo.isSafari){ // strip safari nonsense @@ -328,11 +350,38 @@ * Protected method that will not generally be called directly. Syncs the contents * of the editor iframe with the textarea. */ - syncValue : function(){ + syncValue : function() + { + //Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)"); if(this.initialized){ + + this.undoManager.addEvent(); + + var bd = (this.doc.body || this.doc.documentElement); - //this.cleanUpPaste(); -- this is done else where and causes havoc.. - var html = bd.innerHTML; + + + var sel = this.win.getSelection(); + + var div = document.createElement('div'); + div.innerHTML = bd.innerHTML; + var gtx = div.getElementsByClassName('gtx-trans-icon'); // google translate - really annoying and difficult to get rid of. + if (gtx.length > 0) { + var rm = gtx.item(0).parentNode; + rm.parentNode.removeChild(rm); + } + + + if (this.enableBlocks) { + new Roo.htmleditor.FilterBlock({ node : div }); + } + //?? tidy? + var tidy = new Roo.htmleditor.TidySerializer({ + inner: true + }); + var html = tidy.serialize(div) + + if(Roo.isSafari){ var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element! var m = bs ? bs.match(/text-align:(.*?);/i) : false; @@ -377,24 +426,39 @@ }, /** + * TEXTAREA -> EDITABLE * Protected method that will not generally be called directly. Pushes the value of the textarea * into the iframe editor. */ - pushValue : function(){ + pushValue : function() + { + //Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)"); if(this.initialized){ var v = this.el.dom.value.trim(); -// if(v.length < 1){ -// v = '&#160;'; -// } if(this.owner.fireEvent('beforepush', this, v) !== false){ var d = (this.doc.body || this.doc.documentElement); d.innerHTML = v; - this.cleanUpPaste(); + this.el.dom.value = d.innerHTML; this.owner.fireEvent('push', this, v); } + if (this.autoClean) { + new Roo.htmleditor.FilterParagraph({node : this.doc.body}); // paragraphs + new Roo.htmleditor.FilterSpan({node : this.doc.body}); // empty spans + } + + Roo.htmleditor.Block.initAll(this.doc.body); + this.updateLanguage(); + + var lc = this.doc.body.lastChild; + if (lc && lc.nodeType == 1 && lc.getAttribute("contenteditable") == "false") { + // add an extra line at the end. + this.doc.body.appendChild(this.doc.createElement('br')); + } + + } }, @@ -456,19 +520,27 @@ //var ss = this.el.getStyles( 'background-image', 'background-repeat'); //ss['background-attachment'] = 'fixed'; // w3c dbody.bgProperties = 'fixed'; // ie - //Roo.DomHelper.applyStyles(dbody, ss); + dbody.setAttribute("translate", "no"); + + //Roo.DomHelper.applyStyles(dbody, ss); Roo.EventManager.on(this.doc, { - //'mousedown': this.onEditorEvent, + 'mouseup': this.onEditorEvent, 'dblclick': this.onEditorEvent, 'click': this.onEditorEvent, 'keyup': this.onEditorEvent, + buffer:100, scope: this }); + Roo.EventManager.on(this.doc, { + 'paste': this.onPasteEvent, + scope : this + }); if(Roo.isGecko){ Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this); } + //??? needed??? if(Roo.isIE || Roo.isSafari || Roo.isOpera){ Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this); } @@ -480,11 +552,103 @@ - this.owner.fireEvent('initialize', this); this.pushValue(); }, + // this is to prevent a href clicks resulting in a redirect? + + onPasteEvent : function(e,v) + { + // I think we better assume paste is going to be a dirty load of rubish from word.. + + // even pasting into a 'email version' of this widget will have to clean up that mess. + var cd = (e.browserEvent.clipboardData || window.clipboardData); + + // check what type of paste - if it's an image, then handle it differently. + if (cd.files.length > 0) { + // pasting images? + var urlAPI = (window.createObjectURL && window) || + (window.URL && URL.revokeObjectURL && URL) || + (window.webkitURL && webkitURL); + + var url = urlAPI.createObjectURL( cd.files[0]); + this.insertAtCursor('<img src=" + url + ">'); + return false; + } + var html = cd.getData('text/html'); // clipboard event + var parser = new Roo.rtf.Parser(cd.getData('text/rtf')); + var images = parser.doc ? parser.doc.getElementsByType('pict') : []; + Roo.log(images); + //Roo.log(imgs); + // fixme.. + images = images.filter(function(g) { return !g.path.match(/^rtf\/(head|pgdsctbl|listtable)/); }) // ignore headers + .map(function(g) { return g.toDataURL(); }); + + + html = this.cleanWordChars(html); + + var d = (new DOMParser().parseFromString(html, 'text/html')).body; + + + var sn = this.getParentElement(); + // check if d contains a table, and prevent nesting?? + //Roo.log(d.getElementsByTagName('table')); + //Roo.log(sn); + //Roo.log(sn.closest('table')); + if (d.getElementsByTagName('table').length && sn && sn.closest('table')) { + e.preventDefault(); + this.insertAtCursor("You can not nest tables"); + //Roo.log("prevent?"); // fixme - + return false; + } + + if (images.length > 0) { + Roo.each(d.getElementsByTagName('img'), function(img, i) { + img.setAttribute('src', images[i]); + }); + } + if (this.autoClean) { + new Roo.htmleditor.FilterStyleToTag({ node : d }); + new Roo.htmleditor.FilterAttributes({ + node : d, + attrib_white : ['href', 'src', 'name', 'align'], + attrib_clean : ['href', 'src' ] + }); + new Roo.htmleditor.FilterBlack({ node : d, tag : this.black}); + // should be fonts.. + new Roo.htmleditor.FilterKeepChildren({node : d, tag : [ 'FONT' ]} ); + new Roo.htmleditor.FilterParagraph({ node : d }); + new Roo.htmleditor.FilterSpan({ node : d }); + new Roo.htmleditor.FilterLongBr({ node : d }); + } + if (this.enableBlocks) { + + Array.from(d.getElementsByTagName('img')).forEach(function(img) { + if (img.closest('figure')) { // assume!! that it's aready + return; + } + var fig = new Roo.htmleditor.BlockFigure({ + image_src : img.src + }); + fig.updateElement(img); // replace it.. + + }); + } + + + this.insertAtCursor(d.innerHTML.replace(/&nbsp;/g,' ')); + if (this.enableBlocks) { + Roo.htmleditor.Block.initAll(this.doc.body); + } + + + e.preventDefault(); + return false; + // default behaveiour should be our local cleanup paste? (optional?) + // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable.. + //this.owner.fireEvent('paste', e, v); + }, // private onDestroy : function(){ @@ -506,7 +670,7 @@ onFirstFocus : function(){ this.assignDocWin(); - + this.undoManager = new Roo.lib.UndoManager(100,(this.doc.body || this.doc.documentElement)); this.activated = true; @@ -551,11 +715,49 @@ onEditorEvent : function(e) { - this.owner.fireEvent('editorevent', this, e); + + + if (e && (e.ctrlKey || e.metaKey) && e.keyCode === 90) { + return; // we do not handle this.. (undo manager does..) + } + // in theory this detects if the last element is not a br, then we try and do that. + // its so clicking in space at bottom triggers adding a br and moving the cursor. + if (e && + e.target.nodeName == 'BODY' && + e.type == "mouseup" && + this.doc.body.lastChild + ) { + var lc = this.doc.body.lastChild; + // gtx-trans is google translate plugin adding crap. + while ((lc.nodeType == 3 && lc.nodeValue == '') || lc.id == 'gtx-trans') { + lc = lc.previousSibling; + } + if (lc.nodeType == 1 && lc.nodeName != 'BR') { + // if last element is <BR> - then dont do anything. + + var ns = this.doc.createElement('br'); + this.doc.body.appendChild(ns); + range = this.doc.createRange(); + range.setStartAfter(ns); + range.collapse(true); + var sel = this.win.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + } + } + + + + this.fireEditorEvent(e); // this.updateToolbar(); this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff }, + fireEditorEvent: function(e) + { + this.owner.fireEvent('editorevent', this, e); + }, + insertTag : function(tg) { // could be a bit smarter... -> wrap the current selected tRoo.. @@ -576,7 +778,7 @@ } this.execCmd("formatblock", tg); - + this.undoManager.addEvent(); }, insertText : function(txt) @@ -588,6 +790,7 @@ //alert(Sender.getAttribute('label')); range.insertNode(this.doc.createTextNode(txt)); + this.undoManager.addEvent(); } , @@ -598,7 +801,37 @@ * @param {String} cmd The Midas command * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null) */ - relayCmd : function(cmd, value){ + relayCmd : function(cmd, value) + { + + switch (cmd) { + case 'justifyleft': + case 'justifyright': + case 'justifycenter': + // if we are in a cell, then we will adjust the + var n = this.getParentElement(); + var td = n.closest('td'); + if (td) { + var bl = Roo.htmleditor.Block.factory(td); + bl.textAlign = cmd.replace('justify',''); + bl.updateElement(); + this.owner.fireEvent('editorevent', this); + return; + } + this.execCmd('styleWithCSS', true); // + break; + case 'bold': + case 'italic': + // if there is no selection, then we insert, and set the curson inside it.. + this.execCmd('styleWithCSS', false); + break; + + + default: + break; + } + + this.win.focus(); this.execCmd(cmd, value); this.owner.fireEvent('editorevent', this); @@ -631,20 +864,7 @@ if(!this.activated){ return; } - /* - if(Roo.isIE){ - this.win.focus(); - var r = this.doc.selection.createRange(); - if(r){ - r.collapse(true); - r.pasteHTML(text); - this.syncValue(); - this.deferFocus(); - - } - return; - } - */ + if(Roo.isGecko || Roo.isOpera || Roo.isSafari){ this.win.focus(); @@ -654,19 +874,31 @@ var win = this.win; if (win.getSelection && win.getSelection().getRangeAt) { + + // delete the existing? + + this.createRange(this.getSelection()).deleteContents(); range = win.getSelection().getRangeAt(0); node = typeof(text) == 'string' ? range.createContextualFragment(text) : text; range.insertNode(node); + range = range.cloneRange(); + range.collapse(false); + + win.getSelection().removeAllRanges(); + win.getSelection().addRange(range); + + + } else if (win.document.selection && win.document.selection.createRange) { // no firefox support var txt = typeof(text) == 'string' ? text : text.outerHTML; win.document.selection.createRange().pasteHTML(txt); + } else { // no firefox support var txt = typeof(text) == 'string' ? text : text.outerHTML; this.execCmd('InsertHTML', txt); } - this.syncValue(); this.deferFocus(); @@ -691,15 +923,17 @@ cmd = 'underline'; break; - case 'v': - this.cleanUpPaste.defer(100, this); - return; + //case 'v': + // this.cleanUpPaste.defer(100, this); + // return; - } + } if(cmd){ - this.win.focus(); - this.execCmd(cmd); - this.deferFocus(); + + this.relayCmd(cmd); + //this.win.focus(); + //this.execCmd(cmd); + //this.deferFocus(); e.preventDefault(); } @@ -709,6 +943,8 @@ // private fixKeys : function(){ // load time branching for fastest keydown performance + + if(Roo.isIE){ return function(e){ var k = e.getKey(), r; @@ -722,26 +958,28 @@ } return; } - - if(k == e.ENTER){ - r = this.doc.selection.createRange(); - if(r){ - var target = r.parentElement(); - if(!target || target.tagName.toLowerCase() != 'li'){ - e.stopEvent(); - r.pasteHTML('<br />'); - r.collapse(false); - r.select(); + /// this is handled by Roo.htmleditor.KeyEnter + /* + if(k == e.ENTER){ + r = this.doc.selection.createRange(); + if(r){ + var target = r.parentElement(); + if(!target || target.tagName.toLowerCase() != 'li'){ + e.stopEvent(); + r.pasteHTML('<br/>'); + r.collapse(false); + r.select(); } } } - if (String.fromCharCode(k).toLowerCase() == 'v') { // paste - this.cleanUpPaste.defer(100, this); - return; - } + */ + //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste + // this.cleanUpPaste.defer(100, this); + // return; + //} - }; + }; }else if(Roo.isOpera){ return function(e){ var k = e.getKey(); @@ -751,12 +989,13 @@ this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;'); this.deferFocus(); } - if (String.fromCharCode(k).toLowerCase() == 'v') { // paste - this.cleanUpPaste.defer(100, this); - return; - } - }; + //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste + // this.cleanUpPaste.defer(100, this); + // return; + //} + + }; }else if(Roo.isSafari){ return function(e){ var k = e.getKey(); @@ -767,12 +1006,14 @@ this.deferFocus(); return; } - if (String.fromCharCode(k).toLowerCase() == 'v') { // paste - this.cleanUpPaste.defer(100, this); - return; - } + this.mozKeyPress(e); + + //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste + // this.cleanUpPaste.defer(100, this); + // return; + // } - }; + }; } }(), @@ -800,7 +1041,27 @@ getSelection : function() { this.assignDocWin(); - return Roo.isIE ? this.doc.selection : this.win.getSelection(); + return Roo.lib.Selection.wrap(Roo.isIE ? this.doc.selection : this.win.getSelection(), this.doc); + }, + /** + * Select a dom node + * @param {DomElement} node the node to select + */ + selectNode : function(node, collapse) + { + var nodeRange = node.ownerDocument.createRange(); + try { + nodeRange.selectNode(node); + } catch (e) { + nodeRange.selectNodeContents(node); + } + if (collapse === true) { + nodeRange.collapse(true); + } + // + var s = this.win.getSelection(); + s.removeAllRanges(); + s.addRange(nodeRange); }, getSelectedNode: function() @@ -811,7 +1072,6 @@ - var range = this.createRange(this.getSelection()).cloneRange(); if (Roo.isIE) { @@ -874,6 +1134,8 @@ return nodes[0]; }, + + createRange: function(sel) { // this has strange effects when using with @@ -992,25 +1254,20 @@ return 3; }, - // private? - in a new class? - cleanUpPaste : function() - { - // cleans up the whole document.. - Roo.log('cleanuppaste'); - - this.cleanUpChild(this.doc.body); - var clean = this.cleanWordChars(this.doc.body.innerHTML); - if (clean != this.doc.body.innerHTML) { - this.doc.body.innerHTML = clean; - } - - }, - cleanWordChars : function(input) {// change the chars to hex code - var he = Roo.HtmlEditorCore; + var swapCodes = [ + [ 8211, "&#8211;" ], + [ 8212, "&#8212;" ], + [ 8216, "'" ], + [ 8217, "'" ], + [ 8220, '"' ], + [ 8221, '"' ], + [ 8226, "*" ], + [ 8230, "..." ] + ]; var output = input; - Roo.each(he.swapCodes, function(sw) { + Roo.each(swapCodes, function(sw) { var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes output = output.replace(swapper, sw[1]); @@ -1064,113 +1321,6 @@ - /* ?? why ?? */ - domToHTML : function(currentElement, depth, nopadtext) { - - depth = depth || 0; - nopadtext = nopadtext || false; - - if (!currentElement) { - return this.domToHTML(this.doc.body); - } - - //Roo.log(currentElement); - var j; - var allText = false; - var nodeName = currentElement.nodeName; - var tagName = Roo.util.Format.htmlEncode(currentElement.tagName); - - if (nodeName == '#text') { - - return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim(); - } - - - var ret = ''; - if (nodeName != 'BODY') { - - var i = 0; - // Prints the node tagName, such as <A>, <IMG>, etc - if (tagName) { - var attr = []; - for(i = 0; i < currentElement.attributes.length;i++) { - // quoting? - var aname = currentElement.attributes.item(i).name; - if (!currentElement.attributes.item(i).value.length) { - continue; - } - attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' ); - } - - ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">"; - } - else { - - // eack - } - } else { - tagName = false; - } - if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) { - return ret; - } - if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code? - nopadtext = true; - } - - - // Traverse the tree - i = 0; - var currentElementChild = currentElement.childNodes.item(i); - var allText = true; - var innerHTML = ''; - lastnode = ''; - while (currentElementChild) { - // Formatting code (indent the tree so it looks nice on the screen) - var nopad = nopadtext; - if (lastnode == 'SPAN') { - nopad = true; - } - // text - if (currentElementChild.nodeName == '#text') { - var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue); - toadd = nopadtext ? toadd : toadd.trim(); - if (!nopad && toadd.length > 80) { - innerHTML += "\n" + (new Array( depth + 1 )).join( " " ); - } - innerHTML += toadd; - - i++; - currentElementChild = currentElement.childNodes.item(i); - lastNode = ''; - continue; - } - allText = false; - - innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " ); - - // Recursively traverse the tree structure of the child node - innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext); - lastnode = currentElementChild.nodeName; - i++; - currentElementChild=currentElement.childNodes.item(i); - } - - ret += innerHTML; - - if (!allText) { - // The remaining code is mostly for formatting the tree - ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " ); - } - - - if (tagName) { - ret+= "</"+tagName+">"; - } - return ret; - - }, - applyBlacklists : function() { var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : []; @@ -1297,6 +1447,16 @@ }, + + updateLanguage : function() + { + if (!this.iframe || !this.iframe.contentDocument) { + return; + } + Roo.get(this.iframe.contentDocument.body).attr("lang", this.language); + }, + + removeStylesheets : function() { var _this = this; @@ -1361,36 +1521,39 @@ }); Roo.HtmlEditorCore.white = [ - 'area', 'br', 'img', 'input', 'hr', 'wbr', + 'AREA', 'BR', 'IMG', 'INPUT', 'HR', 'WBR', - 'address', 'blockquote', 'center', 'dd', 'dir', 'div', - 'dl', 'dt', 'h1', 'h2', 'h3', 'h4', - 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee', - 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre', - 'table', 'ul', 'xmp', + 'ADDRESS', 'BLOCKQUOTE', 'CENTER', 'DD', 'DIR', 'DIV', + 'DL', 'DT', 'H1', 'H2', 'H3', 'H4', + 'H5', 'H6', 'HR', 'ISINDEX', 'LISTING', 'MARQUEE', + 'MENU', 'MULTICOL', 'OL', 'P', 'PLAINTEXT', 'PRE', + 'TABLE', 'UL', 'XMP', - 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr', + 'CAPTION', 'COL', 'COLGROUP', 'TBODY', 'TD', 'TFOOT', 'TH', + 'THEAD', 'TR', - 'dir', 'menu', 'ol', 'ul', 'dl', + 'DIR', 'MENU', 'OL', 'UL', 'DL', - 'embed', 'object' + 'EMBED', 'OBJECT' ]; Roo.HtmlEditorCore.black = [ // 'embed', 'object', // enable - backend responsiblity to clean thiese - 'applet', // - 'base', 'basefont', 'bgsound', 'blink', 'body', - 'frame', 'frameset', 'head', 'html', 'ilayer', - 'iframe', 'layer', 'link', 'meta', 'object', - 'script', 'style' ,'title', 'xml' // clean later.. + 'APPLET', // + 'BASE', 'BASEFONT', 'BGSOUND', 'BLINK', 'BODY', + 'FRAME', 'FRAMESET', 'HEAD', 'HTML', 'ILAYER', + 'IFRAME', 'LAYER', 'LINK', 'META', 'OBJECT', + 'SCRIPT', 'STYLE' ,'TITLE', 'XML', + //'FONT' // CLEAN LATER.. + 'COLGROUP', 'COL' // messy tables. + ]; -Roo.HtmlEditorCore.clean = [ - 'script', 'style', 'title', 'xml' +Roo.HtmlEditorCore.clean = [ // ?? needed??? + 'SCRIPT', 'STYLE', 'TITLE', 'XML' ]; Roo.HtmlEditorCore.tag_remove = [ - 'font' + 'FONT', 'TBODY' ]; // attributes.. @@ -1421,15 +1584,6 @@ ]; -Roo.HtmlEditorCore.swapCodes =[ - [ 8211, "&#8211;" ], - [ 8212, "&#8212;" ], - [ 8216, "'" ], - [ 8217, "'" ], - [ 8220, '"' ], - [ 8221, '"' ], - [ 8226, "*" ], - [ 8230, "..." ] -]; + \ No newline at end of file