X-Git-Url: http://git.roojs.org/?a=blobdiff_plain;f=docs%2Fsrc%2FRoo_HtmlEditorCore.js.html;h=806a0ecf8f5acf877dd2d6918d7589f5e2af46a6;hb=1fabf2900a91b646b5406619aac5cf18e1550d53;hp=98ab969a146bb97363c8a493fdc25a0c53b0a295;hpb=35a7f05ed20bcb5f878e613edb7629e6c30e1ff7;p=roojs1 diff --git a/docs/src/Roo_HtmlEditorCore.js.html b/docs/src/Roo_HtmlEditorCore.js.html index 98ab969a14..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.. @@ -180,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>' + @@ -313,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 @@ -333,33 +352,36 @@ */ syncValue : function() { - Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)"); + //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.. - // not sure if this is really the place for this - // the blocks are synced occasionaly - since we currently dont add listeners on the blocks - // this has to update attributes that get duped.. like alt and caption.. - - - //Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) { - // Roo.htmleditor.Block.factory(e); - //},this); + var sel = this.win.getSelection(); var div = document.createElement('div'); div.innerHTML = bd.innerHTML; - // remove content editable. (blocks) + 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); + } - new Roo.htmleditor.FilterAttributes({node : div, attrib_black: [ 'contenteditable' ] }); + if (this.enableBlocks) { + new Roo.htmleditor.FilterBlock({ node : div }); + } //?? tidy? - var html = div.innerHTML; + 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; @@ -410,7 +432,7 @@ */ pushValue : function() { - Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)"); + //Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)"); if(this.initialized){ var v = this.el.dom.value.trim(); @@ -422,12 +444,14 @@ 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.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) { - - Roo.htmleditor.Block.factory(e); + Roo.htmleditor.Block.initAll(this.doc.body); + this.updateLanguage(); - },this); var lc = this.doc.body.lastChild; if (lc && lc.nodeType == 1 && lc.getAttribute("contenteditable") == "false") { // add an extra line at the end. @@ -496,9 +520,11 @@ //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, @@ -514,6 +540,7 @@ 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); } @@ -528,6 +555,7 @@ this.owner.fireEvent('initialize', this); this.pushValue(); }, + // this is to prevent a href clicks resulting in a redirect? onPasteEvent : function(e,v) { @@ -562,29 +590,58 @@ 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.. - 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 }); + }); + } + this.insertAtCursor(d.innerHTML.replace(/&nbsp;/g,' ')); + if (this.enableBlocks) { + Roo.htmleditor.Block.initAll(this.doc.body); + } - this.insertAtCursor(d.innerHTML); e.preventDefault(); return false; @@ -658,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.. @@ -706,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); @@ -804,9 +929,11 @@ } if(cmd){ - this.win.focus(); - this.execCmd(cmd); - this.deferFocus(); + + this.relayCmd(cmd); + //this.win.focus(); + //this.execCmd(cmd); + //this.deferFocus(); e.preventDefault(); } @@ -816,6 +943,8 @@ // private fixKeys : function(){ // load time branching for fastest keydown performance + + if(Roo.isIE){ return function(e){ var k = e.getKey(), r; @@ -829,20 +958,22 @@ } 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 + */ + //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste // this.cleanUpPaste.defer(100, this); // return; //} @@ -858,6 +989,7 @@ this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;'); this.deferFocus(); } + //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste // this.cleanUpPaste.defer(100, this); // return; @@ -874,6 +1006,8 @@ this.deferFocus(); return; } + this.mozKeyPress(e); + //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste // this.cleanUpPaste.defer(100, this); // return; @@ -907,13 +1041,13 @@ 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) + selectNode : function(node, collapse) { var nodeRange = node.ownerDocument.createRange(); try { @@ -921,7 +1055,10 @@ } catch (e) { nodeRange.selectNodeContents(node); } - //nodeRange.collapse(true); + if (collapse === true) { + nodeRange.collapse(true); + } + // var s = this.win.getSelection(); s.removeAllRanges(); s.addRange(nodeRange); @@ -935,7 +1072,6 @@ - var range = this.createRange(this.getSelection()).cloneRange(); if (Roo.isIE) { @@ -998,6 +1134,8 @@ return nodes[0]; }, + + createRange: function(sel) { // this has strange effects when using with @@ -1309,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;