sync
authorAlan <alan@roojs.com>
Fri, 7 Jan 2022 08:25:16 +0000 (16:25 +0800)
committerAlan <alan@roojs.com>
Fri, 7 Jan 2022 08:25:16 +0000 (16:25 +0800)
Roo/HtmlEditorCore.js
Roo/htmleditor/TidyWriter.js
roojs-all.js
roojs-debug.js
roojs-ui-debug.js
roojs-ui.js

index 96360d6..b997fb1 100644 (file)
@@ -196,7 +196,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             'IMG { cursor: pointer } ' +
         '</style>';
         
             'IMG { cursor: pointer } ' +
         '</style>';
         
-        st += '<meta name="google" content="notranslate">'
+        st += '<meta name="google" content="notranslate">';
         
         var cls = 'notranslate roo-htmleditor-body';
         
         
         var cls = 'notranslate roo-htmleditor-body';
         
@@ -379,7 +379,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             var tidy = new Roo.htmleditor.TidySerializer({
                 inner:  true
             });
             var tidy = new Roo.htmleditor.TidySerializer({
                 inner:  true
             });
-            var html  = tidy.serialize(div)
+            var html  = tidy.serialize(div);
             
             
             if(Roo.isSafari){
             
             
             if(Roo.isSafari){
index dfb1144..b461d9e 100644 (file)
@@ -198,9 +198,9 @@ Roo.htmleditor.TidyWriter.prototype = {
         }
         
         if (this.in_inline) {
         }
         
         if (this.in_inline) {
-            text = text.replace(/\s+/g,' ') // all white space inc line breaks to a slingle' '
+            text = text.replace(/\s+/g,' '); // all white space inc line breaks to a slingle' '
             if (text != ' ') {
             if (text != ' ') {
-                text = text.replace(/\s+/,' ')  // all white space to single white space
+                text = text.replace(/\s+/,' ');  // all white space to single white space
                 
                     
                 // if next tag is '<BR>', then we can trim right..
                 
                     
                 // if next tag is '<BR>', then we can trim right..
index 1291126..fd0de23 100644 (file)
@@ -1939,9 +1939,37 @@ return false;}if(!ps||ps.nodeType!=1){return false;}if(!ps||ps.tagName!='BR'){re
 // Roo/htmleditor/FilterBlock.js
 Roo.htmleditor.FilterBlock=function(A){Roo.apply(this,A);var qa=A.node.querySelectorAll;this.removeAttributes('data-block');this.removeAttributes('contenteditable');this.removeAttributes('id');};Roo.apply(Roo.htmleditor.FilterBlock.prototype,{node:true,removeAttributes:function(A){var ar=this.node.querySelectorAll('*['+A+']');
 for(var i=0;i<ar.length;i++){ar[i].removeAttribute(A);}}});
 // Roo/htmleditor/FilterBlock.js
 Roo.htmleditor.FilterBlock=function(A){Roo.apply(this,A);var qa=A.node.querySelectorAll;this.removeAttributes('data-block');this.removeAttributes('contenteditable');this.removeAttributes('id');};Roo.apply(Roo.htmleditor.FilterBlock.prototype,{node:true,removeAttributes:function(A){var ar=this.node.querySelectorAll('*['+A+']');
 for(var i=0;i<ar.length;i++){ar[i].removeAttribute(A);}}});
-// Roo/htmleditor/Tidy.js
-Roo.htmleditor.Tidy=function(A){Roo.apply(this,A);this.core.doc.body.innerHTML=this.tidy(this.core.doc.body,'');};Roo.htmleditor.Tidy.toString=function(A){return Roo.htmleditor.Tidy.prototype.tidy(A,'');};Roo.htmleditor.Tidy.prototype={tidy:function(A,B){}
-}
+// Roo/htmleditor/TidySerializer.js
+Roo.htmleditor.TidySerializer=function(A){Roo.apply(this,A);this.writer=new Roo.htmleditor.TidyWriter(A);};Roo.htmleditor.TidySerializer.prototype={inner:false,writer:false,serialize:function(A){var B=this.writer;var C=this;this.handlers={3:function(D){B.text(D.nodeValue,D);
+},8:function(D){B.comment(D.nodeValue);},7:function(D){B.pi(D.name,D.nodeValue);},10:function(D){B.doctype(D.nodeValue);},4:function(D){B.cdata(D.nodeValue);},11:function(D){D=D.firstChild;if(!D){return;}while(D){C.walk(D);D=D.nextSibling}}};B.reset();1!=A.nodeType||this.inner?this.handlers[11](A):this.walk(A);
+return B.getContent();},walk:function(A){var B,C,D,i,l,E,F=this.handlers[A.nodeType];if(F){F(A);return;}var G=A.nodeName;var H=A.childNodes.length<1;var I=this.writer;var J=A.attributes;I.start(A.nodeName,J,H,A);if(H){return;}A=A.firstChild;if(!A){I.end(G);
+return;}while(A){this.walk(A);A=A.nextSibling;}I.end(G);}};
+// Roo/htmleditor/TidyWriter.js
+Roo.htmleditor.TidyWriter=function(A){Roo.apply(this,A);this.html=[];this.state=[];this.encode=Roo.htmleditor.TidyEntities.getEncodeFunc(A.entity_encoding||'raw',A.entities);};Roo.htmleditor.TidyWriter.prototype={state:false,indent:'  ',indentstr:'',in_pre:false,in_inline:false,last_inline:false,encode:false,start:function(A,B,C,D){var i,l,E,F;
+var G=this.in_inline||Roo.htmleditor.TidyWriter.inline_elements.indexOf(A)>-1;var H=this.in_pre||Roo.htmleditor.TidyWriter.whitespace_elements.indexOf(A)>-1;var I=C?Roo.htmleditor.TidyWriter.shortend_elements.indexOf(A)>-1:false;var J=A=='BR'?false:G;if(!J&&!this.in_pre&&this.lastElementEndsWS()){i_inline=false;
+}var K=this.indentstr;if(!this.in_pre){if(G){if(A=='BR'){this.addLine();}else if(this.lastElementEndsWS()){this.addLine();}else{K='';}}else{this.addLine();}}else{K='';}this.html.push(K+'<',A.toLowerCase());if(B){for(i=0,l=B.length;i<l;i++){E=B[i];this.html.push(' ',E.name,'="',this.encode(E.value,true),'"');
+}}if(C){if(I){this.html[this.html.length]='/>';}else{this.html[this.html.length]='></'+A.toLowerCase()+'>';}var L=A=='BR'?false:this.in_inline;if(!L&&!this.in_pre){this.addLine();}return;}this.html[this.html.length]='>';this.pushState({indentstr:H?'':(this.indentstr+this.indent),in_pre:H,in_inline:G}
+);if(!G&&!H){this.addLine();}},lastElementEndsWS:function(){var A=this.html.length>0?this.html[this.html.length-1]:false;if(A===false){return true;}return A.match(/\s+$/);},end:function(A){var B;this.popState();var C='';var D=this.in_inline||Roo.htmleditor.TidyWriter.inline_elements.indexOf(A)>-1;
+if(!this.in_pre&&!D){this.addLine();C=this.indentstr;}this.html.push(C+'</',A.toLowerCase(),'>');this.last_inline=D;},text:function(A,B){if(A.length<1){return;}if(this.in_pre){this.html[this.html.length]=A;return;}if(this.in_inline){A=A.replace(/\s+/g,' ');
+if(A!=' '){A=A.replace(/\s+/,' ');if(B.nextSibling&&B.nextSibling.nodeType==1&&B.nextSibling.nodeName=='BR'){A=A.replace(/\s+$/g,'');}if(B.previousSibling&&B.previousSibling.nodeType==1&&B.previousSibling.nodeName=='BR'){A=this.indentstr+A.replace(/^\s+/g,'');
+}if(A.match(/\n/)){A=A.replace(/(?![^\n]{1,64}$)([^\n]{1,64})\s/g,'$1\n'+this.indentstr);A=A.replace(/\n\s+$/,'');}}this.html[this.html.length]=A;return;}var C=this.indentstr;A=A.replace(/\s+/g," ");if(B.previousSibling&&B.previousSibling.nodeType==1&&Roo.htmleditor.TidyWriter.inline_elements.indexOf(B.previousSibling.nodeName)>-1){C='';
+}else{this.addLine();A=A.replace(/^\s+/,'');}if(B.nextSibling&&B.nextSibling.nodeType==1&&Roo.htmleditor.TidyWriter.inline_elements.indexOf(B.nextSibling.nodeName)>-1){}else{A=A.replace(/\s+$/,'');}if(A.length<1){return;}if(!A.match(/\n/)){this.html.push(C+A);
+return;}A=this.indentstr+A.replace(/(?![^\n]{1,64}$)([^\n]{1,64})\s/g,'$1\n'+this.indentstr);A=A.replace(/\s+$/,'');this.html.push(A);},cdata:function(A){this.html.push('<![CDATA[',A,']]>');},comment:function(A){this.html.push('<!--',A,'-->');},pi:function(A,B){B?this.html.push('<?',A,' ',this.encode(B),'?>'):this.html.push('<?',A,'?>');
+this.indent!=''&&this.html.push('\n');},doctype:function(A){this.html.push('<!DOCTYPE',A,'>',this.indent!=''?'\n':'');},reset:function(){this.html.length=0;this.state=[];this.pushState({indentstr:'',in_pre:false,in_inline:false})},getContent:function(){return this.html.join('').replace(/\n$/,'');
+},pushState:function(A){this.state.push(A);Roo.apply(this,A);},popState:function(){if(this.state.length<1){return;}var A={in_pre:false,indentstr:''};this.state.pop();if(this.state.length>0){A=this.state[this.state.length-1];}Roo.apply(this,A);},addLine:function(){if(this.html.length<1){return;
+}var A=this.html[this.html.length-1];if(A.length>0&&'\n'!==A){this.html.push('\n');}}};Roo.htmleditor.TidyWriter.inline_elements=['SPAN','STRONG','B','EM','I','FONT','STRIKE','U','VAR','CITE','DFN','CODE','MARK','Q','SUP','SUB','SAMP'];Roo.htmleditor.TidyWriter.shortend_elements=['AREA','BASE','BASEFONT','BR','COL','FRAME','HR','IMG','INPUT','ISINDEX','LINK','','META','PARAM','EMBED','SOURCE','WBR','TRACK'];
+Roo.htmleditor.TidyWriter.whitespace_elements=['PRE','SCRIPT','NOSCRIPT','STYLE','TEXTAREA','VIDEO','AUDIO','IFRAME','OBJECT','CODE'];
+// Roo/htmleditor/TidyEntities.js
+Roo.htmleditor.TidyEntities={init:function(){this.namedEntities=this.buildEntitiesLookup(this.namedEntitiesData,32);},buildEntitiesLookup:function(A,B){var i,C,D,E={};if(!A){return {};}A=typeof(A)=='string'?A.split(','):A;B=B||10;for(i=0;i<A.length;i+=2){C=String.fromCharCode(parseInt(A[i],B));
+if(!this.baseEntities[C]){D='&'+A[i+1]+';';E[C]=D;E[D]=C;}}return E;},asciiMap:{128:'€',130:'‚',131:'ƒ',132:'„',133:'…',134:'†',135:'‡',136:'ˆ',137:'‰',138:'Š',139:'‹',140:'Œ',142:'Ž',145:'‘',146:'’',147:'“',148:'”',149:'•',150:'–',151:'—',152:'˜',153:'™',154:'š',155:'›',156:'œ',158:'ž',159:'Ÿ'}
+,baseEntities:{'"':'&quot;','\'':'&#39;','<':'&lt;','>':'&gt;','&':'&amp;','`':'&#96;'},reverseEntities:{'&lt;':'<','&gt;':'>','&amp;':'&','&quot;':'"','&apos;':'\''},attrsCharsRegExp:/[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,textCharsRegExp:/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,rawCharsRegExp:/[<>&\"\']/g,entityRegExp:/&#([a-z0-9]+);?|&([a-z0-9]+);/gi,namedEntities:false,namedEntitiesData:['50','nbsp','51','iexcl','52','cent','53','pound','54','curren','55','yen','56','brvbar','57','sect','58','uml','59','copy','5a','ordf','5b','laquo','5c','not','5d','shy','5e','reg','5f','macr','5g','deg','5h','plusmn','5i','sup2','5j','sup3','5k','acute','5l','micro','5m','para','5n','middot','5o','cedil','5p','sup1','5q','ordm','5r','raquo','5s','frac14','5t','frac12','5u','frac34','5v','iquest','60','Agrave','61','Aacute','62','Acirc','63','Atilde','64','Auml','65','Aring','66','AElig','67','Ccedil','68','Egrave','69','Eacute','6a','Ecirc','6b','Euml','6c','Igrave','6d','Iacute','6e','Icirc','6f','Iuml','6g','ETH','6h','Ntilde','6i','Ograve','6j','Oacute','6k','Ocirc','6l','Otilde','6m','Ouml','6n','times','6o','Oslash','6p','Ugrave','6q','Uacute','6r','Ucirc','6s','Uuml','6t','Yacute','6u','THORN','6v','szlig','70','agrave','71','aacute','72','acirc','73','atilde','74','auml','75','aring','76','aelig','77','ccedil','78','egrave','79','eacute','7a','ecirc','7b','euml','7c','igrave','7d','iacute','7e','icirc','7f','iuml','7g','eth','7h','ntilde','7i','ograve','7j','oacute','7k','ocirc','7l','otilde','7m','ouml','7n','divide','7o','oslash','7p','ugrave','7q','uacute','7r','ucirc','7s','uuml','7t','yacute','7u','thorn','7v','yuml','ci','fnof','sh','Alpha','si','Beta','sj','Gamma','sk','Delta','sl','Epsilon','sm','Zeta','sn','Eta','so','Theta','sp','Iota','sq','Kappa','sr','Lambda','ss','Mu','st','Nu','su','Xi','sv','Omicron','t0','Pi','t1','Rho','t3','Sigma','t4','Tau','t5','Upsilon','t6','Phi','t7','Chi','t8','Psi','t9','Omega','th','alpha','ti','beta','tj','gamma','tk','delta','tl','epsilon','tm','zeta','tn','eta','to','theta','tp','iota','tq','kappa','tr','lambda','ts','mu','tt','nu','tu','xi','tv','omicron','u0','pi','u1','rho','u2','sigmaf','u3','sigma','u4','tau','u5','upsilon','u6','phi','u7','chi','u8','psi','u9','omega','uh','thetasym','ui','upsih','um','piv','812','bull','816','hellip','81i','prime','81j','Prime','81u','oline','824','frasl','88o','weierp','88h','image','88s','real','892','trade','89l','alefsym','8cg','larr','8ch','uarr','8ci','rarr','8cj','darr','8ck','harr','8dl','crarr','8eg','lArr','8eh','uArr','8ei','rArr','8ej','dArr','8ek','hArr','8g0','forall','8g2','part','8g3','exist','8g5','empty','8g7','nabla','8g8','isin','8g9','notin','8gb','ni','8gf','prod','8gh','sum','8gi','minus','8gn','lowast','8gq','radic','8gt','prop','8gu','infin','8h0','ang','8h7','and','8h8','or','8h9','cap','8ha','cup','8hb','int','8hk','there4','8hs','sim','8i5','cong','8i8','asymp','8j0','ne','8j1','equiv','8j4','le','8j5','ge','8k2','sub','8k3','sup','8k4','nsub','8k6','sube','8k7','supe','8kl','oplus','8kn','otimes','8l5','perp','8m5','sdot','8o8','lceil','8o9','rceil','8oa','lfloor','8ob','rfloor','8p9','lang','8pa','rang','9ea','loz','9j0','spades','9j3','clubs','9j5','hearts','9j6','diams','ai','OElig','aj','oelig','b0','Scaron','b1','scaron','bo','Yuml','m6','circ','ms','tilde','802','ensp','803','emsp','809','thinsp','80c','zwnj','80d','zwj','80e','lrm','80f','rlm','80j','ndash','80k','mdash','80o','lsquo','80p','rsquo','80q','sbquo','80s','ldquo','80t','rdquo','80u','bdquo','810','dagger','811','Dagger','81g','permil','81p','lsaquo','81q','rsaquo','85c','euro'],encodeRaw:function(A,B){var t=this;
+return A.replace(B?this.attrsCharsRegExp:this.textCharsRegExp,function(C){return t.baseEntities[C]||C;});},encodeAllRaw:function(A){var t=this;return (''+A).replace(this.rawCharsRegExp,function(B){return t.baseEntities[B]||B;});},encodeNumeric:function(A,B){var t=this;
+return A.replace(B?this.attrsCharsRegExp:this.textCharsRegExp,function(C){if(C.length>1){return '&#'+(1024*(C.charCodeAt(0)-55296)+(C.charCodeAt(1)-56320)+65536)+';';}return t.baseEntities[C]||'&#'+C.charCodeAt(0)+';';});},encodeNamed:function(A,B,C){var t=this;
+C=C||this.namedEntities;return A.replace(B?this.attrsCharsRegExp:this.textCharsRegExp,function(D){return t.baseEntities[D]||C[D]||D;});},getEncodeFunc:function(A,B){B=this.buildEntitiesLookup(B)||this.namedEntities;var t=this;function encodeNamedAndNumeric(C,D){return C.replace(D?t.attrsCharsRegExp:t.textCharsRegExp,function(E){return t.baseEntities[E]||B[E]||'&#'+E.charCodeAt(0)+';'||E;
+});}function encodeCustomNamed(C,D){return t.encodeNamed(C,D,B);}A=this.makeMap(A.replace(/\+/g,','));if(A.named&&A.numeric){return this.encodeNamedAndNumeric;}if(A.named){if(B){return encodeCustomNamed;}return this.encodeNamed;}if(A.numeric){return this.encodeNumeric;
+}return this.encodeRaw;},decode:function(A){var t=this;return A.replace(this.entityRegExp,function(B,C){if(C){C='x'===C.charAt(0).toLowerCase()?parseInt(C.substr(1),16):parseInt(C,10);if(C>65535){C-=65536;return String.fromCharCode(55296+(C>>10),56320+(1023&C));
+}return t.asciiMap[C]||String.fromCharCode(C);}return t.reverseEntities[B]||t.namedEntities[B]||t.nativeDecode(B);});},nativeDecode:function(A){return A;},makeMap:function(A,B,C){var i;A=A||[];B=B||',';if(typeof A=="string"){A=A.split(B);}C=C||{};i=A.length;
+while(i--){C[A[i]]={};}return C;}};Roo.htmleditor.TidyEntities.init();
 // Roo/htmleditor/KeyEnter.js
 Roo.htmleditor.KeyEnter=function(A){Roo.apply(this,A);Roo.get(this.core.doc.body).on('keypress',this.keypress,this);};Roo.htmleditor.KeyEnter.prototype={core:false,keypress:function(e){if(e.charCode!=13&&e.charCode!=10){Roo.log([e.charCode,e]);return true;
 }e.preventDefault();var A=this.core.doc;var B=this.core.getSelection();var C=B.getRangeAt(0);var n=C.commonAncestorContainer;var pc=C.closest(['ol','ul']);var D=C.closest('li');if(!pc||e.ctrlKey){B.insertNode('br','after');this.core.undoManager.addEvent();
 // Roo/htmleditor/KeyEnter.js
 Roo.htmleditor.KeyEnter=function(A){Roo.apply(this,A);Roo.get(this.core.doc.body).on('keypress',this.keypress,this);};Roo.htmleditor.KeyEnter.prototype={core:false,keypress:function(e){if(e.charCode!=13&&e.charCode!=10){Roo.log([e.charCode,e]);return true;
 }e.preventDefault();var A=this.core.doc;var B=this.core.getSelection();var C=B.getRangeAt(0);var n=C.commonAncestorContainer;var pc=C.closest(['ol','ul']);var D=C.closest('li');if(!pc||e.ctrlKey){B.insertNode('br','after');this.core.undoManager.addEvent();
@@ -1962,7 +1990,7 @@ var b=B();b.image_src=this.getValue();b.updateElement();D();A.editorcore.onEdito
 var b=B();b.width=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['auto'],['50%'],['100%']],fields:['val'],xns:Roo.data}},{xtype:'TextItem',text:"Align: ",xns:C.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:70,name:'align',listeners:{select:function(F,r,G){A.editorcore.selectNode(A.tb.selectedNode);
 var b=B();b.align=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['left'],['right'],['center']],fields:['val'],xns:Roo.data}},{xtype:'Button',text:'Hide Caption',name:'caption_display',pressed:false,enableToggle:true,setValue:function(v){this.toggle(v=='block'?false:true);
 },listeners:{toggle:function(F,G){var b=B();b.caption_display=b.caption_display=='block'?'none':'block';this.setText(b.caption_display=='block'?"Hide Caption":"Show Caption");b.updateElement();D();A.editorcore.selectNode(A.tb.selectedNode);A.editorcore.onEditorEvent();
 var b=B();b.width=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['auto'],['50%'],['100%']],fields:['val'],xns:Roo.data}},{xtype:'TextItem',text:"Align: ",xns:C.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:70,name:'align',listeners:{select:function(F,r,G){A.editorcore.selectNode(A.tb.selectedNode);
 var b=B();b.align=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['left'],['right'],['center']],fields:['val'],xns:Roo.data}},{xtype:'Button',text:'Hide Caption',name:'caption_display',pressed:false,enableToggle:true,setValue:function(v){this.toggle(v=='block'?false:true);
 },listeners:{toggle:function(F,G){var b=B();b.caption_display=b.caption_display=='block'?'none':'block';this.setText(b.caption_display=='block'?"Hide Caption":"Show Caption");b.updateElement();D();A.editorcore.selectNode(A.tb.selectedNode);A.editorcore.onEditorEvent();
-}},xns:C.Toolbar}];},toObject:function(){var d=document.createElement('div');d.innerHTML=this.caption;var m=this.width=='50%'&&this.align=='center'?'0 auto':0;var A={tag:'img',contenteditable:'false',src:this.image_src,alt:d.innerText.replace(/\n/g," "),style:{width:'auto','max-width':'100%',margin:'0px'}
+}},xns:C.Toolbar}];},toObject:function(){var d=document.createElement('div');d.innerHTML=this.caption;var m=this.width=='50%'&&this.align=='center'?'0 auto':0;var A={tag:'img',contenteditable:'false',src:this.image_src,alt:d.innerText.replace(/\n/g," ").replace(/\s+/g,' ').trim(),style:{width:'auto','max-width':'100%',margin:'0px'}
 };if(this.href.length>0){A={tag:'a',href:this.href,contenteditable:'true',cn:[A]};}if(this.video_url.length>0){A={tag:'div',cls:this.cls,frameborder:0,allowfullscreen:true,width:420,height:315,src:this.video_url,cn:[A]};}return {tag:'figure','data-block':'Figure',contenteditable:'false',style:{display:'block',float:this.align,'max-width':this.width,width:'auto',margin:m,padding:'10px'}
 ,align:this.align,cn:[A,{tag:'figcaption',contenteditable:true,style:{'text-align':'left','margin-top':'16px','font-size':'16px','line-height':'24px','font-style':'italic',display:this.caption_display},cls:this.cls.length>0?(this.cls+'-thumbnail'):'',html:this.caption}
 ]};},readElement:function(A){this.video_url=this.getVal(A,'div','src');this.cls=this.getVal(A,'div','class');this.href=this.getVal(A,'a','href');this.image_src=this.getVal(A,'img','src');this.align=this.getVal(A,'figure','align');this.caption=this.getVal(A,'figcaption','html');
 };if(this.href.length>0){A={tag:'a',href:this.href,contenteditable:'true',cn:[A]};}if(this.video_url.length>0){A={tag:'div',cls:this.cls,frameborder:0,allowfullscreen:true,width:420,height:315,src:this.video_url,cn:[A]};}return {tag:'figure','data-block':'Figure',contenteditable:'false',style:{display:'block',float:this.align,'max-width':this.width,width:'auto',margin:m,padding:'10px'}
 ,align:this.align,cn:[A,{tag:'figcaption',contenteditable:true,style:{'text-align':'left','margin-top':'16px','font-size':'16px','line-height':'24px','font-style':'italic',display:this.caption_display},cls:this.cls.length>0?(this.cls+'-thumbnail'):'',html:this.caption}
 ]};},readElement:function(A){this.video_url=this.getVal(A,'div','src');this.cls=this.getVal(A,'div','class');this.href=this.getVal(A,'a','href');this.image_src=this.getVal(A,'img','src');this.align=this.getVal(A,'figure','align');this.caption=this.getVal(A,'figcaption','html');
@@ -2022,24 +2050,24 @@ if(c.col!=this.cellData.col){A[i][this.cellData.col].colspan--;}else if(c.colspa
 Roo.HtmlEditorCore=function(A){Roo.HtmlEditorCore.superclass.constructor.call(this,A);this.addEvents({initialize:true,activate:true,beforesync:true,beforepush:true,sync:true,push:true,editorevent:true});this.applyBlacklists();};Roo.extend(Roo.HtmlEditorCore,Roo.Component,{owner:false,resizable:false,height:300,width:500,autoClean:true,enableBlocks:true,stylesheets:false,language:'en',allowComments:false,frameId:false,validationEvent:false,deferHeight:true,initialized:false,activated:false,sourceEditMode:false,onFocus:Roo.emptyFn,iframePad:3,hideMode:'offsets',clearUp:true,black:false,white:false,bodyCls:'',undoManager:false,getDocMarkup:function(){var st='';
 if(this.stylesheets===false){Roo.get(document.head).select('style').each(function(B){st+=B.dom.outerHTML||new XMLSerializer().serializeToString(B.dom);});Roo.get(document.head).select('link').each(function(B){st+=B.dom.outerHTML||new XMLSerializer().serializeToString(B.dom);
 });}else if(!this.stylesheets.length){st='<style type="text/css">'+'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}'+'</style>';}else{for(var i in this.stylesheets){if(typeof(this.stylesheets[i])!='string'){continue;}st+='<link rel="stylesheet" href="'+this.stylesheets[i]+'" type="text/css">';
 Roo.HtmlEditorCore=function(A){Roo.HtmlEditorCore.superclass.constructor.call(this,A);this.addEvents({initialize:true,activate:true,beforesync:true,beforepush:true,sync:true,push:true,editorevent:true});this.applyBlacklists();};Roo.extend(Roo.HtmlEditorCore,Roo.Component,{owner:false,resizable:false,height:300,width:500,autoClean:true,enableBlocks:true,stylesheets:false,language:'en',allowComments:false,frameId:false,validationEvent:false,deferHeight:true,initialized:false,activated:false,sourceEditMode:false,onFocus:Roo.emptyFn,iframePad:3,hideMode:'offsets',clearUp:true,black:false,white:false,bodyCls:'',undoManager:false,getDocMarkup:function(){var st='';
 if(this.stylesheets===false){Roo.get(document.head).select('style').each(function(B){st+=B.dom.outerHTML||new XMLSerializer().serializeToString(B.dom);});Roo.get(document.head).select('link').each(function(B){st+=B.dom.outerHTML||new XMLSerializer().serializeToString(B.dom);
 });}else if(!this.stylesheets.length){st='<style type="text/css">'+'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}'+'</style>';}else{for(var i in this.stylesheets){if(typeof(this.stylesheets[i])!='string'){continue;}st+='<link rel="stylesheet" href="'+this.stylesheets[i]+'" type="text/css">';
-}}st+='<style type="text/css">'+'IMG { cursor: pointer } '+'</style>';var A='roo-htmleditor-body';if(this.bodyCls.length){A+=' '+this.bodyCls;}return '<html><head>'+st+' </head><body contenteditable="true" data-enable-grammerly="true" class="'+A+'"></body></html>';
+}}st+='<style type="text/css">'+'IMG { cursor: pointer } '+'</style>';st+='<meta name="google" content="notranslate">';var A='notranslate roo-htmleditor-body';if(this.bodyCls.length){A+=' '+this.bodyCls;}return '<html  class="notranslate" translate="no"><head>'+st+' </head><body contenteditable="true" data-enable-grammerly="true" class="'+A+'"></body></html>';
 },onRender:function(ct,A){var _t=this;this.el=this.owner.inputEl?this.owner.inputEl():this.owner.el;this.el.dom.style.border='0 none';this.el.dom.setAttribute('tabIndex',-1);this.el.addClass('x-hidden hide');if(Roo.isIE){this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')}
 this.frameId=Roo.id();var B=this.owner.wrap.createChild({tag:'iframe',cls:'form-control',id:this.frameId,name:this.frameId,frameBorder:'no','src':Roo.SSL_SECURE_URL?Roo.SSL_SECURE_URL:"javascript:false"},this.el);this.iframe=B.dom;this.assignDocWin();this.doc.designMode='on';
 this.doc.open();this.doc.write(this.getDocMarkup());this.doc.close();var C={run:function(){this.assignDocWin();if(this.doc.body||this.doc.readyState=='complete'){try{this.doc.designMode="on";}catch(e){return;}Roo.TaskMgr.stop(C);this.initEditor.defer(10,this);
 }},interval:10,duration:10000,scope:this};Roo.TaskMgr.start(C);},onResize:function(w,h){Roo.log('resize: '+w+','+h);if(!this.iframe){return;}if(typeof w=='number'){this.iframe.style.width=w+'px';}if(typeof h=='number'){this.iframe.style.height=h+'px';if(this.doc){(this.doc.body||this.doc.documentElement).style.height=(h-(this.iframePad*2))+'px';
 }}},toggleSourceEdit:function(A){this.sourceEditMode=A===true;if(this.sourceEditMode){Roo.get(this.iframe).addClass(['x-hidden','hide','d-none']);}else{Roo.get(this.iframe).removeClass(['x-hidden','hide','d-none']);this.deferFocus();}},cleanHtml:function(A){A=String(A);
 if(A.length>5){if(Roo.isSafari){A=A.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi,'');}}if(A=='&nbsp;'){A='';}return A;},syncValue:function(){if(this.initialized){this.undoManager.addEvent();var bd=(this.doc.body||this.doc.documentElement);
 },onRender:function(ct,A){var _t=this;this.el=this.owner.inputEl?this.owner.inputEl():this.owner.el;this.el.dom.style.border='0 none';this.el.dom.setAttribute('tabIndex',-1);this.el.addClass('x-hidden hide');if(Roo.isIE){this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')}
 this.frameId=Roo.id();var B=this.owner.wrap.createChild({tag:'iframe',cls:'form-control',id:this.frameId,name:this.frameId,frameBorder:'no','src':Roo.SSL_SECURE_URL?Roo.SSL_SECURE_URL:"javascript:false"},this.el);this.iframe=B.dom;this.assignDocWin();this.doc.designMode='on';
 this.doc.open();this.doc.write(this.getDocMarkup());this.doc.close();var C={run:function(){this.assignDocWin();if(this.doc.body||this.doc.readyState=='complete'){try{this.doc.designMode="on";}catch(e){return;}Roo.TaskMgr.stop(C);this.initEditor.defer(10,this);
 }},interval:10,duration:10000,scope:this};Roo.TaskMgr.start(C);},onResize:function(w,h){Roo.log('resize: '+w+','+h);if(!this.iframe){return;}if(typeof w=='number'){this.iframe.style.width=w+'px';}if(typeof h=='number'){this.iframe.style.height=h+'px';if(this.doc){(this.doc.body||this.doc.documentElement).style.height=(h-(this.iframePad*2))+'px';
 }}},toggleSourceEdit:function(A){this.sourceEditMode=A===true;if(this.sourceEditMode){Roo.get(this.iframe).addClass(['x-hidden','hide','d-none']);}else{Roo.get(this.iframe).removeClass(['x-hidden','hide','d-none']);this.deferFocus();}},cleanHtml:function(A){A=String(A);
 if(A.length>5){if(Roo.isSafari){A=A.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi,'');}}if(A=='&nbsp;'){A='';}return A;},syncValue:function(){if(this.initialized){this.undoManager.addEvent();var bd=(this.doc.body||this.doc.documentElement);
-var A=document.createElement('div');A.innerHTML=bd.innerHTML;if(this.enableBlocks){new Roo.htmleditor.FilterBlock({node:A});}var B=A.innerHTML;if(Roo.isSafari){var bs=bd.getAttribute('style');var m=bs?bs.match(/text-align:(.*?);/i):false;if(m&&m[1]){B='<div style="'+m[0]+'">'+B+'</div>';
-}}B=this.cleanHtml(B);B=B.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g,function(C){var cc=C.charCodeAt();if(C.length==2){var D=C.charCodeAt(0)-0xD800;var E=C.charCodeAt(1)-0xDC00;cc=(D*0x400)+E+0x10000;}else if((cc>=0x4E00&&cc<0xA000)||(cc>=0x3400&&cc<0x4E00)||(cc>=0xf900&&cc<0xfb00)){return C;
-}return "&#"+cc+";";});if(this.owner.fireEvent('beforesync',this,B)!==false){this.el.dom.value=B;this.owner.fireEvent('sync',this,B);}}},pushValue:function(){if(this.initialized){var v=this.el.dom.value.trim();if(this.owner.fireEvent('beforepush',this,v)!==false){var d=(this.doc.body||this.doc.documentElement);
-d.innerHTML=v;this.el.dom.value=d.innerHTML;this.owner.fireEvent('push',this,v);}if(this.autoClean){new Roo.htmleditor.FilterParagraph({node:this.doc.body});new Roo.htmleditor.FilterSpan({node:this.doc.body});}Roo.htmleditor.Block.initAll(this.doc.body);this.updateLanguage();
-var lc=this.doc.body.lastChild;if(lc&&lc.nodeType==1&&lc.getAttribute("contenteditable")=="false"){this.doc.body.appendChild(this.doc.createElement('br'));}}},deferFocus:function(){this.focus.defer(10,this);},focus:function(){if(this.win&&!this.sourceEditMode){this.win.focus();
-}else{this.el.focus();}},assignDocWin:function(){var A=this.iframe;if(Roo.isIE){this.doc=A.contentWindow.document;this.win=A.contentWindow;}else{if(!Roo.get(this.frameId)&&!A.contentDocument){return;}this.doc=(A.contentDocument||Roo.get(this.frameId).dom.document);
-this.win=(A.contentWindow||Roo.get(this.frameId).dom.contentWindow);}},initEditor:function(){this.assignDocWin();this.doc.designMode="on";this.doc.open();this.doc.write(this.getDocMarkup());this.doc.close();var A=(this.doc.body||this.doc.documentElement);
-A.bgProperties='fixed';Roo.EventManager.on(this.doc,{'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);}if(Roo.isIE||Roo.isSafari||Roo.isOpera){Roo.EventManager.on(this.doc,'keydown',this.fixKeys,this);}this.initialized=true;new Roo.htmleditor.KeyEnter({core:this});this.owner.fireEvent('initialize',this);
-this.pushValue();},onPasteEvent:function(e,v){var cd=(e.browserEvent.clipboardData||window.clipboardData);if(cd.files.length>0){var A=(window.createObjectURL&&window)||(window.URL&&URL.revokeObjectURL&&URL)||(window.webkitURL&&webkitURL);var B=A.createObjectURL(cd.files[0]);
-this.insertAtCursor('<img src=" + url + ">');return false;}var C=cd.getData('text/html');var D=new Roo.rtf.Parser(cd.getData('text/rtf'));var E=D.doc?D.doc.getElementsByType('pict'):[];Roo.log(E);E=E.filter(function(g){return !g.path.match(/^rtf\/(head|pgdsctbl|listtable)/);
+var A=this.win.getSelection();var B=document.createElement('div');B.innerHTML=bd.innerHTML;var C=B.getElementsByClassName('gtx-trans-icon');if(C.length>0){var rm=C.item(0).parentNode;rm.parentNode.removeChild(rm);}if(this.enableBlocks){new Roo.htmleditor.FilterBlock({node:B}
+);}var D=new Roo.htmleditor.TidySerializer({inner:true});var E=D.serialize(B);if(Roo.isSafari){var bs=bd.getAttribute('style');var m=bs?bs.match(/text-align:(.*?);/i):false;if(m&&m[1]){E='<div style="'+m[0]+'">'+E+'</div>';}}E=this.cleanHtml(E);E=E.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g,function(F){var cc=F.charCodeAt();
+if(F.length==2){var G=F.charCodeAt(0)-0xD800;var H=F.charCodeAt(1)-0xDC00;cc=(G*0x400)+H+0x10000;}else if((cc>=0x4E00&&cc<0xA000)||(cc>=0x3400&&cc<0x4E00)||(cc>=0xf900&&cc<0xfb00)){return F;}return "&#"+cc+";";});if(this.owner.fireEvent('beforesync',this,E)!==false){this.el.dom.value=E;
+this.owner.fireEvent('sync',this,E);}}},pushValue:function(){if(this.initialized){var v=this.el.dom.value.trim();if(this.owner.fireEvent('beforepush',this,v)!==false){var d=(this.doc.body||this.doc.documentElement);d.innerHTML=v;this.el.dom.value=d.innerHTML;
+this.owner.fireEvent('push',this,v);}if(this.autoClean){new Roo.htmleditor.FilterParagraph({node:this.doc.body});new Roo.htmleditor.FilterSpan({node:this.doc.body});}Roo.htmleditor.Block.initAll(this.doc.body);this.updateLanguage();var lc=this.doc.body.lastChild;
+if(lc&&lc.nodeType==1&&lc.getAttribute("contenteditable")=="false"){this.doc.body.appendChild(this.doc.createElement('br'));}}},deferFocus:function(){this.focus.defer(10,this);},focus:function(){if(this.win&&!this.sourceEditMode){this.win.focus();}else{this.el.focus();
+}},assignDocWin:function(){var A=this.iframe;if(Roo.isIE){this.doc=A.contentWindow.document;this.win=A.contentWindow;}else{if(!Roo.get(this.frameId)&&!A.contentDocument){return;}this.doc=(A.contentDocument||Roo.get(this.frameId).dom.document);this.win=(A.contentWindow||Roo.get(this.frameId).dom.contentWindow);
+}},initEditor:function(){this.assignDocWin();this.doc.designMode="on";this.doc.open();this.doc.write(this.getDocMarkup());this.doc.close();var A=(this.doc.body||this.doc.documentElement);A.bgProperties='fixed';A.setAttribute("translate","no");Roo.EventManager.on(this.doc,{'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);}if(Roo.isIE||Roo.isSafari||Roo.isOpera){Roo.EventManager.on(this.doc,'keydown',this.fixKeys,this);}this.initialized=true;
+new Roo.htmleditor.KeyEnter({core:this});this.owner.fireEvent('initialize',this);this.pushValue();},onPasteEvent:function(e,v){var cd=(e.browserEvent.clipboardData||window.clipboardData);if(cd.files.length>0){var A=(window.createObjectURL&&window)||(window.URL&&URL.revokeObjectURL&&URL)||(window.webkitURL&&webkitURL);
+var B=A.createObjectURL(cd.files[0]);this.insertAtCursor('<img src=" + url + ">');return false;}var C=cd.getData('text/html');var D=new Roo.rtf.Parser(cd.getData('text/rtf'));var E=D.doc?D.doc.getElementsByType('pict'):[];Roo.log(E);E=E.filter(function(g){return !g.path.match(/^rtf\/(head|pgdsctbl|listtable)/);
 }).map(function(g){return g.toDataURL();});C=this.cleanWordChars(C);var d=(new DOMParser().parseFromString(C,'text/html')).body;var sn=this.getParentElement();if(d.getElementsByTagName('table').length&&sn&&sn.closest('table')){e.preventDefault();this.insertAtCursor("You can not nest tables");
 return false;}if(E.length>0){Roo.each(d.getElementsByTagName('img'),function(F,i){F.setAttribute('src',E[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});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(F){if(F.closest('figure')){return;
 }).map(function(g){return g.toDataURL();});C=this.cleanWordChars(C);var d=(new DOMParser().parseFromString(C,'text/html')).body;var sn=this.getParentElement();if(d.getElementsByTagName('table').length&&sn&&sn.closest('table')){e.preventDefault();this.insertAtCursor("You can not nest tables");
 return false;}if(E.length>0){Roo.each(d.getElementsByTagName('img'),function(F,i){F.setAttribute('src',E[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});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(F){if(F.closest('figure')){return;
index 5d6e7b2..a5e751f 100644 (file)
@@ -46306,41 +46306,1304 @@ Roo.apply(Roo.htmleditor.FilterBlock.prototype,
         
     
 });
         
     
 });
-/**
- * @class Roo.htmleditor.Tidy
- * Tidy HTML 
- * @cfg {Roo.HtmlEditorCore} core the editor.
+/***
+ * This is based loosely on tinymce 
+ * @class Roo.htmleditor.TidySerializer
+ * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
  * @constructor
  * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
+ * @method Serializer
+ * @param {Object} settings Name/value settings object.
+ * @param {tinymce.html.Schema} schema Schema instance to use.
  */
 
 
  */
 
 
-Roo.htmleditor.Tidy = function(cfg) {
-    Roo.apply(this, cfg);
+Roo.htmleditor.TidySerializer = function(settings)
+{
+    Roo.apply(this, settings);
     
     
-    this.core.doc.body.innerHTML = this.tidy(this.core.doc.body, '');
-     
-}
+    this.writer = new Roo.htmleditor.TidyWriter(settings);
+    
+    //settings.validate = !('validate' in settings) || settings.validate;
+    //      self.schema = schema = schema || new Schema();
 
 
-Roo.htmleditor.Tidy.toString = function(node)
+};
+Roo.htmleditor.TidySerializer.prototype = {
+    
+    /**
+     * @param {boolean} inner do the inner of the node.
+     */
+    inner : false,
+    
+    writer : false,
+    
+    /**
+    * Serializes the specified node into a string.
+    *
+    * @example
+    * new tinymce.html.Serializer().serialize(new tinymce.html.DomParser().parse('<p>text</p>'));
+    * @method serialize
+    * @param {DomElement} node Node instance to serialize.
+    * @return {String} String with HTML based on DOM tree.
+    */
+    serialize : function(node) {
+        
+        // = settings.validate;
+        var writer = this.writer;
+        var self  = this;
+        this.handlers = {
+            // #text
+            3: function(node) {
+                
+                writer.text(node.nodeValue, node);
+            },
+            // #comment
+            8: function(node) {
+                writer.comment(node.nodeValue);
+            },
+            // Processing instruction
+            7: function(node) {
+                writer.pi(node.name, node.nodeValue);
+            },
+            // Doctype
+            10: function(node) {
+                writer.doctype(node.nodeValue);
+            },
+            // CDATA
+            4: function(node) {
+                writer.cdata(node.nodeValue);
+            },
+            // Document fragment
+            11: function(node) {
+                node = node.firstChild;
+                if (!node) {
+                    return;
+                }
+                while(node) {
+                    self.walk(node);
+                    node = node.nextSibling
+                }
+            }
+        };
+        writer.reset();
+        1 != node.nodeType || this.inner ? this.handlers[11](node) : this.walk(node);
+        return writer.getContent();
+    },
+
+    walk: function(node)
+    {
+        var attrName, attrValue, sortedAttrs, i, l, elementRule,
+            handler = this.handlers[node.nodeType];
+            
+        if (handler) {
+            handler(node);
+            return;
+        }
+    
+        var name = node.nodeName;
+        var isEmpty = node.childNodes.length < 1;
+      
+        var writer = this.writer;
+        var attrs = node.attributes;
+        // Sort attributes
+        /*
+        if (validate && attrs && attrs.length > 1) {
+            sortedAttrs = [];
+            sortedAttrs.map = {};
+            elementRule = schema.getElementRule(node.name);
+            if (elementRule) {
+                for (i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
+                    attrName = elementRule.attributesOrder[i];
+                    if (attrName in attrs.map) {
+                        attrValue = attrs.map[attrName];
+                        sortedAttrs.map[attrName] = attrValue;
+                        sortedAttrs.push({
+                            name: attrName,
+                            value: attrValue
+                        });
+                    }
+                }
+                for (i = 0, l = attrs.length; i < l; i++) {
+                    attrName = attrs[i].name;
+                    if (!(attrName in sortedAttrs.map)) {
+                        attrValue = attrs.map[attrName];
+                        sortedAttrs.map[attrName] = attrValue;
+                        sortedAttrs.push({
+                            name: attrName,
+                            value: attrValue
+                        });
+                    }
+                }
+                attrs = sortedAttrs;
+            }
+        }
+        */
+        writer.start(node.nodeName, attrs, isEmpty, node);
+        if (isEmpty) {
+            return;
+        }
+        node = node.firstChild;
+        if (!node) {
+            writer.end(name);
+            return;
+        }
+        while (node) {
+            this.walk(node);
+            node = node.nextSibling;
+        }
+        writer.end(name);
+        
+    
+    }
+    // Serialize element and treat all non elements as fragments
+   
+}; 
+
+/***
+ * This is based loosely on tinymce 
+ * @class Roo.htmleditor.TidyWriter
+ * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
+ *
+ * Known issues?
+ * - not tested much with 'PRE' formated elements.
+ * 
+ *
+ *
+ */
+
+Roo.htmleditor.TidyWriter = function(settings)
 {
 {
-    return Roo.htmleditor.Tidy.prototype.tidy(node, '');
+    
+    // indent, indentBefore, indentAfter, encode, htmlOutput, html = [];
+    Roo.apply(this, settings);
+    this.html = [];
+    this.state = [];
+     
+    this.encode = Roo.htmleditor.TidyEntities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
+  
 }
 }
+Roo.htmleditor.TidyWriter.prototype = {
 
 
-Roo.htmleditor.Tidy.prototype = {
+    state : false,
     
     
+    indent :  '  ',
     
     
+    // part of state...
+    indentstr : '',
+    in_pre: false,
+    in_inline : false,
+    last_inline : false,
+    encode : false,
      
      
-
     
     
-    tidy : function(node, indent) {
+            /**
+    * Writes the a start element such as <p id="a">.
+    *
+    * @method start
+    * @param {String} name Name of the element.
+    * @param {Array} attrs Optional attribute array or undefined if it hasn't any.
+    * @param {Boolean} empty Optional empty state if the tag should end like <br />.
+    */
+    start: function(name, attrs, empty, node)
+    {
+        var i, l, attr, value;
+        
+        // there are some situations where adding line break && indentation will not work. will not work.
+        // <span / b / i ... formating?
+        
+        var in_inline = this.in_inline || Roo.htmleditor.TidyWriter.inline_elements.indexOf(name) > -1;
+        var in_pre    = this.in_pre    || Roo.htmleditor.TidyWriter.whitespace_elements.indexOf(name) > -1;
+        
+        var is_short   = empty ? Roo.htmleditor.TidyWriter.shortend_elements.indexOf(name) > -1 : false;
+        
+        var add_lb = name == 'BR' ? false : in_inline;
+        
+        if (!add_lb && !this.in_pre && this.lastElementEndsWS()) {
+            i_inline = false;
+        }
+
+        var indentstr =  this.indentstr;
+        
+        // e_inline = elements that can be inline, but still allow \n before and after?
+        // only 'BR' ??? any others?
+        
+        // ADD LINE BEFORE tage
+        if (!this.in_pre) {
+            if (in_inline) {
+                //code
+                if (name == 'BR') {
+                    this.addLine();
+                } else if (this.lastElementEndsWS()) {
+                    this.addLine();
+                } else{
+                    // otherwise - no new line. (and dont indent.)
+                    indentstr = '';
+                }
+                
+            } else {
+                this.addLine();
+            }
+        } else {
+            indentstr = '';
+        }
+        
+        this.html.push(indentstr + '<', name.toLowerCase());
+        
+        if (attrs) {
+            for (i = 0, l = attrs.length; i < l; i++) {
+                attr = attrs[i];
+                this.html.push(' ', attr.name, '="', this.encode(attr.value, true), '"');
+            }
+        }
      
      
+        if (empty) {
+            if (is_short) {
+                this.html[this.html.length] = '/>';
+            } else {
+                this.html[this.html.length] = '></' + name.toLowerCase() + '>';
+            }
+            var e_inline = name == 'BR' ? false : this.in_inline;
+            
+            if (!e_inline && !this.in_pre) {
+                this.addLine();
+            }
+            return;
+        
+        }
+        // not empty..
+        this.html[this.html.length] = '>';
+        
+        // there is a special situation, where we need to turn on in_inline - if any of the imediate chidlren are one of these.
+        /*
+        if (!in_inline && !in_pre) {
+            var cn = node.firstChild;
+            while(cn) {
+                if (Roo.htmleditor.TidyWriter.inline_elements.indexOf(cn.nodeName) > -1) {
+                    in_inline = true
+                    break;
+                }
+                cn = cn.nextSibling;
+            }
+             
+        }
+        */
+        
+        
+        this.pushState({
+            indentstr : in_pre   ? '' : (this.indentstr + this.indent),
+            in_pre : in_pre,
+            in_inline :  in_inline
+        });
+        // add a line after if we are not in a
+        
+        if (!in_inline && !in_pre) {
+            this.addLine();
+        }
+        
+            
          
          
+        
+    },
+    
+    lastElementEndsWS : function()
+    {
+        var value = this.html.length > 0 ? this.html[this.html.length-1] : false;
+        if (value === false) {
+            return true;
+        }
+        return value.match(/\s+$/);
+        
+    },
     
     
+    /**
+     * Writes the a end element such as </p>.
+     *
+     * @method end
+     * @param {String} name Name of the element.
+     */
+    end: function(name) {
+        var value;
+        this.popState();
+        var indentstr = '';
+        var in_inline = this.in_inline || Roo.htmleditor.TidyWriter.inline_elements.indexOf(name) > -1;
+        
+        if (!this.in_pre && !in_inline) {
+            this.addLine();
+            indentstr  = this.indentstr;
+        }
+        this.html.push(indentstr + '</', name.toLowerCase(), '>');
+        this.last_inline = in_inline;
+        
+        // pop the indent state..
+    },
+    /**
+     * Writes a text node.
+     *
+     * In pre - we should not mess with the contents.
+     * 
+     *
+     * @method text
+     * @param {String} text String to write out.
+     * @param {Boolean} raw Optional raw state if true the contents wont get encoded.
+     */
+    text: function(text, node)
+    {
+        // if not in whitespace critical
+        if (text.length < 1) {
+            return;
+        }
+        if (this.in_pre) {
+            this.html[this.html.length] =  text;
+            return;   
+        }
+        
+        if (this.in_inline) {
+            text = text.replace(/\s+/g,' '); // all white space inc line breaks to a slingle' '
+            if (text != ' ') {
+                text = text.replace(/\s+/,' ');  // all white space to single white space
+                
+                    
+                // if next tag is '<BR>', then we can trim right..
+                if (node.nextSibling &&
+                    node.nextSibling.nodeType == 1 &&
+                    node.nextSibling.nodeName == 'BR' )
+                {
+                    text = text.replace(/\s+$/g,'');
+                }
+                // if previous tag was a BR, we can also trim..
+                if (node.previousSibling &&
+                    node.previousSibling.nodeType == 1 &&
+                    node.previousSibling.nodeName == 'BR' )
+                {
+                    text = this.indentstr +  text.replace(/^\s+/g,'');
+                }
+                if (text.match(/\n/)) {
+                    text = text.replace(
+                        /(?![^\n]{1,64}$)([^\n]{1,64})\s/g, '$1\n' + this.indentstr
+                    );
+                    // remoeve the last whitespace / line break.
+                    text = text.replace(/\n\s+$/,'');
+                }
+                // repace long lines
+                
+            }
+             
+            this.html[this.html.length] =  text;
+            return;   
+        }
+        // see if previous element was a inline element.
+        var indentstr = this.indentstr;
+   
+        text = text.replace(/\s+/g," "); // all whitespace into single white space.
+        
+        // should trim left?
+        if (node.previousSibling &&
+            node.previousSibling.nodeType == 1 &&
+            Roo.htmleditor.TidyWriter.inline_elements.indexOf(node.previousSibling.nodeName) > -1)
+        {
+            indentstr = '';
+            
+        } else {
+            this.addLine();
+            text = text.replace(/^\s+/,''); // trim left
+          
+        }
+        // should trim right?
+        if (node.nextSibling &&
+            node.nextSibling.nodeType == 1 &&
+            Roo.htmleditor.TidyWriter.inline_elements.indexOf(node.nextSibling.nodeName) > -1)
+        {
+          // noop
+            
+        }  else {
+            text = text.replace(/\s+$/,''); // trim right
+        }
+         
+              
+        
+        
+        
+        if (text.length < 1) {
+            return;
+        }
+        if (!text.match(/\n/)) {
+            this.html.push(indentstr + text);
+            return;
+        }
+        
+        text = this.indentstr + text.replace(
+            /(?![^\n]{1,64}$)([^\n]{1,64})\s/g, '$1\n' + this.indentstr
+        );
+        // remoeve the last whitespace / line break.
+        text = text.replace(/\s+$/,''); 
+        
+        this.html.push(text);
+        
+        // split and indent..
+        
+        
+    },
+    /**
+     * Writes a cdata node such as <![CDATA[data]]>.
+     *
+     * @method cdata
+     * @param {String} text String to write out inside the cdata.
+     */
+    cdata: function(text) {
+        this.html.push('<![CDATA[', text, ']]>');
+    },
+    /**
+    * Writes a comment node such as <!-- Comment -->.
+    *
+    * @method cdata
+    * @param {String} text String to write out inside the comment.
+    */
+   comment: function(text) {
+       this.html.push('<!--', text, '-->');
+   },
+    /**
+     * Writes a PI node such as <?xml attr="value" ?>.
+     *
+     * @method pi
+     * @param {String} name Name of the pi.
+     * @param {String} text String to write out inside the pi.
+     */
+    pi: function(name, text) {
+        text ? this.html.push('<?', name, ' ', this.encode(text), '?>') : this.html.push('<?', name, '?>');
+        this.indent != '' && this.html.push('\n');
+    },
+    /**
+     * Writes a doctype node such as <!DOCTYPE data>.
+     *
+     * @method doctype
+     * @param {String} text String to write out inside the doctype.
+     */
+    doctype: function(text) {
+        this.html.push('<!DOCTYPE', text, '>', this.indent != '' ? '\n' : '');
+    },
+    /**
+     * Resets the internal buffer if one wants to reuse the writer.
+     *
+     * @method reset
+     */
+    reset: function() {
+        this.html.length = 0;
+        this.state = [];
+        this.pushState({
+            indentstr : '',
+            in_pre : false, 
+            in_inline : false
+        })
+    },
+    /**
+     * Returns the contents that got serialized.
+     *
+     * @method getContent
+     * @return {String} HTML contents that got written down.
+     */
+    getContent: function() {
+        return this.html.join('').replace(/\n$/, '');
+    },
+    
+    pushState : function(cfg)
+    {
+        this.state.push(cfg);
+        Roo.apply(this, cfg);
+    },
+    
+    popState : function()
+    {
+        if (this.state.length < 1) {
+            return; // nothing to push
+        }
+        var cfg = {
+            in_pre: false,
+            indentstr : ''
+        };
+        this.state.pop();
+        if (this.state.length > 0) {
+            cfg = this.state[this.state.length-1]; 
+        }
+        Roo.apply(this, cfg);
+    },
+    
+    addLine: function()
+    {
+        if (this.html.length < 1) {
+            return;
+        }
+        
+        
+        var value = this.html[this.html.length - 1];
+        if (value.length > 0 && '\n' !== value) {
+            this.html.push('\n');
+        }
     }
     
     }
     
-}
+    
+//'pre script noscript style textarea video audio iframe object code'
+// shortended... 'area base basefont br col frame hr img input isindex link  meta param embed source wbr track');
+// inline 
+};
+
+Roo.htmleditor.TidyWriter.inline_elements = [
+        'SPAN','STRONG','B','EM','I','FONT','STRIKE','U','VAR',
+        'CITE','DFN','CODE','MARK','Q','SUP','SUB','SAMP'
+];
+Roo.htmleditor.TidyWriter.shortend_elements = [
+    'AREA','BASE','BASEFONT','BR','COL','FRAME','HR','IMG','INPUT',
+    'ISINDEX','LINK','','META','PARAM','EMBED','SOURCE','WBR','TRACK'
+];
+
+Roo.htmleditor.TidyWriter.whitespace_elements = [
+    'PRE','SCRIPT','NOSCRIPT','STYLE','TEXTAREA','VIDEO','AUDIO','IFRAME','OBJECT','CODE'
+];/***
+ * This is based loosely on tinymce 
+ * @class Roo.htmleditor.TidyEntities
+ * @static
+ * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
+ *
+ * Not 100% sure this is actually used or needed.
+ */
+
+Roo.htmleditor.TidyEntities = {
+    
+    /**
+     * initialize data..
+     */
+    init : function (){
+     
+        this.namedEntities = this.buildEntitiesLookup(this.namedEntitiesData, 32);
+       
+    },
+
+
+    buildEntitiesLookup: function(items, radix) {
+        var i, chr, entity, lookup = {};
+        if (!items) {
+            return {};
+        }
+        items = typeof(items) == 'string' ? items.split(',') : items;
+        radix = radix || 10;
+        // Build entities lookup table
+        for (i = 0; i < items.length; i += 2) {
+            chr = String.fromCharCode(parseInt(items[i], radix));
+            // Only add non base entities
+            if (!this.baseEntities[chr]) {
+                entity = '&' + items[i + 1] + ';';
+                lookup[chr] = entity;
+                lookup[entity] = chr;
+            }
+        }
+        return lookup;
+        
+    },
+    
+    asciiMap : {
+            128: '€',
+            130: '‚',
+            131: 'ƒ',
+            132: '„',
+            133: '…',
+            134: '†',
+            135: '‡',
+            136: 'ˆ',
+            137: '‰',
+            138: 'Š',
+            139: '‹',
+            140: 'Œ',
+            142: 'Ž',
+            145: '‘',
+            146: '’',
+            147: '“',
+            148: '”',
+            149: '•',
+            150: '–',
+            151: '—',
+            152: '˜',
+            153: '™',
+            154: 'š',
+            155: '›',
+            156: 'œ',
+            158: 'ž',
+            159: 'Ÿ'
+    },
+    // Raw entities
+    baseEntities : {
+        '"': '&quot;',
+        // Needs to be escaped since the YUI compressor would otherwise break the code
+        '\'': '&#39;',
+        '<': '&lt;',
+        '>': '&gt;',
+        '&': '&amp;',
+        '`': '&#96;'
+    },
+    // Reverse lookup table for raw entities
+    reverseEntities : {
+        '&lt;': '<',
+        '&gt;': '>',
+        '&amp;': '&',
+        '&quot;': '"',
+        '&apos;': '\''
+    },
+    
+    attrsCharsRegExp : /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+    textCharsRegExp : /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+    rawCharsRegExp : /[<>&\"\']/g,
+    entityRegExp : /&#([a-z0-9]+);?|&([a-z0-9]+);/gi,
+    namedEntities  : false,
+    namedEntitiesData : [ 
+        '50',
+        'nbsp',
+        '51',
+        'iexcl',
+        '52',
+        'cent',
+        '53',
+        'pound',
+        '54',
+        'curren',
+        '55',
+        'yen',
+        '56',
+        'brvbar',
+        '57',
+        'sect',
+        '58',
+        'uml',
+        '59',
+        'copy',
+        '5a',
+        'ordf',
+        '5b',
+        'laquo',
+        '5c',
+        'not',
+        '5d',
+        'shy',
+        '5e',
+        'reg',
+        '5f',
+        'macr',
+        '5g',
+        'deg',
+        '5h',
+        'plusmn',
+        '5i',
+        'sup2',
+        '5j',
+        'sup3',
+        '5k',
+        'acute',
+        '5l',
+        'micro',
+        '5m',
+        'para',
+        '5n',
+        'middot',
+        '5o',
+        'cedil',
+        '5p',
+        'sup1',
+        '5q',
+        'ordm',
+        '5r',
+        'raquo',
+        '5s',
+        'frac14',
+        '5t',
+        'frac12',
+        '5u',
+        'frac34',
+        '5v',
+        'iquest',
+        '60',
+        'Agrave',
+        '61',
+        'Aacute',
+        '62',
+        'Acirc',
+        '63',
+        'Atilde',
+        '64',
+        'Auml',
+        '65',
+        'Aring',
+        '66',
+        'AElig',
+        '67',
+        'Ccedil',
+        '68',
+        'Egrave',
+        '69',
+        'Eacute',
+        '6a',
+        'Ecirc',
+        '6b',
+        'Euml',
+        '6c',
+        'Igrave',
+        '6d',
+        'Iacute',
+        '6e',
+        'Icirc',
+        '6f',
+        'Iuml',
+        '6g',
+        'ETH',
+        '6h',
+        'Ntilde',
+        '6i',
+        'Ograve',
+        '6j',
+        'Oacute',
+        '6k',
+        'Ocirc',
+        '6l',
+        'Otilde',
+        '6m',
+        'Ouml',
+        '6n',
+        'times',
+        '6o',
+        'Oslash',
+        '6p',
+        'Ugrave',
+        '6q',
+        'Uacute',
+        '6r',
+        'Ucirc',
+        '6s',
+        'Uuml',
+        '6t',
+        'Yacute',
+        '6u',
+        'THORN',
+        '6v',
+        'szlig',
+        '70',
+        'agrave',
+        '71',
+        'aacute',
+        '72',
+        'acirc',
+        '73',
+        'atilde',
+        '74',
+        'auml',
+        '75',
+        'aring',
+        '76',
+        'aelig',
+        '77',
+        'ccedil',
+        '78',
+        'egrave',
+        '79',
+        'eacute',
+        '7a',
+        'ecirc',
+        '7b',
+        'euml',
+        '7c',
+        'igrave',
+        '7d',
+        'iacute',
+        '7e',
+        'icirc',
+        '7f',
+        'iuml',
+        '7g',
+        'eth',
+        '7h',
+        'ntilde',
+        '7i',
+        'ograve',
+        '7j',
+        'oacute',
+        '7k',
+        'ocirc',
+        '7l',
+        'otilde',
+        '7m',
+        'ouml',
+        '7n',
+        'divide',
+        '7o',
+        'oslash',
+        '7p',
+        'ugrave',
+        '7q',
+        'uacute',
+        '7r',
+        'ucirc',
+        '7s',
+        'uuml',
+        '7t',
+        'yacute',
+        '7u',
+        'thorn',
+        '7v',
+        'yuml',
+        'ci',
+        'fnof',
+        'sh',
+        'Alpha',
+        'si',
+        'Beta',
+        'sj',
+        'Gamma',
+        'sk',
+        'Delta',
+        'sl',
+        'Epsilon',
+        'sm',
+        'Zeta',
+        'sn',
+        'Eta',
+        'so',
+        'Theta',
+        'sp',
+        'Iota',
+        'sq',
+        'Kappa',
+        'sr',
+        'Lambda',
+        'ss',
+        'Mu',
+        'st',
+        'Nu',
+        'su',
+        'Xi',
+        'sv',
+        'Omicron',
+        't0',
+        'Pi',
+        't1',
+        'Rho',
+        't3',
+        'Sigma',
+        't4',
+        'Tau',
+        't5',
+        'Upsilon',
+        't6',
+        'Phi',
+        't7',
+        'Chi',
+        't8',
+        'Psi',
+        't9',
+        'Omega',
+        'th',
+        'alpha',
+        'ti',
+        'beta',
+        'tj',
+        'gamma',
+        'tk',
+        'delta',
+        'tl',
+        'epsilon',
+        'tm',
+        'zeta',
+        'tn',
+        'eta',
+        'to',
+        'theta',
+        'tp',
+        'iota',
+        'tq',
+        'kappa',
+        'tr',
+        'lambda',
+        'ts',
+        'mu',
+        'tt',
+        'nu',
+        'tu',
+        'xi',
+        'tv',
+        'omicron',
+        'u0',
+        'pi',
+        'u1',
+        'rho',
+        'u2',
+        'sigmaf',
+        'u3',
+        'sigma',
+        'u4',
+        'tau',
+        'u5',
+        'upsilon',
+        'u6',
+        'phi',
+        'u7',
+        'chi',
+        'u8',
+        'psi',
+        'u9',
+        'omega',
+        'uh',
+        'thetasym',
+        'ui',
+        'upsih',
+        'um',
+        'piv',
+        '812',
+        'bull',
+        '816',
+        'hellip',
+        '81i',
+        'prime',
+        '81j',
+        'Prime',
+        '81u',
+        'oline',
+        '824',
+        'frasl',
+        '88o',
+        'weierp',
+        '88h',
+        'image',
+        '88s',
+        'real',
+        '892',
+        'trade',
+        '89l',
+        'alefsym',
+        '8cg',
+        'larr',
+        '8ch',
+        'uarr',
+        '8ci',
+        'rarr',
+        '8cj',
+        'darr',
+        '8ck',
+        'harr',
+        '8dl',
+        'crarr',
+        '8eg',
+        'lArr',
+        '8eh',
+        'uArr',
+        '8ei',
+        'rArr',
+        '8ej',
+        'dArr',
+        '8ek',
+        'hArr',
+        '8g0',
+        'forall',
+        '8g2',
+        'part',
+        '8g3',
+        'exist',
+        '8g5',
+        'empty',
+        '8g7',
+        'nabla',
+        '8g8',
+        'isin',
+        '8g9',
+        'notin',
+        '8gb',
+        'ni',
+        '8gf',
+        'prod',
+        '8gh',
+        'sum',
+        '8gi',
+        'minus',
+        '8gn',
+        'lowast',
+        '8gq',
+        'radic',
+        '8gt',
+        'prop',
+        '8gu',
+        'infin',
+        '8h0',
+        'ang',
+        '8h7',
+        'and',
+        '8h8',
+        'or',
+        '8h9',
+        'cap',
+        '8ha',
+        'cup',
+        '8hb',
+        'int',
+        '8hk',
+        'there4',
+        '8hs',
+        'sim',
+        '8i5',
+        'cong',
+        '8i8',
+        'asymp',
+        '8j0',
+        'ne',
+        '8j1',
+        'equiv',
+        '8j4',
+        'le',
+        '8j5',
+        'ge',
+        '8k2',
+        'sub',
+        '8k3',
+        'sup',
+        '8k4',
+        'nsub',
+        '8k6',
+        'sube',
+        '8k7',
+        'supe',
+        '8kl',
+        'oplus',
+        '8kn',
+        'otimes',
+        '8l5',
+        'perp',
+        '8m5',
+        'sdot',
+        '8o8',
+        'lceil',
+        '8o9',
+        'rceil',
+        '8oa',
+        'lfloor',
+        '8ob',
+        'rfloor',
+        '8p9',
+        'lang',
+        '8pa',
+        'rang',
+        '9ea',
+        'loz',
+        '9j0',
+        'spades',
+        '9j3',
+        'clubs',
+        '9j5',
+        'hearts',
+        '9j6',
+        'diams',
+        'ai',
+        'OElig',
+        'aj',
+        'oelig',
+        'b0',
+        'Scaron',
+        'b1',
+        'scaron',
+        'bo',
+        'Yuml',
+        'm6',
+        'circ',
+        'ms',
+        'tilde',
+        '802',
+        'ensp',
+        '803',
+        'emsp',
+        '809',
+        'thinsp',
+        '80c',
+        'zwnj',
+        '80d',
+        'zwj',
+        '80e',
+        'lrm',
+        '80f',
+        'rlm',
+        '80j',
+        'ndash',
+        '80k',
+        'mdash',
+        '80o',
+        'lsquo',
+        '80p',
+        'rsquo',
+        '80q',
+        'sbquo',
+        '80s',
+        'ldquo',
+        '80t',
+        'rdquo',
+        '80u',
+        'bdquo',
+        '810',
+        'dagger',
+        '811',
+        'Dagger',
+        '81g',
+        'permil',
+        '81p',
+        'lsaquo',
+        '81q',
+        'rsaquo',
+        '85c',
+        'euro'
+    ],
+
+         
+    /**
+     * Encodes the specified string using raw entities. This means only the required XML base entities will be encoded.
+     *
+     * @method encodeRaw
+     * @param {String} text Text to encode.
+     * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+     * @return {String} Entity encoded text.
+     */
+    encodeRaw: function(text, attr)
+    {
+        var t = this;
+        return text.replace(attr ? this.attrsCharsRegExp : this.textCharsRegExp, function(chr) {
+            return t.baseEntities[chr] || chr;
+        });
+    },
+    /**
+     * Encoded the specified text with both the attributes and text entities. This function will produce larger text contents
+     * since it doesn't know if the context is within a attribute or text node. This was added for compatibility
+     * and is exposed as the DOMUtils.encode function.
+     *
+     * @method encodeAllRaw
+     * @param {String} text Text to encode.
+     * @return {String} Entity encoded text.
+     */
+    encodeAllRaw: function(text) {
+        var t = this;
+        return ('' + text).replace(this.rawCharsRegExp, function(chr) {
+            return t.baseEntities[chr] || chr;
+        });
+    },
+    /**
+     * Encodes the specified string using numeric entities. The core entities will be
+     * encoded as named ones but all non lower ascii characters will be encoded into numeric entities.
+     *
+     * @method encodeNumeric
+     * @param {String} text Text to encode.
+     * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+     * @return {String} Entity encoded text.
+     */
+    encodeNumeric: function(text, attr) {
+        var t = this;
+        return text.replace(attr ? this.attrsCharsRegExp : this.textCharsRegExp, function(chr) {
+            // Multi byte sequence convert it to a single entity
+            if (chr.length > 1) {
+                return '&#' + (1024 * (chr.charCodeAt(0) - 55296) + (chr.charCodeAt(1) - 56320) + 65536) + ';';
+            }
+            return t.baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
+        });
+    },
+    /**
+     * Encodes the specified string using named entities. The core entities will be encoded
+     * as named ones but all non lower ascii characters will be encoded into named entities.
+     *
+     * @method encodeNamed
+     * @param {String} text Text to encode.
+     * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+     * @param {Object} entities Optional parameter with entities to use.
+     * @return {String} Entity encoded text.
+     */
+    encodeNamed: function(text, attr, entities) {
+        var t = this;
+        entities = entities || this.namedEntities;
+        return text.replace(attr ? this.attrsCharsRegExp : this.textCharsRegExp, function(chr) {
+            return t.baseEntities[chr] || entities[chr] || chr;
+        });
+    },
+    /**
+     * Returns an encode function based on the name(s) and it's optional entities.
+     *
+     * @method getEncodeFunc
+     * @param {String} name Comma separated list of encoders for example named,numeric.
+     * @param {String} entities Optional parameter with entities to use instead of the built in set.
+     * @return {function} Encode function to be used.
+     */
+    getEncodeFunc: function(name, entities) {
+        entities = this.buildEntitiesLookup(entities) || this.namedEntities;
+        var t = this;
+        function encodeNamedAndNumeric(text, attr) {
+            return text.replace(attr ? t.attrsCharsRegExp : t.textCharsRegExp, function(chr) {
+                return t.baseEntities[chr] || entities[chr] || '&#' + chr.charCodeAt(0) + ';' || chr;
+            });
+        }
+
+        function encodeCustomNamed(text, attr) {
+            return t.encodeNamed(text, attr, entities);
+        }
+        // Replace + with , to be compatible with previous TinyMCE versions
+        name = this.makeMap(name.replace(/\+/g, ','));
+        // Named and numeric encoder
+        if (name.named && name.numeric) {
+            return this.encodeNamedAndNumeric;
+        }
+        // Named encoder
+        if (name.named) {
+            // Custom names
+            if (entities) {
+                return encodeCustomNamed;
+            }
+            return this.encodeNamed;
+        }
+        // Numeric
+        if (name.numeric) {
+            return this.encodeNumeric;
+        }
+        // Raw encoder
+        return this.encodeRaw;
+    },
+    /**
+     * Decodes the specified string, this will replace entities with raw UTF characters.
+     *
+     * @method decode
+     * @param {String} text Text to entity decode.
+     * @return {String} Entity decoded string.
+     */
+    decode: function(text)
+    {
+        var  t = this;
+        return text.replace(this.entityRegExp, function(all, numeric) {
+            if (numeric) {
+                numeric = 'x' === numeric.charAt(0).toLowerCase() ? parseInt(numeric.substr(1), 16) : parseInt(numeric, 10);
+                // Support upper UTF
+                if (numeric > 65535) {
+                    numeric -= 65536;
+                    return String.fromCharCode(55296 + (numeric >> 10), 56320 + (1023 & numeric));
+                }
+                return t.asciiMap[numeric] || String.fromCharCode(numeric);
+            }
+            return t.reverseEntities[all] || t.namedEntities[all] || t.nativeDecode(all);
+        });
+    },
+    nativeDecode : function (text) {
+        return text;
+    },
+    makeMap : function (items, delim, map) {
+               var i;
+               items = items || [];
+               delim = delim || ',';
+               if (typeof items == "string") {
+                       items = items.split(delim);
+               }
+               map = map || {};
+               i = items.length;
+               while (i--) {
+                       map[items[i]] = {};
+               }
+               return map;
+       }
+};
+    
+    
+    
+Roo.htmleditor.TidyEntities.init();
 /**
  * @class Roo.htmleditor.KeyEnter
  * Handle Enter press..
 /**
  * @class Roo.htmleditor.KeyEnter
  * Handle Enter press..
@@ -46775,7 +48038,7 @@ Roo.extend(Roo.htmleditor.BlockFigure, Roo.htmleditor.Block, {
             tag : 'img',
             contenteditable : 'false',
             src : this.image_src,
             tag : 'img',
             contenteditable : 'false',
             src : this.image_src,
-            alt : d.innerText.replace(/\n/g, " "), // removeHTML..
+            alt : d.innerText.replace(/\n/g, " ").replace(/\s+/g, ' ').trim(), // removeHTML and reduce spaces..
             style: {
                 width : 'auto',
                 'max-width': '100%',
             style: {
                 width : 'auto',
                 'max-width': '100%',
@@ -48323,14 +49586,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         st +=  '<style type="text/css">' +
             'IMG { cursor: pointer } ' +
         '</style>';
         st +=  '<style type="text/css">' +
             '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;
         }
         
         
         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>' +
             //<style type="text/css">' +
             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
             //'</style>' +
@@ -48457,7 +49722,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      * @param {String} html The HTML to be cleaned
      * return {String} The cleaned HTML
      */
      * @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
         html = String(html);
         if(html.length > 5){
             if(Roo.isSafari){ // strip safari nonsense
@@ -48486,18 +49752,27 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             var bd = (this.doc.body || this.doc.documentElement);
            
             
             var bd = (this.doc.body || this.doc.documentElement);
            
             
+            var sel = this.win.getSelection();
             
             var div = document.createElement('div');
             div.innerHTML = bd.innerHTML;
             
             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?
            
             if (this.enableBlocks) {
                 new Roo.htmleditor.FilterBlock({ node : div });
             }
             //?? tidy?
+            var tidy = new Roo.htmleditor.TidySerializer({
+                inner:  true
+            });
+            var html  = tidy.serialize(div);
             
             
             
             
-            var html = div.innerHTML;
             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;
             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;
@@ -48636,6 +49911,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
         //ss['background-attachment'] = 'fixed'; // w3c
         dbody.bgProperties = 'fixed'; // ie
         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
         //ss['background-attachment'] = 'fixed'; // w3c
         dbody.bgProperties = 'fixed'; // ie
+        dbody.setAttribute("translate", "no");
+        
         //Roo.DomHelper.applyStyles(dbody, ss);
         Roo.EventManager.on(this.doc, {
              
         //Roo.DomHelper.applyStyles(dbody, ss);
         Roo.EventManager.on(this.doc, {
              
index 6e15a5e..3b3124f 100644 (file)
@@ -21837,41 +21837,1304 @@ Roo.apply(Roo.htmleditor.FilterBlock.prototype,
         
     
 });
         
     
 });
-/**
- * @class Roo.htmleditor.Tidy
- * Tidy HTML 
- * @cfg {Roo.HtmlEditorCore} core the editor.
+/***
+ * This is based loosely on tinymce 
+ * @class Roo.htmleditor.TidySerializer
+ * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
  * @constructor
  * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
+ * @method Serializer
+ * @param {Object} settings Name/value settings object.
+ * @param {tinymce.html.Schema} schema Schema instance to use.
  */
 
 
  */
 
 
-Roo.htmleditor.Tidy = function(cfg) {
-    Roo.apply(this, cfg);
+Roo.htmleditor.TidySerializer = function(settings)
+{
+    Roo.apply(this, settings);
     
     
-    this.core.doc.body.innerHTML = this.tidy(this.core.doc.body, '');
-     
-}
+    this.writer = new Roo.htmleditor.TidyWriter(settings);
+    
+    //settings.validate = !('validate' in settings) || settings.validate;
+    //      self.schema = schema = schema || new Schema();
+
+};
+Roo.htmleditor.TidySerializer.prototype = {
+    
+    /**
+     * @param {boolean} inner do the inner of the node.
+     */
+    inner : false,
+    
+    writer : false,
+    
+    /**
+    * Serializes the specified node into a string.
+    *
+    * @example
+    * new tinymce.html.Serializer().serialize(new tinymce.html.DomParser().parse('<p>text</p>'));
+    * @method serialize
+    * @param {DomElement} node Node instance to serialize.
+    * @return {String} String with HTML based on DOM tree.
+    */
+    serialize : function(node) {
+        
+        // = settings.validate;
+        var writer = this.writer;
+        var self  = this;
+        this.handlers = {
+            // #text
+            3: function(node) {
+                
+                writer.text(node.nodeValue, node);
+            },
+            // #comment
+            8: function(node) {
+                writer.comment(node.nodeValue);
+            },
+            // Processing instruction
+            7: function(node) {
+                writer.pi(node.name, node.nodeValue);
+            },
+            // Doctype
+            10: function(node) {
+                writer.doctype(node.nodeValue);
+            },
+            // CDATA
+            4: function(node) {
+                writer.cdata(node.nodeValue);
+            },
+            // Document fragment
+            11: function(node) {
+                node = node.firstChild;
+                if (!node) {
+                    return;
+                }
+                while(node) {
+                    self.walk(node);
+                    node = node.nextSibling
+                }
+            }
+        };
+        writer.reset();
+        1 != node.nodeType || this.inner ? this.handlers[11](node) : this.walk(node);
+        return writer.getContent();
+    },
+
+    walk: function(node)
+    {
+        var attrName, attrValue, sortedAttrs, i, l, elementRule,
+            handler = this.handlers[node.nodeType];
+            
+        if (handler) {
+            handler(node);
+            return;
+        }
+    
+        var name = node.nodeName;
+        var isEmpty = node.childNodes.length < 1;
+      
+        var writer = this.writer;
+        var attrs = node.attributes;
+        // Sort attributes
+        /*
+        if (validate && attrs && attrs.length > 1) {
+            sortedAttrs = [];
+            sortedAttrs.map = {};
+            elementRule = schema.getElementRule(node.name);
+            if (elementRule) {
+                for (i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
+                    attrName = elementRule.attributesOrder[i];
+                    if (attrName in attrs.map) {
+                        attrValue = attrs.map[attrName];
+                        sortedAttrs.map[attrName] = attrValue;
+                        sortedAttrs.push({
+                            name: attrName,
+                            value: attrValue
+                        });
+                    }
+                }
+                for (i = 0, l = attrs.length; i < l; i++) {
+                    attrName = attrs[i].name;
+                    if (!(attrName in sortedAttrs.map)) {
+                        attrValue = attrs.map[attrName];
+                        sortedAttrs.map[attrName] = attrValue;
+                        sortedAttrs.push({
+                            name: attrName,
+                            value: attrValue
+                        });
+                    }
+                }
+                attrs = sortedAttrs;
+            }
+        }
+        */
+        writer.start(node.nodeName, attrs, isEmpty, node);
+        if (isEmpty) {
+            return;
+        }
+        node = node.firstChild;
+        if (!node) {
+            writer.end(name);
+            return;
+        }
+        while (node) {
+            this.walk(node);
+            node = node.nextSibling;
+        }
+        writer.end(name);
+        
+    
+    }
+    // Serialize element and treat all non elements as fragments
+   
+}; 
 
 
-Roo.htmleditor.Tidy.toString = function(node)
+/***
+ * This is based loosely on tinymce 
+ * @class Roo.htmleditor.TidyWriter
+ * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
+ *
+ * Known issues?
+ * - not tested much with 'PRE' formated elements.
+ * 
+ *
+ *
+ */
+
+Roo.htmleditor.TidyWriter = function(settings)
 {
 {
-    return Roo.htmleditor.Tidy.prototype.tidy(node, '');
+    
+    // indent, indentBefore, indentAfter, encode, htmlOutput, html = [];
+    Roo.apply(this, settings);
+    this.html = [];
+    this.state = [];
+     
+    this.encode = Roo.htmleditor.TidyEntities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
+  
 }
 }
+Roo.htmleditor.TidyWriter.prototype = {
 
 
-Roo.htmleditor.Tidy.prototype = {
+    state : false,
     
     
+    indent :  '  ',
     
     
+    // part of state...
+    indentstr : '',
+    in_pre: false,
+    in_inline : false,
+    last_inline : false,
+    encode : false,
      
      
-
     
     
-    tidy : function(node, indent) {
+            /**
+    * Writes the a start element such as <p id="a">.
+    *
+    * @method start
+    * @param {String} name Name of the element.
+    * @param {Array} attrs Optional attribute array or undefined if it hasn't any.
+    * @param {Boolean} empty Optional empty state if the tag should end like <br />.
+    */
+    start: function(name, attrs, empty, node)
+    {
+        var i, l, attr, value;
+        
+        // there are some situations where adding line break && indentation will not work. will not work.
+        // <span / b / i ... formating?
+        
+        var in_inline = this.in_inline || Roo.htmleditor.TidyWriter.inline_elements.indexOf(name) > -1;
+        var in_pre    = this.in_pre    || Roo.htmleditor.TidyWriter.whitespace_elements.indexOf(name) > -1;
+        
+        var is_short   = empty ? Roo.htmleditor.TidyWriter.shortend_elements.indexOf(name) > -1 : false;
+        
+        var add_lb = name == 'BR' ? false : in_inline;
+        
+        if (!add_lb && !this.in_pre && this.lastElementEndsWS()) {
+            i_inline = false;
+        }
+
+        var indentstr =  this.indentstr;
+        
+        // e_inline = elements that can be inline, but still allow \n before and after?
+        // only 'BR' ??? any others?
+        
+        // ADD LINE BEFORE tage
+        if (!this.in_pre) {
+            if (in_inline) {
+                //code
+                if (name == 'BR') {
+                    this.addLine();
+                } else if (this.lastElementEndsWS()) {
+                    this.addLine();
+                } else{
+                    // otherwise - no new line. (and dont indent.)
+                    indentstr = '';
+                }
+                
+            } else {
+                this.addLine();
+            }
+        } else {
+            indentstr = '';
+        }
+        
+        this.html.push(indentstr + '<', name.toLowerCase());
+        
+        if (attrs) {
+            for (i = 0, l = attrs.length; i < l; i++) {
+                attr = attrs[i];
+                this.html.push(' ', attr.name, '="', this.encode(attr.value, true), '"');
+            }
+        }
      
      
+        if (empty) {
+            if (is_short) {
+                this.html[this.html.length] = '/>';
+            } else {
+                this.html[this.html.length] = '></' + name.toLowerCase() + '>';
+            }
+            var e_inline = name == 'BR' ? false : this.in_inline;
+            
+            if (!e_inline && !this.in_pre) {
+                this.addLine();
+            }
+            return;
+        
+        }
+        // not empty..
+        this.html[this.html.length] = '>';
+        
+        // there is a special situation, where we need to turn on in_inline - if any of the imediate chidlren are one of these.
+        /*
+        if (!in_inline && !in_pre) {
+            var cn = node.firstChild;
+            while(cn) {
+                if (Roo.htmleditor.TidyWriter.inline_elements.indexOf(cn.nodeName) > -1) {
+                    in_inline = true
+                    break;
+                }
+                cn = cn.nextSibling;
+            }
+             
+        }
+        */
+        
+        
+        this.pushState({
+            indentstr : in_pre   ? '' : (this.indentstr + this.indent),
+            in_pre : in_pre,
+            in_inline :  in_inline
+        });
+        // add a line after if we are not in a
+        
+        if (!in_inline && !in_pre) {
+            this.addLine();
+        }
+        
+            
+         
+        
+    },
+    
+    lastElementEndsWS : function()
+    {
+        var value = this.html.length > 0 ? this.html[this.html.length-1] : false;
+        if (value === false) {
+            return true;
+        }
+        return value.match(/\s+$/);
+        
+    },
+    
+    /**
+     * Writes the a end element such as </p>.
+     *
+     * @method end
+     * @param {String} name Name of the element.
+     */
+    end: function(name) {
+        var value;
+        this.popState();
+        var indentstr = '';
+        var in_inline = this.in_inline || Roo.htmleditor.TidyWriter.inline_elements.indexOf(name) > -1;
+        
+        if (!this.in_pre && !in_inline) {
+            this.addLine();
+            indentstr  = this.indentstr;
+        }
+        this.html.push(indentstr + '</', name.toLowerCase(), '>');
+        this.last_inline = in_inline;
+        
+        // pop the indent state..
+    },
+    /**
+     * Writes a text node.
+     *
+     * In pre - we should not mess with the contents.
+     * 
+     *
+     * @method text
+     * @param {String} text String to write out.
+     * @param {Boolean} raw Optional raw state if true the contents wont get encoded.
+     */
+    text: function(text, node)
+    {
+        // if not in whitespace critical
+        if (text.length < 1) {
+            return;
+        }
+        if (this.in_pre) {
+            this.html[this.html.length] =  text;
+            return;   
+        }
+        
+        if (this.in_inline) {
+            text = text.replace(/\s+/g,' '); // all white space inc line breaks to a slingle' '
+            if (text != ' ') {
+                text = text.replace(/\s+/,' ');  // all white space to single white space
+                
+                    
+                // if next tag is '<BR>', then we can trim right..
+                if (node.nextSibling &&
+                    node.nextSibling.nodeType == 1 &&
+                    node.nextSibling.nodeName == 'BR' )
+                {
+                    text = text.replace(/\s+$/g,'');
+                }
+                // if previous tag was a BR, we can also trim..
+                if (node.previousSibling &&
+                    node.previousSibling.nodeType == 1 &&
+                    node.previousSibling.nodeName == 'BR' )
+                {
+                    text = this.indentstr +  text.replace(/^\s+/g,'');
+                }
+                if (text.match(/\n/)) {
+                    text = text.replace(
+                        /(?![^\n]{1,64}$)([^\n]{1,64})\s/g, '$1\n' + this.indentstr
+                    );
+                    // remoeve the last whitespace / line break.
+                    text = text.replace(/\n\s+$/,'');
+                }
+                // repace long lines
+                
+            }
+             
+            this.html[this.html.length] =  text;
+            return;   
+        }
+        // see if previous element was a inline element.
+        var indentstr = this.indentstr;
+   
+        text = text.replace(/\s+/g," "); // all whitespace into single white space.
+        
+        // should trim left?
+        if (node.previousSibling &&
+            node.previousSibling.nodeType == 1 &&
+            Roo.htmleditor.TidyWriter.inline_elements.indexOf(node.previousSibling.nodeName) > -1)
+        {
+            indentstr = '';
+            
+        } else {
+            this.addLine();
+            text = text.replace(/^\s+/,''); // trim left
+          
+        }
+        // should trim right?
+        if (node.nextSibling &&
+            node.nextSibling.nodeType == 1 &&
+            Roo.htmleditor.TidyWriter.inline_elements.indexOf(node.nextSibling.nodeName) > -1)
+        {
+          // noop
+            
+        }  else {
+            text = text.replace(/\s+$/,''); // trim right
+        }
          
          
+              
+        
+        
+        
+        if (text.length < 1) {
+            return;
+        }
+        if (!text.match(/\n/)) {
+            this.html.push(indentstr + text);
+            return;
+        }
+        
+        text = this.indentstr + text.replace(
+            /(?![^\n]{1,64}$)([^\n]{1,64})\s/g, '$1\n' + this.indentstr
+        );
+        // remoeve the last whitespace / line break.
+        text = text.replace(/\s+$/,''); 
+        
+        this.html.push(text);
+        
+        // split and indent..
+        
+        
+    },
+    /**
+     * Writes a cdata node such as <![CDATA[data]]>.
+     *
+     * @method cdata
+     * @param {String} text String to write out inside the cdata.
+     */
+    cdata: function(text) {
+        this.html.push('<![CDATA[', text, ']]>');
+    },
+    /**
+    * Writes a comment node such as <!-- Comment -->.
+    *
+    * @method cdata
+    * @param {String} text String to write out inside the comment.
+    */
+   comment: function(text) {
+       this.html.push('<!--', text, '-->');
+   },
+    /**
+     * Writes a PI node such as <?xml attr="value" ?>.
+     *
+     * @method pi
+     * @param {String} name Name of the pi.
+     * @param {String} text String to write out inside the pi.
+     */
+    pi: function(name, text) {
+        text ? this.html.push('<?', name, ' ', this.encode(text), '?>') : this.html.push('<?', name, '?>');
+        this.indent != '' && this.html.push('\n');
+    },
+    /**
+     * Writes a doctype node such as <!DOCTYPE data>.
+     *
+     * @method doctype
+     * @param {String} text String to write out inside the doctype.
+     */
+    doctype: function(text) {
+        this.html.push('<!DOCTYPE', text, '>', this.indent != '' ? '\n' : '');
+    },
+    /**
+     * Resets the internal buffer if one wants to reuse the writer.
+     *
+     * @method reset
+     */
+    reset: function() {
+        this.html.length = 0;
+        this.state = [];
+        this.pushState({
+            indentstr : '',
+            in_pre : false, 
+            in_inline : false
+        })
+    },
+    /**
+     * Returns the contents that got serialized.
+     *
+     * @method getContent
+     * @return {String} HTML contents that got written down.
+     */
+    getContent: function() {
+        return this.html.join('').replace(/\n$/, '');
+    },
+    
+    pushState : function(cfg)
+    {
+        this.state.push(cfg);
+        Roo.apply(this, cfg);
+    },
+    
+    popState : function()
+    {
+        if (this.state.length < 1) {
+            return; // nothing to push
+        }
+        var cfg = {
+            in_pre: false,
+            indentstr : ''
+        };
+        this.state.pop();
+        if (this.state.length > 0) {
+            cfg = this.state[this.state.length-1]; 
+        }
+        Roo.apply(this, cfg);
+    },
     
     
+    addLine: function()
+    {
+        if (this.html.length < 1) {
+            return;
+        }
+        
+        
+        var value = this.html[this.html.length - 1];
+        if (value.length > 0 && '\n' !== value) {
+            this.html.push('\n');
+        }
     }
     
     }
     
-}
+    
+//'pre script noscript style textarea video audio iframe object code'
+// shortended... 'area base basefont br col frame hr img input isindex link  meta param embed source wbr track');
+// inline 
+};
+
+Roo.htmleditor.TidyWriter.inline_elements = [
+        'SPAN','STRONG','B','EM','I','FONT','STRIKE','U','VAR',
+        'CITE','DFN','CODE','MARK','Q','SUP','SUB','SAMP'
+];
+Roo.htmleditor.TidyWriter.shortend_elements = [
+    'AREA','BASE','BASEFONT','BR','COL','FRAME','HR','IMG','INPUT',
+    'ISINDEX','LINK','','META','PARAM','EMBED','SOURCE','WBR','TRACK'
+];
+
+Roo.htmleditor.TidyWriter.whitespace_elements = [
+    'PRE','SCRIPT','NOSCRIPT','STYLE','TEXTAREA','VIDEO','AUDIO','IFRAME','OBJECT','CODE'
+];/***
+ * This is based loosely on tinymce 
+ * @class Roo.htmleditor.TidyEntities
+ * @static
+ * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
+ *
+ * Not 100% sure this is actually used or needed.
+ */
+
+Roo.htmleditor.TidyEntities = {
+    
+    /**
+     * initialize data..
+     */
+    init : function (){
+     
+        this.namedEntities = this.buildEntitiesLookup(this.namedEntitiesData, 32);
+       
+    },
+
+
+    buildEntitiesLookup: function(items, radix) {
+        var i, chr, entity, lookup = {};
+        if (!items) {
+            return {};
+        }
+        items = typeof(items) == 'string' ? items.split(',') : items;
+        radix = radix || 10;
+        // Build entities lookup table
+        for (i = 0; i < items.length; i += 2) {
+            chr = String.fromCharCode(parseInt(items[i], radix));
+            // Only add non base entities
+            if (!this.baseEntities[chr]) {
+                entity = '&' + items[i + 1] + ';';
+                lookup[chr] = entity;
+                lookup[entity] = chr;
+            }
+        }
+        return lookup;
+        
+    },
+    
+    asciiMap : {
+            128: '€',
+            130: '‚',
+            131: 'ƒ',
+            132: '„',
+            133: '…',
+            134: '†',
+            135: '‡',
+            136: 'ˆ',
+            137: '‰',
+            138: 'Š',
+            139: '‹',
+            140: 'Œ',
+            142: 'Ž',
+            145: '‘',
+            146: '’',
+            147: '“',
+            148: '”',
+            149: '•',
+            150: '–',
+            151: '—',
+            152: '˜',
+            153: '™',
+            154: 'š',
+            155: '›',
+            156: 'œ',
+            158: 'ž',
+            159: 'Ÿ'
+    },
+    // Raw entities
+    baseEntities : {
+        '"': '&quot;',
+        // Needs to be escaped since the YUI compressor would otherwise break the code
+        '\'': '&#39;',
+        '<': '&lt;',
+        '>': '&gt;',
+        '&': '&amp;',
+        '`': '&#96;'
+    },
+    // Reverse lookup table for raw entities
+    reverseEntities : {
+        '&lt;': '<',
+        '&gt;': '>',
+        '&amp;': '&',
+        '&quot;': '"',
+        '&apos;': '\''
+    },
+    
+    attrsCharsRegExp : /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+    textCharsRegExp : /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+    rawCharsRegExp : /[<>&\"\']/g,
+    entityRegExp : /&#([a-z0-9]+);?|&([a-z0-9]+);/gi,
+    namedEntities  : false,
+    namedEntitiesData : [ 
+        '50',
+        'nbsp',
+        '51',
+        'iexcl',
+        '52',
+        'cent',
+        '53',
+        'pound',
+        '54',
+        'curren',
+        '55',
+        'yen',
+        '56',
+        'brvbar',
+        '57',
+        'sect',
+        '58',
+        'uml',
+        '59',
+        'copy',
+        '5a',
+        'ordf',
+        '5b',
+        'laquo',
+        '5c',
+        'not',
+        '5d',
+        'shy',
+        '5e',
+        'reg',
+        '5f',
+        'macr',
+        '5g',
+        'deg',
+        '5h',
+        'plusmn',
+        '5i',
+        'sup2',
+        '5j',
+        'sup3',
+        '5k',
+        'acute',
+        '5l',
+        'micro',
+        '5m',
+        'para',
+        '5n',
+        'middot',
+        '5o',
+        'cedil',
+        '5p',
+        'sup1',
+        '5q',
+        'ordm',
+        '5r',
+        'raquo',
+        '5s',
+        'frac14',
+        '5t',
+        'frac12',
+        '5u',
+        'frac34',
+        '5v',
+        'iquest',
+        '60',
+        'Agrave',
+        '61',
+        'Aacute',
+        '62',
+        'Acirc',
+        '63',
+        'Atilde',
+        '64',
+        'Auml',
+        '65',
+        'Aring',
+        '66',
+        'AElig',
+        '67',
+        'Ccedil',
+        '68',
+        'Egrave',
+        '69',
+        'Eacute',
+        '6a',
+        'Ecirc',
+        '6b',
+        'Euml',
+        '6c',
+        'Igrave',
+        '6d',
+        'Iacute',
+        '6e',
+        'Icirc',
+        '6f',
+        'Iuml',
+        '6g',
+        'ETH',
+        '6h',
+        'Ntilde',
+        '6i',
+        'Ograve',
+        '6j',
+        'Oacute',
+        '6k',
+        'Ocirc',
+        '6l',
+        'Otilde',
+        '6m',
+        'Ouml',
+        '6n',
+        'times',
+        '6o',
+        'Oslash',
+        '6p',
+        'Ugrave',
+        '6q',
+        'Uacute',
+        '6r',
+        'Ucirc',
+        '6s',
+        'Uuml',
+        '6t',
+        'Yacute',
+        '6u',
+        'THORN',
+        '6v',
+        'szlig',
+        '70',
+        'agrave',
+        '71',
+        'aacute',
+        '72',
+        'acirc',
+        '73',
+        'atilde',
+        '74',
+        'auml',
+        '75',
+        'aring',
+        '76',
+        'aelig',
+        '77',
+        'ccedil',
+        '78',
+        'egrave',
+        '79',
+        'eacute',
+        '7a',
+        'ecirc',
+        '7b',
+        'euml',
+        '7c',
+        'igrave',
+        '7d',
+        'iacute',
+        '7e',
+        'icirc',
+        '7f',
+        'iuml',
+        '7g',
+        'eth',
+        '7h',
+        'ntilde',
+        '7i',
+        'ograve',
+        '7j',
+        'oacute',
+        '7k',
+        'ocirc',
+        '7l',
+        'otilde',
+        '7m',
+        'ouml',
+        '7n',
+        'divide',
+        '7o',
+        'oslash',
+        '7p',
+        'ugrave',
+        '7q',
+        'uacute',
+        '7r',
+        'ucirc',
+        '7s',
+        'uuml',
+        '7t',
+        'yacute',
+        '7u',
+        'thorn',
+        '7v',
+        'yuml',
+        'ci',
+        'fnof',
+        'sh',
+        'Alpha',
+        'si',
+        'Beta',
+        'sj',
+        'Gamma',
+        'sk',
+        'Delta',
+        'sl',
+        'Epsilon',
+        'sm',
+        'Zeta',
+        'sn',
+        'Eta',
+        'so',
+        'Theta',
+        'sp',
+        'Iota',
+        'sq',
+        'Kappa',
+        'sr',
+        'Lambda',
+        'ss',
+        'Mu',
+        'st',
+        'Nu',
+        'su',
+        'Xi',
+        'sv',
+        'Omicron',
+        't0',
+        'Pi',
+        't1',
+        'Rho',
+        't3',
+        'Sigma',
+        't4',
+        'Tau',
+        't5',
+        'Upsilon',
+        't6',
+        'Phi',
+        't7',
+        'Chi',
+        't8',
+        'Psi',
+        't9',
+        'Omega',
+        'th',
+        'alpha',
+        'ti',
+        'beta',
+        'tj',
+        'gamma',
+        'tk',
+        'delta',
+        'tl',
+        'epsilon',
+        'tm',
+        'zeta',
+        'tn',
+        'eta',
+        'to',
+        'theta',
+        'tp',
+        'iota',
+        'tq',
+        'kappa',
+        'tr',
+        'lambda',
+        'ts',
+        'mu',
+        'tt',
+        'nu',
+        'tu',
+        'xi',
+        'tv',
+        'omicron',
+        'u0',
+        'pi',
+        'u1',
+        'rho',
+        'u2',
+        'sigmaf',
+        'u3',
+        'sigma',
+        'u4',
+        'tau',
+        'u5',
+        'upsilon',
+        'u6',
+        'phi',
+        'u7',
+        'chi',
+        'u8',
+        'psi',
+        'u9',
+        'omega',
+        'uh',
+        'thetasym',
+        'ui',
+        'upsih',
+        'um',
+        'piv',
+        '812',
+        'bull',
+        '816',
+        'hellip',
+        '81i',
+        'prime',
+        '81j',
+        'Prime',
+        '81u',
+        'oline',
+        '824',
+        'frasl',
+        '88o',
+        'weierp',
+        '88h',
+        'image',
+        '88s',
+        'real',
+        '892',
+        'trade',
+        '89l',
+        'alefsym',
+        '8cg',
+        'larr',
+        '8ch',
+        'uarr',
+        '8ci',
+        'rarr',
+        '8cj',
+        'darr',
+        '8ck',
+        'harr',
+        '8dl',
+        'crarr',
+        '8eg',
+        'lArr',
+        '8eh',
+        'uArr',
+        '8ei',
+        'rArr',
+        '8ej',
+        'dArr',
+        '8ek',
+        'hArr',
+        '8g0',
+        'forall',
+        '8g2',
+        'part',
+        '8g3',
+        'exist',
+        '8g5',
+        'empty',
+        '8g7',
+        'nabla',
+        '8g8',
+        'isin',
+        '8g9',
+        'notin',
+        '8gb',
+        'ni',
+        '8gf',
+        'prod',
+        '8gh',
+        'sum',
+        '8gi',
+        'minus',
+        '8gn',
+        'lowast',
+        '8gq',
+        'radic',
+        '8gt',
+        'prop',
+        '8gu',
+        'infin',
+        '8h0',
+        'ang',
+        '8h7',
+        'and',
+        '8h8',
+        'or',
+        '8h9',
+        'cap',
+        '8ha',
+        'cup',
+        '8hb',
+        'int',
+        '8hk',
+        'there4',
+        '8hs',
+        'sim',
+        '8i5',
+        'cong',
+        '8i8',
+        'asymp',
+        '8j0',
+        'ne',
+        '8j1',
+        'equiv',
+        '8j4',
+        'le',
+        '8j5',
+        'ge',
+        '8k2',
+        'sub',
+        '8k3',
+        'sup',
+        '8k4',
+        'nsub',
+        '8k6',
+        'sube',
+        '8k7',
+        'supe',
+        '8kl',
+        'oplus',
+        '8kn',
+        'otimes',
+        '8l5',
+        'perp',
+        '8m5',
+        'sdot',
+        '8o8',
+        'lceil',
+        '8o9',
+        'rceil',
+        '8oa',
+        'lfloor',
+        '8ob',
+        'rfloor',
+        '8p9',
+        'lang',
+        '8pa',
+        'rang',
+        '9ea',
+        'loz',
+        '9j0',
+        'spades',
+        '9j3',
+        'clubs',
+        '9j5',
+        'hearts',
+        '9j6',
+        'diams',
+        'ai',
+        'OElig',
+        'aj',
+        'oelig',
+        'b0',
+        'Scaron',
+        'b1',
+        'scaron',
+        'bo',
+        'Yuml',
+        'm6',
+        'circ',
+        'ms',
+        'tilde',
+        '802',
+        'ensp',
+        '803',
+        'emsp',
+        '809',
+        'thinsp',
+        '80c',
+        'zwnj',
+        '80d',
+        'zwj',
+        '80e',
+        'lrm',
+        '80f',
+        'rlm',
+        '80j',
+        'ndash',
+        '80k',
+        'mdash',
+        '80o',
+        'lsquo',
+        '80p',
+        'rsquo',
+        '80q',
+        'sbquo',
+        '80s',
+        'ldquo',
+        '80t',
+        'rdquo',
+        '80u',
+        'bdquo',
+        '810',
+        'dagger',
+        '811',
+        'Dagger',
+        '81g',
+        'permil',
+        '81p',
+        'lsaquo',
+        '81q',
+        'rsaquo',
+        '85c',
+        'euro'
+    ],
+
+         
+    /**
+     * Encodes the specified string using raw entities. This means only the required XML base entities will be encoded.
+     *
+     * @method encodeRaw
+     * @param {String} text Text to encode.
+     * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+     * @return {String} Entity encoded text.
+     */
+    encodeRaw: function(text, attr)
+    {
+        var t = this;
+        return text.replace(attr ? this.attrsCharsRegExp : this.textCharsRegExp, function(chr) {
+            return t.baseEntities[chr] || chr;
+        });
+    },
+    /**
+     * Encoded the specified text with both the attributes and text entities. This function will produce larger text contents
+     * since it doesn't know if the context is within a attribute or text node. This was added for compatibility
+     * and is exposed as the DOMUtils.encode function.
+     *
+     * @method encodeAllRaw
+     * @param {String} text Text to encode.
+     * @return {String} Entity encoded text.
+     */
+    encodeAllRaw: function(text) {
+        var t = this;
+        return ('' + text).replace(this.rawCharsRegExp, function(chr) {
+            return t.baseEntities[chr] || chr;
+        });
+    },
+    /**
+     * Encodes the specified string using numeric entities. The core entities will be
+     * encoded as named ones but all non lower ascii characters will be encoded into numeric entities.
+     *
+     * @method encodeNumeric
+     * @param {String} text Text to encode.
+     * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+     * @return {String} Entity encoded text.
+     */
+    encodeNumeric: function(text, attr) {
+        var t = this;
+        return text.replace(attr ? this.attrsCharsRegExp : this.textCharsRegExp, function(chr) {
+            // Multi byte sequence convert it to a single entity
+            if (chr.length > 1) {
+                return '&#' + (1024 * (chr.charCodeAt(0) - 55296) + (chr.charCodeAt(1) - 56320) + 65536) + ';';
+            }
+            return t.baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
+        });
+    },
+    /**
+     * Encodes the specified string using named entities. The core entities will be encoded
+     * as named ones but all non lower ascii characters will be encoded into named entities.
+     *
+     * @method encodeNamed
+     * @param {String} text Text to encode.
+     * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+     * @param {Object} entities Optional parameter with entities to use.
+     * @return {String} Entity encoded text.
+     */
+    encodeNamed: function(text, attr, entities) {
+        var t = this;
+        entities = entities || this.namedEntities;
+        return text.replace(attr ? this.attrsCharsRegExp : this.textCharsRegExp, function(chr) {
+            return t.baseEntities[chr] || entities[chr] || chr;
+        });
+    },
+    /**
+     * Returns an encode function based on the name(s) and it's optional entities.
+     *
+     * @method getEncodeFunc
+     * @param {String} name Comma separated list of encoders for example named,numeric.
+     * @param {String} entities Optional parameter with entities to use instead of the built in set.
+     * @return {function} Encode function to be used.
+     */
+    getEncodeFunc: function(name, entities) {
+        entities = this.buildEntitiesLookup(entities) || this.namedEntities;
+        var t = this;
+        function encodeNamedAndNumeric(text, attr) {
+            return text.replace(attr ? t.attrsCharsRegExp : t.textCharsRegExp, function(chr) {
+                return t.baseEntities[chr] || entities[chr] || '&#' + chr.charCodeAt(0) + ';' || chr;
+            });
+        }
+
+        function encodeCustomNamed(text, attr) {
+            return t.encodeNamed(text, attr, entities);
+        }
+        // Replace + with , to be compatible with previous TinyMCE versions
+        name = this.makeMap(name.replace(/\+/g, ','));
+        // Named and numeric encoder
+        if (name.named && name.numeric) {
+            return this.encodeNamedAndNumeric;
+        }
+        // Named encoder
+        if (name.named) {
+            // Custom names
+            if (entities) {
+                return encodeCustomNamed;
+            }
+            return this.encodeNamed;
+        }
+        // Numeric
+        if (name.numeric) {
+            return this.encodeNumeric;
+        }
+        // Raw encoder
+        return this.encodeRaw;
+    },
+    /**
+     * Decodes the specified string, this will replace entities with raw UTF characters.
+     *
+     * @method decode
+     * @param {String} text Text to entity decode.
+     * @return {String} Entity decoded string.
+     */
+    decode: function(text)
+    {
+        var  t = this;
+        return text.replace(this.entityRegExp, function(all, numeric) {
+            if (numeric) {
+                numeric = 'x' === numeric.charAt(0).toLowerCase() ? parseInt(numeric.substr(1), 16) : parseInt(numeric, 10);
+                // Support upper UTF
+                if (numeric > 65535) {
+                    numeric -= 65536;
+                    return String.fromCharCode(55296 + (numeric >> 10), 56320 + (1023 & numeric));
+                }
+                return t.asciiMap[numeric] || String.fromCharCode(numeric);
+            }
+            return t.reverseEntities[all] || t.namedEntities[all] || t.nativeDecode(all);
+        });
+    },
+    nativeDecode : function (text) {
+        return text;
+    },
+    makeMap : function (items, delim, map) {
+               var i;
+               items = items || [];
+               delim = delim || ',';
+               if (typeof items == "string") {
+                       items = items.split(delim);
+               }
+               map = map || {};
+               i = items.length;
+               while (i--) {
+                       map[items[i]] = {};
+               }
+               return map;
+       }
+};
+    
+    
+    
+Roo.htmleditor.TidyEntities.init();
 /**
  * @class Roo.htmleditor.KeyEnter
  * Handle Enter press..
 /**
  * @class Roo.htmleditor.KeyEnter
  * Handle Enter press..
@@ -22306,7 +23569,7 @@ Roo.extend(Roo.htmleditor.BlockFigure, Roo.htmleditor.Block, {
             tag : 'img',
             contenteditable : 'false',
             src : this.image_src,
             tag : 'img',
             contenteditable : 'false',
             src : this.image_src,
-            alt : d.innerText.replace(/\n/g, " "), // removeHTML..
+            alt : d.innerText.replace(/\n/g, " ").replace(/\s+/g, ' ').trim(), // removeHTML and reduce spaces..
             style: {
                 width : 'auto',
                 'max-width': '100%',
             style: {
                 width : 'auto',
                 'max-width': '100%',
@@ -23854,14 +25117,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         st +=  '<style type="text/css">' +
             'IMG { cursor: pointer } ' +
         '</style>';
         st +=  '<style type="text/css">' +
             '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;
         }
         
         
         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>' +
             //<style type="text/css">' +
             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
             //'</style>' +
@@ -23988,7 +25253,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      * @param {String} html The HTML to be cleaned
      * return {String} The cleaned HTML
      */
      * @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
         html = String(html);
         if(html.length > 5){
             if(Roo.isSafari){ // strip safari nonsense
@@ -24017,18 +25283,27 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             var bd = (this.doc.body || this.doc.documentElement);
            
             
             var bd = (this.doc.body || this.doc.documentElement);
            
             
+            var sel = this.win.getSelection();
             
             var div = document.createElement('div');
             div.innerHTML = bd.innerHTML;
             
             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?
            
             if (this.enableBlocks) {
                 new Roo.htmleditor.FilterBlock({ node : div });
             }
             //?? tidy?
+            var tidy = new Roo.htmleditor.TidySerializer({
+                inner:  true
+            });
+            var html  = tidy.serialize(div);
             
             
             
             
-            var html = div.innerHTML;
             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;
             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;
@@ -24167,6 +25442,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
         //ss['background-attachment'] = 'fixed'; // w3c
         dbody.bgProperties = 'fixed'; // ie
         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
         //ss['background-attachment'] = 'fixed'; // w3c
         dbody.bgProperties = 'fixed'; // ie
+        dbody.setAttribute("translate", "no");
+        
         //Roo.DomHelper.applyStyles(dbody, ss);
         Roo.EventManager.on(this.doc, {
              
         //Roo.DomHelper.applyStyles(dbody, ss);
         Roo.EventManager.on(this.doc, {
              
index 3fe2708..7c24529 100644 (file)
@@ -994,9 +994,37 @@ return false;}if(!ps||ps.nodeType!=1){return false;}if(!ps||ps.tagName!='BR'){re
 // Roo/htmleditor/FilterBlock.js
 Roo.htmleditor.FilterBlock=function(A){Roo.apply(this,A);var qa=A.node.querySelectorAll;this.removeAttributes('data-block');this.removeAttributes('contenteditable');this.removeAttributes('id');};Roo.apply(Roo.htmleditor.FilterBlock.prototype,{node:true,removeAttributes:function(A){var ar=this.node.querySelectorAll('*['+A+']');
 for(var i=0;i<ar.length;i++){ar[i].removeAttribute(A);}}});
 // Roo/htmleditor/FilterBlock.js
 Roo.htmleditor.FilterBlock=function(A){Roo.apply(this,A);var qa=A.node.querySelectorAll;this.removeAttributes('data-block');this.removeAttributes('contenteditable');this.removeAttributes('id');};Roo.apply(Roo.htmleditor.FilterBlock.prototype,{node:true,removeAttributes:function(A){var ar=this.node.querySelectorAll('*['+A+']');
 for(var i=0;i<ar.length;i++){ar[i].removeAttribute(A);}}});
-// Roo/htmleditor/Tidy.js
-Roo.htmleditor.Tidy=function(A){Roo.apply(this,A);this.core.doc.body.innerHTML=this.tidy(this.core.doc.body,'');};Roo.htmleditor.Tidy.toString=function(A){return Roo.htmleditor.Tidy.prototype.tidy(A,'');};Roo.htmleditor.Tidy.prototype={tidy:function(A,B){}
-}
+// Roo/htmleditor/TidySerializer.js
+Roo.htmleditor.TidySerializer=function(A){Roo.apply(this,A);this.writer=new Roo.htmleditor.TidyWriter(A);};Roo.htmleditor.TidySerializer.prototype={inner:false,writer:false,serialize:function(A){var B=this.writer;var C=this;this.handlers={3:function(D){B.text(D.nodeValue,D);
+},8:function(D){B.comment(D.nodeValue);},7:function(D){B.pi(D.name,D.nodeValue);},10:function(D){B.doctype(D.nodeValue);},4:function(D){B.cdata(D.nodeValue);},11:function(D){D=D.firstChild;if(!D){return;}while(D){C.walk(D);D=D.nextSibling}}};B.reset();1!=A.nodeType||this.inner?this.handlers[11](A):this.walk(A);
+return B.getContent();},walk:function(A){var B,C,D,i,l,E,F=this.handlers[A.nodeType];if(F){F(A);return;}var G=A.nodeName;var H=A.childNodes.length<1;var I=this.writer;var J=A.attributes;I.start(A.nodeName,J,H,A);if(H){return;}A=A.firstChild;if(!A){I.end(G);
+return;}while(A){this.walk(A);A=A.nextSibling;}I.end(G);}};
+// Roo/htmleditor/TidyWriter.js
+Roo.htmleditor.TidyWriter=function(A){Roo.apply(this,A);this.html=[];this.state=[];this.encode=Roo.htmleditor.TidyEntities.getEncodeFunc(A.entity_encoding||'raw',A.entities);};Roo.htmleditor.TidyWriter.prototype={state:false,indent:'  ',indentstr:'',in_pre:false,in_inline:false,last_inline:false,encode:false,start:function(A,B,C,D){var i,l,E,F;
+var G=this.in_inline||Roo.htmleditor.TidyWriter.inline_elements.indexOf(A)>-1;var H=this.in_pre||Roo.htmleditor.TidyWriter.whitespace_elements.indexOf(A)>-1;var I=C?Roo.htmleditor.TidyWriter.shortend_elements.indexOf(A)>-1:false;var J=A=='BR'?false:G;if(!J&&!this.in_pre&&this.lastElementEndsWS()){i_inline=false;
+}var K=this.indentstr;if(!this.in_pre){if(G){if(A=='BR'){this.addLine();}else if(this.lastElementEndsWS()){this.addLine();}else{K='';}}else{this.addLine();}}else{K='';}this.html.push(K+'<',A.toLowerCase());if(B){for(i=0,l=B.length;i<l;i++){E=B[i];this.html.push(' ',E.name,'="',this.encode(E.value,true),'"');
+}}if(C){if(I){this.html[this.html.length]='/>';}else{this.html[this.html.length]='></'+A.toLowerCase()+'>';}var L=A=='BR'?false:this.in_inline;if(!L&&!this.in_pre){this.addLine();}return;}this.html[this.html.length]='>';this.pushState({indentstr:H?'':(this.indentstr+this.indent),in_pre:H,in_inline:G}
+);if(!G&&!H){this.addLine();}},lastElementEndsWS:function(){var A=this.html.length>0?this.html[this.html.length-1]:false;if(A===false){return true;}return A.match(/\s+$/);},end:function(A){var B;this.popState();var C='';var D=this.in_inline||Roo.htmleditor.TidyWriter.inline_elements.indexOf(A)>-1;
+if(!this.in_pre&&!D){this.addLine();C=this.indentstr;}this.html.push(C+'</',A.toLowerCase(),'>');this.last_inline=D;},text:function(A,B){if(A.length<1){return;}if(this.in_pre){this.html[this.html.length]=A;return;}if(this.in_inline){A=A.replace(/\s+/g,' ');
+if(A!=' '){A=A.replace(/\s+/,' ');if(B.nextSibling&&B.nextSibling.nodeType==1&&B.nextSibling.nodeName=='BR'){A=A.replace(/\s+$/g,'');}if(B.previousSibling&&B.previousSibling.nodeType==1&&B.previousSibling.nodeName=='BR'){A=this.indentstr+A.replace(/^\s+/g,'');
+}if(A.match(/\n/)){A=A.replace(/(?![^\n]{1,64}$)([^\n]{1,64})\s/g,'$1\n'+this.indentstr);A=A.replace(/\n\s+$/,'');}}this.html[this.html.length]=A;return;}var C=this.indentstr;A=A.replace(/\s+/g," ");if(B.previousSibling&&B.previousSibling.nodeType==1&&Roo.htmleditor.TidyWriter.inline_elements.indexOf(B.previousSibling.nodeName)>-1){C='';
+}else{this.addLine();A=A.replace(/^\s+/,'');}if(B.nextSibling&&B.nextSibling.nodeType==1&&Roo.htmleditor.TidyWriter.inline_elements.indexOf(B.nextSibling.nodeName)>-1){}else{A=A.replace(/\s+$/,'');}if(A.length<1){return;}if(!A.match(/\n/)){this.html.push(C+A);
+return;}A=this.indentstr+A.replace(/(?![^\n]{1,64}$)([^\n]{1,64})\s/g,'$1\n'+this.indentstr);A=A.replace(/\s+$/,'');this.html.push(A);},cdata:function(A){this.html.push('<![CDATA[',A,']]>');},comment:function(A){this.html.push('<!--',A,'-->');},pi:function(A,B){B?this.html.push('<?',A,' ',this.encode(B),'?>'):this.html.push('<?',A,'?>');
+this.indent!=''&&this.html.push('\n');},doctype:function(A){this.html.push('<!DOCTYPE',A,'>',this.indent!=''?'\n':'');},reset:function(){this.html.length=0;this.state=[];this.pushState({indentstr:'',in_pre:false,in_inline:false})},getContent:function(){return this.html.join('').replace(/\n$/,'');
+},pushState:function(A){this.state.push(A);Roo.apply(this,A);},popState:function(){if(this.state.length<1){return;}var A={in_pre:false,indentstr:''};this.state.pop();if(this.state.length>0){A=this.state[this.state.length-1];}Roo.apply(this,A);},addLine:function(){if(this.html.length<1){return;
+}var A=this.html[this.html.length-1];if(A.length>0&&'\n'!==A){this.html.push('\n');}}};Roo.htmleditor.TidyWriter.inline_elements=['SPAN','STRONG','B','EM','I','FONT','STRIKE','U','VAR','CITE','DFN','CODE','MARK','Q','SUP','SUB','SAMP'];Roo.htmleditor.TidyWriter.shortend_elements=['AREA','BASE','BASEFONT','BR','COL','FRAME','HR','IMG','INPUT','ISINDEX','LINK','','META','PARAM','EMBED','SOURCE','WBR','TRACK'];
+Roo.htmleditor.TidyWriter.whitespace_elements=['PRE','SCRIPT','NOSCRIPT','STYLE','TEXTAREA','VIDEO','AUDIO','IFRAME','OBJECT','CODE'];
+// Roo/htmleditor/TidyEntities.js
+Roo.htmleditor.TidyEntities={init:function(){this.namedEntities=this.buildEntitiesLookup(this.namedEntitiesData,32);},buildEntitiesLookup:function(A,B){var i,C,D,E={};if(!A){return {};}A=typeof(A)=='string'?A.split(','):A;B=B||10;for(i=0;i<A.length;i+=2){C=String.fromCharCode(parseInt(A[i],B));
+if(!this.baseEntities[C]){D='&'+A[i+1]+';';E[C]=D;E[D]=C;}}return E;},asciiMap:{128:'€',130:'‚',131:'ƒ',132:'„',133:'…',134:'†',135:'‡',136:'ˆ',137:'‰',138:'Š',139:'‹',140:'Œ',142:'Ž',145:'‘',146:'’',147:'“',148:'”',149:'•',150:'–',151:'—',152:'˜',153:'™',154:'š',155:'›',156:'œ',158:'ž',159:'Ÿ'}
+,baseEntities:{'"':'&quot;','\'':'&#39;','<':'&lt;','>':'&gt;','&':'&amp;','`':'&#96;'},reverseEntities:{'&lt;':'<','&gt;':'>','&amp;':'&','&quot;':'"','&apos;':'\''},attrsCharsRegExp:/[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,textCharsRegExp:/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,rawCharsRegExp:/[<>&\"\']/g,entityRegExp:/&#([a-z0-9]+);?|&([a-z0-9]+);/gi,namedEntities:false,namedEntitiesData:['50','nbsp','51','iexcl','52','cent','53','pound','54','curren','55','yen','56','brvbar','57','sect','58','uml','59','copy','5a','ordf','5b','laquo','5c','not','5d','shy','5e','reg','5f','macr','5g','deg','5h','plusmn','5i','sup2','5j','sup3','5k','acute','5l','micro','5m','para','5n','middot','5o','cedil','5p','sup1','5q','ordm','5r','raquo','5s','frac14','5t','frac12','5u','frac34','5v','iquest','60','Agrave','61','Aacute','62','Acirc','63','Atilde','64','Auml','65','Aring','66','AElig','67','Ccedil','68','Egrave','69','Eacute','6a','Ecirc','6b','Euml','6c','Igrave','6d','Iacute','6e','Icirc','6f','Iuml','6g','ETH','6h','Ntilde','6i','Ograve','6j','Oacute','6k','Ocirc','6l','Otilde','6m','Ouml','6n','times','6o','Oslash','6p','Ugrave','6q','Uacute','6r','Ucirc','6s','Uuml','6t','Yacute','6u','THORN','6v','szlig','70','agrave','71','aacute','72','acirc','73','atilde','74','auml','75','aring','76','aelig','77','ccedil','78','egrave','79','eacute','7a','ecirc','7b','euml','7c','igrave','7d','iacute','7e','icirc','7f','iuml','7g','eth','7h','ntilde','7i','ograve','7j','oacute','7k','ocirc','7l','otilde','7m','ouml','7n','divide','7o','oslash','7p','ugrave','7q','uacute','7r','ucirc','7s','uuml','7t','yacute','7u','thorn','7v','yuml','ci','fnof','sh','Alpha','si','Beta','sj','Gamma','sk','Delta','sl','Epsilon','sm','Zeta','sn','Eta','so','Theta','sp','Iota','sq','Kappa','sr','Lambda','ss','Mu','st','Nu','su','Xi','sv','Omicron','t0','Pi','t1','Rho','t3','Sigma','t4','Tau','t5','Upsilon','t6','Phi','t7','Chi','t8','Psi','t9','Omega','th','alpha','ti','beta','tj','gamma','tk','delta','tl','epsilon','tm','zeta','tn','eta','to','theta','tp','iota','tq','kappa','tr','lambda','ts','mu','tt','nu','tu','xi','tv','omicron','u0','pi','u1','rho','u2','sigmaf','u3','sigma','u4','tau','u5','upsilon','u6','phi','u7','chi','u8','psi','u9','omega','uh','thetasym','ui','upsih','um','piv','812','bull','816','hellip','81i','prime','81j','Prime','81u','oline','824','frasl','88o','weierp','88h','image','88s','real','892','trade','89l','alefsym','8cg','larr','8ch','uarr','8ci','rarr','8cj','darr','8ck','harr','8dl','crarr','8eg','lArr','8eh','uArr','8ei','rArr','8ej','dArr','8ek','hArr','8g0','forall','8g2','part','8g3','exist','8g5','empty','8g7','nabla','8g8','isin','8g9','notin','8gb','ni','8gf','prod','8gh','sum','8gi','minus','8gn','lowast','8gq','radic','8gt','prop','8gu','infin','8h0','ang','8h7','and','8h8','or','8h9','cap','8ha','cup','8hb','int','8hk','there4','8hs','sim','8i5','cong','8i8','asymp','8j0','ne','8j1','equiv','8j4','le','8j5','ge','8k2','sub','8k3','sup','8k4','nsub','8k6','sube','8k7','supe','8kl','oplus','8kn','otimes','8l5','perp','8m5','sdot','8o8','lceil','8o9','rceil','8oa','lfloor','8ob','rfloor','8p9','lang','8pa','rang','9ea','loz','9j0','spades','9j3','clubs','9j5','hearts','9j6','diams','ai','OElig','aj','oelig','b0','Scaron','b1','scaron','bo','Yuml','m6','circ','ms','tilde','802','ensp','803','emsp','809','thinsp','80c','zwnj','80d','zwj','80e','lrm','80f','rlm','80j','ndash','80k','mdash','80o','lsquo','80p','rsquo','80q','sbquo','80s','ldquo','80t','rdquo','80u','bdquo','810','dagger','811','Dagger','81g','permil','81p','lsaquo','81q','rsaquo','85c','euro'],encodeRaw:function(A,B){var t=this;
+return A.replace(B?this.attrsCharsRegExp:this.textCharsRegExp,function(C){return t.baseEntities[C]||C;});},encodeAllRaw:function(A){var t=this;return (''+A).replace(this.rawCharsRegExp,function(B){return t.baseEntities[B]||B;});},encodeNumeric:function(A,B){var t=this;
+return A.replace(B?this.attrsCharsRegExp:this.textCharsRegExp,function(C){if(C.length>1){return '&#'+(1024*(C.charCodeAt(0)-55296)+(C.charCodeAt(1)-56320)+65536)+';';}return t.baseEntities[C]||'&#'+C.charCodeAt(0)+';';});},encodeNamed:function(A,B,C){var t=this;
+C=C||this.namedEntities;return A.replace(B?this.attrsCharsRegExp:this.textCharsRegExp,function(D){return t.baseEntities[D]||C[D]||D;});},getEncodeFunc:function(A,B){B=this.buildEntitiesLookup(B)||this.namedEntities;var t=this;function encodeNamedAndNumeric(C,D){return C.replace(D?t.attrsCharsRegExp:t.textCharsRegExp,function(E){return t.baseEntities[E]||B[E]||'&#'+E.charCodeAt(0)+';'||E;
+});}function encodeCustomNamed(C,D){return t.encodeNamed(C,D,B);}A=this.makeMap(A.replace(/\+/g,','));if(A.named&&A.numeric){return this.encodeNamedAndNumeric;}if(A.named){if(B){return encodeCustomNamed;}return this.encodeNamed;}if(A.numeric){return this.encodeNumeric;
+}return this.encodeRaw;},decode:function(A){var t=this;return A.replace(this.entityRegExp,function(B,C){if(C){C='x'===C.charAt(0).toLowerCase()?parseInt(C.substr(1),16):parseInt(C,10);if(C>65535){C-=65536;return String.fromCharCode(55296+(C>>10),56320+(1023&C));
+}return t.asciiMap[C]||String.fromCharCode(C);}return t.reverseEntities[B]||t.namedEntities[B]||t.nativeDecode(B);});},nativeDecode:function(A){return A;},makeMap:function(A,B,C){var i;A=A||[];B=B||',';if(typeof A=="string"){A=A.split(B);}C=C||{};i=A.length;
+while(i--){C[A[i]]={};}return C;}};Roo.htmleditor.TidyEntities.init();
 // Roo/htmleditor/KeyEnter.js
 Roo.htmleditor.KeyEnter=function(A){Roo.apply(this,A);Roo.get(this.core.doc.body).on('keypress',this.keypress,this);};Roo.htmleditor.KeyEnter.prototype={core:false,keypress:function(e){if(e.charCode!=13&&e.charCode!=10){Roo.log([e.charCode,e]);return true;
 }e.preventDefault();var A=this.core.doc;var B=this.core.getSelection();var C=B.getRangeAt(0);var n=C.commonAncestorContainer;var pc=C.closest(['ol','ul']);var D=C.closest('li');if(!pc||e.ctrlKey){B.insertNode('br','after');this.core.undoManager.addEvent();
 // Roo/htmleditor/KeyEnter.js
 Roo.htmleditor.KeyEnter=function(A){Roo.apply(this,A);Roo.get(this.core.doc.body).on('keypress',this.keypress,this);};Roo.htmleditor.KeyEnter.prototype={core:false,keypress:function(e){if(e.charCode!=13&&e.charCode!=10){Roo.log([e.charCode,e]);return true;
 }e.preventDefault();var A=this.core.doc;var B=this.core.getSelection();var C=B.getRangeAt(0);var n=C.commonAncestorContainer;var pc=C.closest(['ol','ul']);var D=C.closest('li');if(!pc||e.ctrlKey){B.insertNode('br','after');this.core.undoManager.addEvent();
@@ -1017,7 +1045,7 @@ var b=B();b.image_src=this.getValue();b.updateElement();D();A.editorcore.onEdito
 var b=B();b.width=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['auto'],['50%'],['100%']],fields:['val'],xns:Roo.data}},{xtype:'TextItem',text:"Align: ",xns:C.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:70,name:'align',listeners:{select:function(F,r,G){A.editorcore.selectNode(A.tb.selectedNode);
 var b=B();b.align=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['left'],['right'],['center']],fields:['val'],xns:Roo.data}},{xtype:'Button',text:'Hide Caption',name:'caption_display',pressed:false,enableToggle:true,setValue:function(v){this.toggle(v=='block'?false:true);
 },listeners:{toggle:function(F,G){var b=B();b.caption_display=b.caption_display=='block'?'none':'block';this.setText(b.caption_display=='block'?"Hide Caption":"Show Caption");b.updateElement();D();A.editorcore.selectNode(A.tb.selectedNode);A.editorcore.onEditorEvent();
 var b=B();b.width=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['auto'],['50%'],['100%']],fields:['val'],xns:Roo.data}},{xtype:'TextItem',text:"Align: ",xns:C.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:70,name:'align',listeners:{select:function(F,r,G){A.editorcore.selectNode(A.tb.selectedNode);
 var b=B();b.align=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['left'],['right'],['center']],fields:['val'],xns:Roo.data}},{xtype:'Button',text:'Hide Caption',name:'caption_display',pressed:false,enableToggle:true,setValue:function(v){this.toggle(v=='block'?false:true);
 },listeners:{toggle:function(F,G){var b=B();b.caption_display=b.caption_display=='block'?'none':'block';this.setText(b.caption_display=='block'?"Hide Caption":"Show Caption");b.updateElement();D();A.editorcore.selectNode(A.tb.selectedNode);A.editorcore.onEditorEvent();
-}},xns:C.Toolbar}];},toObject:function(){var d=document.createElement('div');d.innerHTML=this.caption;var m=this.width=='50%'&&this.align=='center'?'0 auto':0;var A={tag:'img',contenteditable:'false',src:this.image_src,alt:d.innerText.replace(/\n/g," "),style:{width:'auto','max-width':'100%',margin:'0px'}
+}},xns:C.Toolbar}];},toObject:function(){var d=document.createElement('div');d.innerHTML=this.caption;var m=this.width=='50%'&&this.align=='center'?'0 auto':0;var A={tag:'img',contenteditable:'false',src:this.image_src,alt:d.innerText.replace(/\n/g," ").replace(/\s+/g,' ').trim(),style:{width:'auto','max-width':'100%',margin:'0px'}
 };if(this.href.length>0){A={tag:'a',href:this.href,contenteditable:'true',cn:[A]};}if(this.video_url.length>0){A={tag:'div',cls:this.cls,frameborder:0,allowfullscreen:true,width:420,height:315,src:this.video_url,cn:[A]};}return {tag:'figure','data-block':'Figure',contenteditable:'false',style:{display:'block',float:this.align,'max-width':this.width,width:'auto',margin:m,padding:'10px'}
 ,align:this.align,cn:[A,{tag:'figcaption',contenteditable:true,style:{'text-align':'left','margin-top':'16px','font-size':'16px','line-height':'24px','font-style':'italic',display:this.caption_display},cls:this.cls.length>0?(this.cls+'-thumbnail'):'',html:this.caption}
 ]};},readElement:function(A){this.video_url=this.getVal(A,'div','src');this.cls=this.getVal(A,'div','class');this.href=this.getVal(A,'a','href');this.image_src=this.getVal(A,'img','src');this.align=this.getVal(A,'figure','align');this.caption=this.getVal(A,'figcaption','html');
 };if(this.href.length>0){A={tag:'a',href:this.href,contenteditable:'true',cn:[A]};}if(this.video_url.length>0){A={tag:'div',cls:this.cls,frameborder:0,allowfullscreen:true,width:420,height:315,src:this.video_url,cn:[A]};}return {tag:'figure','data-block':'Figure',contenteditable:'false',style:{display:'block',float:this.align,'max-width':this.width,width:'auto',margin:m,padding:'10px'}
 ,align:this.align,cn:[A,{tag:'figcaption',contenteditable:true,style:{'text-align':'left','margin-top':'16px','font-size':'16px','line-height':'24px','font-style':'italic',display:this.caption_display},cls:this.cls.length>0?(this.cls+'-thumbnail'):'',html:this.caption}
 ]};},readElement:function(A){this.video_url=this.getVal(A,'div','src');this.cls=this.getVal(A,'div','class');this.href=this.getVal(A,'a','href');this.image_src=this.getVal(A,'img','src');this.align=this.getVal(A,'figure','align');this.caption=this.getVal(A,'figcaption','html');
@@ -1077,24 +1105,24 @@ if(c.col!=this.cellData.col){A[i][this.cellData.col].colspan--;}else if(c.colspa
 Roo.HtmlEditorCore=function(A){Roo.HtmlEditorCore.superclass.constructor.call(this,A);this.addEvents({initialize:true,activate:true,beforesync:true,beforepush:true,sync:true,push:true,editorevent:true});this.applyBlacklists();};Roo.extend(Roo.HtmlEditorCore,Roo.Component,{owner:false,resizable:false,height:300,width:500,autoClean:true,enableBlocks:true,stylesheets:false,language:'en',allowComments:false,frameId:false,validationEvent:false,deferHeight:true,initialized:false,activated:false,sourceEditMode:false,onFocus:Roo.emptyFn,iframePad:3,hideMode:'offsets',clearUp:true,black:false,white:false,bodyCls:'',undoManager:false,getDocMarkup:function(){var st='';
 if(this.stylesheets===false){Roo.get(document.head).select('style').each(function(B){st+=B.dom.outerHTML||new XMLSerializer().serializeToString(B.dom);});Roo.get(document.head).select('link').each(function(B){st+=B.dom.outerHTML||new XMLSerializer().serializeToString(B.dom);
 });}else if(!this.stylesheets.length){st='<style type="text/css">'+'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}'+'</style>';}else{for(var i in this.stylesheets){if(typeof(this.stylesheets[i])!='string'){continue;}st+='<link rel="stylesheet" href="'+this.stylesheets[i]+'" type="text/css">';
 Roo.HtmlEditorCore=function(A){Roo.HtmlEditorCore.superclass.constructor.call(this,A);this.addEvents({initialize:true,activate:true,beforesync:true,beforepush:true,sync:true,push:true,editorevent:true});this.applyBlacklists();};Roo.extend(Roo.HtmlEditorCore,Roo.Component,{owner:false,resizable:false,height:300,width:500,autoClean:true,enableBlocks:true,stylesheets:false,language:'en',allowComments:false,frameId:false,validationEvent:false,deferHeight:true,initialized:false,activated:false,sourceEditMode:false,onFocus:Roo.emptyFn,iframePad:3,hideMode:'offsets',clearUp:true,black:false,white:false,bodyCls:'',undoManager:false,getDocMarkup:function(){var st='';
 if(this.stylesheets===false){Roo.get(document.head).select('style').each(function(B){st+=B.dom.outerHTML||new XMLSerializer().serializeToString(B.dom);});Roo.get(document.head).select('link').each(function(B){st+=B.dom.outerHTML||new XMLSerializer().serializeToString(B.dom);
 });}else if(!this.stylesheets.length){st='<style type="text/css">'+'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}'+'</style>';}else{for(var i in this.stylesheets){if(typeof(this.stylesheets[i])!='string'){continue;}st+='<link rel="stylesheet" href="'+this.stylesheets[i]+'" type="text/css">';
-}}st+='<style type="text/css">'+'IMG { cursor: pointer } '+'</style>';var A='roo-htmleditor-body';if(this.bodyCls.length){A+=' '+this.bodyCls;}return '<html><head>'+st+' </head><body contenteditable="true" data-enable-grammerly="true" class="'+A+'"></body></html>';
+}}st+='<style type="text/css">'+'IMG { cursor: pointer } '+'</style>';st+='<meta name="google" content="notranslate">';var A='notranslate roo-htmleditor-body';if(this.bodyCls.length){A+=' '+this.bodyCls;}return '<html  class="notranslate" translate="no"><head>'+st+' </head><body contenteditable="true" data-enable-grammerly="true" class="'+A+'"></body></html>';
 },onRender:function(ct,A){var _t=this;this.el=this.owner.inputEl?this.owner.inputEl():this.owner.el;this.el.dom.style.border='0 none';this.el.dom.setAttribute('tabIndex',-1);this.el.addClass('x-hidden hide');if(Roo.isIE){this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')}
 this.frameId=Roo.id();var B=this.owner.wrap.createChild({tag:'iframe',cls:'form-control',id:this.frameId,name:this.frameId,frameBorder:'no','src':Roo.SSL_SECURE_URL?Roo.SSL_SECURE_URL:"javascript:false"},this.el);this.iframe=B.dom;this.assignDocWin();this.doc.designMode='on';
 this.doc.open();this.doc.write(this.getDocMarkup());this.doc.close();var C={run:function(){this.assignDocWin();if(this.doc.body||this.doc.readyState=='complete'){try{this.doc.designMode="on";}catch(e){return;}Roo.TaskMgr.stop(C);this.initEditor.defer(10,this);
 }},interval:10,duration:10000,scope:this};Roo.TaskMgr.start(C);},onResize:function(w,h){Roo.log('resize: '+w+','+h);if(!this.iframe){return;}if(typeof w=='number'){this.iframe.style.width=w+'px';}if(typeof h=='number'){this.iframe.style.height=h+'px';if(this.doc){(this.doc.body||this.doc.documentElement).style.height=(h-(this.iframePad*2))+'px';
 }}},toggleSourceEdit:function(A){this.sourceEditMode=A===true;if(this.sourceEditMode){Roo.get(this.iframe).addClass(['x-hidden','hide','d-none']);}else{Roo.get(this.iframe).removeClass(['x-hidden','hide','d-none']);this.deferFocus();}},cleanHtml:function(A){A=String(A);
 if(A.length>5){if(Roo.isSafari){A=A.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi,'');}}if(A=='&nbsp;'){A='';}return A;},syncValue:function(){if(this.initialized){this.undoManager.addEvent();var bd=(this.doc.body||this.doc.documentElement);
 },onRender:function(ct,A){var _t=this;this.el=this.owner.inputEl?this.owner.inputEl():this.owner.el;this.el.dom.style.border='0 none';this.el.dom.setAttribute('tabIndex',-1);this.el.addClass('x-hidden hide');if(Roo.isIE){this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')}
 this.frameId=Roo.id();var B=this.owner.wrap.createChild({tag:'iframe',cls:'form-control',id:this.frameId,name:this.frameId,frameBorder:'no','src':Roo.SSL_SECURE_URL?Roo.SSL_SECURE_URL:"javascript:false"},this.el);this.iframe=B.dom;this.assignDocWin();this.doc.designMode='on';
 this.doc.open();this.doc.write(this.getDocMarkup());this.doc.close();var C={run:function(){this.assignDocWin();if(this.doc.body||this.doc.readyState=='complete'){try{this.doc.designMode="on";}catch(e){return;}Roo.TaskMgr.stop(C);this.initEditor.defer(10,this);
 }},interval:10,duration:10000,scope:this};Roo.TaskMgr.start(C);},onResize:function(w,h){Roo.log('resize: '+w+','+h);if(!this.iframe){return;}if(typeof w=='number'){this.iframe.style.width=w+'px';}if(typeof h=='number'){this.iframe.style.height=h+'px';if(this.doc){(this.doc.body||this.doc.documentElement).style.height=(h-(this.iframePad*2))+'px';
 }}},toggleSourceEdit:function(A){this.sourceEditMode=A===true;if(this.sourceEditMode){Roo.get(this.iframe).addClass(['x-hidden','hide','d-none']);}else{Roo.get(this.iframe).removeClass(['x-hidden','hide','d-none']);this.deferFocus();}},cleanHtml:function(A){A=String(A);
 if(A.length>5){if(Roo.isSafari){A=A.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi,'');}}if(A=='&nbsp;'){A='';}return A;},syncValue:function(){if(this.initialized){this.undoManager.addEvent();var bd=(this.doc.body||this.doc.documentElement);
-var A=document.createElement('div');A.innerHTML=bd.innerHTML;if(this.enableBlocks){new Roo.htmleditor.FilterBlock({node:A});}var B=A.innerHTML;if(Roo.isSafari){var bs=bd.getAttribute('style');var m=bs?bs.match(/text-align:(.*?);/i):false;if(m&&m[1]){B='<div style="'+m[0]+'">'+B+'</div>';
-}}B=this.cleanHtml(B);B=B.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g,function(C){var cc=C.charCodeAt();if(C.length==2){var D=C.charCodeAt(0)-0xD800;var E=C.charCodeAt(1)-0xDC00;cc=(D*0x400)+E+0x10000;}else if((cc>=0x4E00&&cc<0xA000)||(cc>=0x3400&&cc<0x4E00)||(cc>=0xf900&&cc<0xfb00)){return C;
-}return "&#"+cc+";";});if(this.owner.fireEvent('beforesync',this,B)!==false){this.el.dom.value=B;this.owner.fireEvent('sync',this,B);}}},pushValue:function(){if(this.initialized){var v=this.el.dom.value.trim();if(this.owner.fireEvent('beforepush',this,v)!==false){var d=(this.doc.body||this.doc.documentElement);
-d.innerHTML=v;this.el.dom.value=d.innerHTML;this.owner.fireEvent('push',this,v);}if(this.autoClean){new Roo.htmleditor.FilterParagraph({node:this.doc.body});new Roo.htmleditor.FilterSpan({node:this.doc.body});}Roo.htmleditor.Block.initAll(this.doc.body);this.updateLanguage();
-var lc=this.doc.body.lastChild;if(lc&&lc.nodeType==1&&lc.getAttribute("contenteditable")=="false"){this.doc.body.appendChild(this.doc.createElement('br'));}}},deferFocus:function(){this.focus.defer(10,this);},focus:function(){if(this.win&&!this.sourceEditMode){this.win.focus();
-}else{this.el.focus();}},assignDocWin:function(){var A=this.iframe;if(Roo.isIE){this.doc=A.contentWindow.document;this.win=A.contentWindow;}else{if(!Roo.get(this.frameId)&&!A.contentDocument){return;}this.doc=(A.contentDocument||Roo.get(this.frameId).dom.document);
-this.win=(A.contentWindow||Roo.get(this.frameId).dom.contentWindow);}},initEditor:function(){this.assignDocWin();this.doc.designMode="on";this.doc.open();this.doc.write(this.getDocMarkup());this.doc.close();var A=(this.doc.body||this.doc.documentElement);
-A.bgProperties='fixed';Roo.EventManager.on(this.doc,{'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);}if(Roo.isIE||Roo.isSafari||Roo.isOpera){Roo.EventManager.on(this.doc,'keydown',this.fixKeys,this);}this.initialized=true;new Roo.htmleditor.KeyEnter({core:this});this.owner.fireEvent('initialize',this);
-this.pushValue();},onPasteEvent:function(e,v){var cd=(e.browserEvent.clipboardData||window.clipboardData);if(cd.files.length>0){var A=(window.createObjectURL&&window)||(window.URL&&URL.revokeObjectURL&&URL)||(window.webkitURL&&webkitURL);var B=A.createObjectURL(cd.files[0]);
-this.insertAtCursor('<img src=" + url + ">');return false;}var C=cd.getData('text/html');var D=new Roo.rtf.Parser(cd.getData('text/rtf'));var E=D.doc?D.doc.getElementsByType('pict'):[];Roo.log(E);E=E.filter(function(g){return !g.path.match(/^rtf\/(head|pgdsctbl|listtable)/);
+var A=this.win.getSelection();var B=document.createElement('div');B.innerHTML=bd.innerHTML;var C=B.getElementsByClassName('gtx-trans-icon');if(C.length>0){var rm=C.item(0).parentNode;rm.parentNode.removeChild(rm);}if(this.enableBlocks){new Roo.htmleditor.FilterBlock({node:B}
+);}var D=new Roo.htmleditor.TidySerializer({inner:true});var E=D.serialize(B);if(Roo.isSafari){var bs=bd.getAttribute('style');var m=bs?bs.match(/text-align:(.*?);/i):false;if(m&&m[1]){E='<div style="'+m[0]+'">'+E+'</div>';}}E=this.cleanHtml(E);E=E.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g,function(F){var cc=F.charCodeAt();
+if(F.length==2){var G=F.charCodeAt(0)-0xD800;var H=F.charCodeAt(1)-0xDC00;cc=(G*0x400)+H+0x10000;}else if((cc>=0x4E00&&cc<0xA000)||(cc>=0x3400&&cc<0x4E00)||(cc>=0xf900&&cc<0xfb00)){return F;}return "&#"+cc+";";});if(this.owner.fireEvent('beforesync',this,E)!==false){this.el.dom.value=E;
+this.owner.fireEvent('sync',this,E);}}},pushValue:function(){if(this.initialized){var v=this.el.dom.value.trim();if(this.owner.fireEvent('beforepush',this,v)!==false){var d=(this.doc.body||this.doc.documentElement);d.innerHTML=v;this.el.dom.value=d.innerHTML;
+this.owner.fireEvent('push',this,v);}if(this.autoClean){new Roo.htmleditor.FilterParagraph({node:this.doc.body});new Roo.htmleditor.FilterSpan({node:this.doc.body});}Roo.htmleditor.Block.initAll(this.doc.body);this.updateLanguage();var lc=this.doc.body.lastChild;
+if(lc&&lc.nodeType==1&&lc.getAttribute("contenteditable")=="false"){this.doc.body.appendChild(this.doc.createElement('br'));}}},deferFocus:function(){this.focus.defer(10,this);},focus:function(){if(this.win&&!this.sourceEditMode){this.win.focus();}else{this.el.focus();
+}},assignDocWin:function(){var A=this.iframe;if(Roo.isIE){this.doc=A.contentWindow.document;this.win=A.contentWindow;}else{if(!Roo.get(this.frameId)&&!A.contentDocument){return;}this.doc=(A.contentDocument||Roo.get(this.frameId).dom.document);this.win=(A.contentWindow||Roo.get(this.frameId).dom.contentWindow);
+}},initEditor:function(){this.assignDocWin();this.doc.designMode="on";this.doc.open();this.doc.write(this.getDocMarkup());this.doc.close();var A=(this.doc.body||this.doc.documentElement);A.bgProperties='fixed';A.setAttribute("translate","no");Roo.EventManager.on(this.doc,{'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);}if(Roo.isIE||Roo.isSafari||Roo.isOpera){Roo.EventManager.on(this.doc,'keydown',this.fixKeys,this);}this.initialized=true;
+new Roo.htmleditor.KeyEnter({core:this});this.owner.fireEvent('initialize',this);this.pushValue();},onPasteEvent:function(e,v){var cd=(e.browserEvent.clipboardData||window.clipboardData);if(cd.files.length>0){var A=(window.createObjectURL&&window)||(window.URL&&URL.revokeObjectURL&&URL)||(window.webkitURL&&webkitURL);
+var B=A.createObjectURL(cd.files[0]);this.insertAtCursor('<img src=" + url + ">');return false;}var C=cd.getData('text/html');var D=new Roo.rtf.Parser(cd.getData('text/rtf'));var E=D.doc?D.doc.getElementsByType('pict'):[];Roo.log(E);E=E.filter(function(g){return !g.path.match(/^rtf\/(head|pgdsctbl|listtable)/);
 }).map(function(g){return g.toDataURL();});C=this.cleanWordChars(C);var d=(new DOMParser().parseFromString(C,'text/html')).body;var sn=this.getParentElement();if(d.getElementsByTagName('table').length&&sn&&sn.closest('table')){e.preventDefault();this.insertAtCursor("You can not nest tables");
 return false;}if(E.length>0){Roo.each(d.getElementsByTagName('img'),function(F,i){F.setAttribute('src',E[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});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(F){if(F.closest('figure')){return;
 }).map(function(g){return g.toDataURL();});C=this.cleanWordChars(C);var d=(new DOMParser().parseFromString(C,'text/html')).body;var sn=this.getParentElement();if(d.getElementsByTagName('table').length&&sn&&sn.closest('table')){e.preventDefault();this.insertAtCursor("You can not nest tables");
 return false;}if(E.length>0){Roo.each(d.getElementsByTagName('img'),function(F,i){F.setAttribute('src',E[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});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(F){if(F.closest('figure')){return;