X-Git-Url: http://git.roojs.org/?a=blobdiff_plain;f=Roo%2FHtmlEditorCore.js;h=9eb3ab65ac68d5c3b31e3796b838f913b5f1476a;hb=61bc45258e16a779856dd2ad0862630b489e4583;hp=f91060e4558e9d46bcdea16d112b09be70b6576e;hpb=9ab6e1f94888548351e06f1e9ea70483defa538b;p=roojs1 diff --git a/Roo/HtmlEditorCore.js b/Roo/HtmlEditorCore.js index f91060e455..9eb3ab65ac 100644 --- a/Roo/HtmlEditorCore.js +++ b/Roo/HtmlEditorCore.js @@ -133,7 +133,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { black: false, white: false, - + bodyCls : '', /** * Protected method that will not generally be called directly. It @@ -143,7 +143,6 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { getDocMarkup : function(){ // body styles.. var st = ''; - Roo.log(this.stylesheets); // inherit styels from page...?? if (this.stylesheets === false) { @@ -161,23 +160,27 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { st = ''; - } else { - Roo.each(this.stylesheets, function(s) { - st += '' - }); - + } else { + st = ''; } st += ''; + var cls = 'roo-htmleditor-body'; + + if(this.bodyCls.length){ + cls += ' ' + this.bodyCls; + } return '' + st + //' + - ' '; + ' '; }, // private @@ -245,8 +248,6 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { }; Roo.TaskMgr.start(task); - - }, // private @@ -334,17 +335,32 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { html = this.cleanHtml(html); // fix up the special chars.. normaly like back quotes in word... // however we do not want to do this with chinese.. - html = html.replace(/([\x80-\uffff])/g, function (a, b) { - var cc = b.charCodeAt(); - if ( + html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) { + + var cc = match.charCodeAt(); + + // Get the character value, handling surrogate pairs + if (match.length == 2) { + // It's a surrogate pair, calculate the Unicode code point + var high = match.charCodeAt(0) - 0xD800; + var low = match.charCodeAt(1) - 0xDC00; + cc = (high * 0x400) + low + 0x10000; + } else if ( (cc >= 0x4E00 && cc < 0xA000 ) || (cc >= 0x3400 && cc < 0x4E00 ) || (cc >= 0xf900 && cc < 0xfb00 ) ) { - return b; - } - return "&#"+cc+";" + return match; + } + + // No, use a numeric entity. Here we brazenly (and possibly mistakenly) + return "&#" + cc + ";"; + + }); + + + if(this.owner.fireEvent('beforesync', this, html) !== false){ this.el.dom.value = html; this.owner.fireEvent('sync', this, html); @@ -518,7 +534,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { this.execCmd('FontSize', v ); }, - onEditorEvent : function(e){ + onEditorEvent : function(e) + { this.owner.fireEvent('editorevent', this, e); // this.updateToolbar(); this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff @@ -527,7 +544,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { insertTag : function(tg) { // could be a bit smarter... -> wrap the current selected tRoo.. - if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') { + if (tg.toLowerCase() == 'span' || + tg.toLowerCase() == 'code' || + tg.toLowerCase() == 'sup' || + tg.toLowerCase() == 'sub' + ) { range = this.createRange(this.getSelection()); var wrappingNode = this.doc.createElement(tg.toLowerCase()); @@ -592,8 +613,6 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { insertAtCursor : function(text) { - - if(!this.activated){ return; } @@ -944,13 +963,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { var nodeIsBefore = ss == 1; var nodeIsAfter = ee == -1; - if (nodeIsBefore && nodeIsAfter) + if (nodeIsBefore && nodeIsAfter) { return 0; // outer - if (!nodeIsBefore && nodeIsAfter) + } + if (!nodeIsBefore && nodeIsAfter) { return 1; //right trailed. + } - if (nodeIsBefore && !nodeIsAfter) + if (nodeIsBefore && !nodeIsAfter) { return 2; // left trailed. + } // fully contined. return 3; }, @@ -1022,6 +1044,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1; + // spans with no attributes - just remove them.. + if ((!node.attributes || !node.attributes.length) && lcname == 'span') { + remove_keep_children = true; + } + // remove as rendering on yahoo mailer is borked with this. // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer.. @@ -1042,6 +1069,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { } if (!node.attributes || !node.attributes.length) { + + + + this.cleanUpChildren(node); return; } @@ -1052,7 +1083,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { if (v.match(/^\./) || v.match(/^\//)) { return; } - if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) { + if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) { return; } if (v.match(/^#/)) { @@ -1138,11 +1169,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { if (a.name == 'class') { if (a.value.match(/^Mso/)) { - node.className = ''; + node.removeAttribute('class'); } - if (a.value.match(/body/)) { - node.className = ''; + if (a.value.match(/^body$/)) { + node.removeAttribute('class'); } continue; } @@ -1157,27 +1188,35 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { }, + /** * Clean up MS wordisms... */ cleanWord : function(node) { - var _t = this; - var cleanWordChildren = function() - { - if (!node.childNodes.length) { - return; - } - for (var i = node.childNodes.length-1; i > -1 ; i--) { - _t.cleanWord(node.childNodes[i]); - } - } - - if (!node) { this.cleanWord(this.doc.body); return; } + + if( + node.nodeName == 'SPAN' && + !node.hasAttributes() && + node.childNodes.length == 1 && + node.firstChild.nodeName == "#text" + ) { + var textNode = node.firstChild; + node.removeChild(textNode); + if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters.. + node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node); + } + node.parentNode.insertBefore(textNode, node); + if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters.. + node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node); + } + node.parentNode.removeChild(node); + } + if (node.nodeName == "#text") { // clean up silly Windows -- stuff? return; @@ -1192,16 +1231,20 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { node.parentNode.removeChild(node); return; } - + //Roo.log(node.tagName); // remove - but keep children.. - if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) { + if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) { + //Roo.log('-- removed'); while (node.childNodes.length) { var cn = node.childNodes[0]; node.removeChild(cn); node.parentNode.insertBefore(cn, node); + // move node to parent - and clean it.. + this.cleanWord(cn); } node.parentNode.removeChild(node); - cleanWordChildren(); + /// no need to iterate chidlren = it's got none.. + //this.iterateChildren(node, this.cleanWord); return; } // clean styles @@ -1245,11 +1288,87 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { node.removeAttribute('style'); } } + this.iterateChildren(node, this.cleanWord); + + + + }, + /** + * iterateChildren of a Node, calling fn each time, using this as the scole.. + * @param {DomNode} node node to iterate children of. + * @param {Function} fn method of this class to call on each item. + */ + iterateChildren : function(node, fn) + { + if (!node.childNodes.length) { + return; + } + for (var i = node.childNodes.length-1; i > -1 ; i--) { + fn.call(this, node.childNodes[i]) + } + }, + + + /** + * cleanTableWidths. + * + * Quite often pasting from word etc.. results in tables with column and widths. + * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them.. + * + */ + cleanTableWidths : function(node) + { + + + if (!node) { + this.cleanTableWidths(this.doc.body); + return; + } + + // ignore list... + if (node.nodeName == "#text" || node.nodeName == "#comment") { + return; + } + Roo.log(node.tagName); + if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) { + this.iterateChildren(node, this.cleanTableWidths); + return; + } + if (node.hasAttribute('width')) { + node.removeAttribute('width'); + } + + + if (node.hasAttribute("style")) { + // pretty basic... + + var styles = node.getAttribute("style").split(";"); + var nstyle = []; + Roo.each(styles, function(s) { + if (!s.match(/:/)) { + return; + } + var kv = s.split(":"); + if (kv[0].match(/^\s*(width|min-width)\s*$/)) { + return; + } + // what ever is left... we allow. + nstyle.push(s); + }); + node.setAttribute("style", nstyle.length ? nstyle.join(';') : ''); + if (!nstyle.length) { + node.removeAttribute('style'); + } + } - cleanWordChildren(); + this.iterateChildren(node, this.cleanTableWidths); }, + + + + domToHTML : function(currentElement, depth, nopadtext) { depth = depth || 0; @@ -1446,6 +1565,56 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { this.cblack.push(tag); }, this); + }, + + setStylesheets : function(stylesheets) + { + if(typeof(stylesheets) == 'string'){ + Roo.get(this.iframe.contentDocument.head).createChild({ + tag : 'link', + rel : 'stylesheet', + type : 'text/css', + href : stylesheets + }); + + return; + } + var _this = this; + + Roo.each(stylesheets, function(s) { + if(!s.length){ + return; + } + + Roo.get(_this.iframe.contentDocument.head).createChild({ + tag : 'link', + rel : 'stylesheet', + type : 'text/css', + href : s + }); + }); + + + }, + + removeStylesheets : function() + { + var _this = this; + + Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){ + s.remove(); + }); + }, + + setStyle : function(style) + { + Roo.get(this.iframe.contentDocument.head).createChild({ + tag : 'style', + type : 'text/css', + html : style + }); + + return; } // hide stuff that is not compatible