fix #6962 - new editor
authorAlan <alan@roojs.com>
Tue, 22 Feb 2022 07:15:05 +0000 (15:15 +0800)
committerAlan <alan@roojs.com>
Tue, 22 Feb 2022 07:15:05 +0000 (15:15 +0800)
roojs-all.js
roojs-bootstrap-debug.js
roojs-bootstrap.js
roojs-core-debug.js
roojs-core.js
roojs-debug.js
roojs-ui-debug.js
roojs-ui.js

index fbcb5e0..da9b22b 100644 (file)
@@ -209,26 +209,6 @@ i<J;++i){H[i]=[G[0]+H[i][0],G[1]+H[i][1]];}}this.runtimeAttributes[E]=[G];if(H.l
 var id=el.id||el.tagName;return ("Scroll "+id);};B.doMethod=function(C,D,E){var F=null;if(C=='scroll'){F=[this.method(this.currentFrame,D[0],E[0]-D[0],this.totalFrames),this.method(this.currentFrame,D[1],E[1]-D[1],this.totalFrames)];}else{F=A.doMethod.call(this,C,D,E);
 }return F;};B.getAttribute=function(C){var D=null;var el=this.getEl();if(C=='scroll'){D=[el.scrollLeft,el.scrollTop];}else{D=A.getAttribute.call(this,C);}return D;};B.setAttribute=function(C,D,E){var el=this.getEl();if(C=='scroll'){el.scrollLeft=D[0];el.scrollTop=D[1];
 }else{A.setAttribute.call(this,C,D,E);}};})();
 var id=el.id||el.tagName;return ("Scroll "+id);};B.doMethod=function(C,D,E){var F=null;if(C=='scroll'){F=[this.method(this.currentFrame,D[0],E[0]-D[0],this.totalFrames),this.method(this.currentFrame,D[1],E[1]-D[1],this.totalFrames)];}else{F=A.doMethod.call(this,C,D,E);
 }return F;};B.getAttribute=function(C){var D=null;var el=this.getEl();if(C=='scroll'){D=[el.scrollLeft,el.scrollTop];}else{D=A.getAttribute.call(this,C);}return D;};B.setAttribute=function(C,D,E){var el=this.getEl();if(C=='scroll'){el.scrollLeft=D[0];el.scrollTop=D[1];
 }else{A.setAttribute.call(this,C,D,E);}};})();
-// Roo/lib/UndoManager.js
-Roo.lib.UndoManager=function(A,B){this.stack=[];this.limit=A;this.scope=B;this.fireEvent=typeof CustomEvent!='undefined'&&B&&B.dispatchEvent;if(this.fireEvent){this.bindEvents();}this.reset();};Roo.lib.UndoManager.prototype={limit:false,stack:false,scope:false,fireEvent:false,position:0,length:0,transact:function(A,B){if(arguments.length<2){throw new TypeError('Not enough arguments to UndoManager.transact.');
-}A.execute();this.stack.splice(0,this.position);if(B&&this.length){this.stack[0].push(A);}else{this.stack.unshift([A]);}this.position=0;if(this.limit&&this.stack.length>this.limit){this.length=this.stack.length=this.limit;}else{this.length=this.stack.length;
-}if(this.fireEvent){this.scope.dispatchEvent(new CustomEvent('DOMTransaction',{detail:{transactions:this.stack[0].slice()},bubbles:true,cancelable:false}));}},undo:function(){if(this.position<this.length){for(var i=this.stack[this.position].length-1;i>=0;
-i--){this.stack[this.position][i].undo();}this.position++;if(this.fireEvent){this.scope.dispatchEvent(new CustomEvent('undo',{detail:{transactions:this.stack[this.position-1].slice()},bubbles:true,cancelable:false}));}}},redo:function(){if(this.position>0){for(var i=0,n=this.stack[this.position-1].length;
-i<n;i++){this.stack[this.position-1][i].redo();}this.position--;if(this.fireEvent){this.scope.dispatchEvent(new CustomEvent('redo',{detail:{transactions:this.stack[this.position].slice()},bubbles:true,cancelable:false}));}}},item:function(A){if(A>=0&&A<this.length){return this.stack[A].slice();
-}return null;},clearUndo:function(){this.stack.length=this.length=this.position;},clearRedo:function(){this.stack.splice(0,this.position);this.position=0;this.length=this.stack.length;},reset:function(){this.stack=[];this.position=0;this.length=0;this.current_html=this.scope.innerHTML;
-if(this.timer!==false){clearTimeout(this.timer);}this.timer=false;this.merge=false;this.addEvent();},current_html:'',timer:false,merge:false,bindEvents:function(){var el=this.scope;el.undoManager=this;this.scope.addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.keyCode===90){if(e.shiftKey){el.undoManager.redo();
-}else{el.undoManager.undo();}e.preventDefault();}});this.scope.addEventListener('keyup',function(e){if((e.ctrlKey||e.metaKey)&&e.keyCode===90){e.preventDefault();}});var t=this;el.addEventListener('input',function(e){if(el.innerHTML==t.current_html){return;
-}if(t.timer!==false){clearTimeout(t.timer);t.timer=false;}t.timer=setTimeout(function(){t.merge=false;},1000);t.addEvent(t.merge);t.merge=true;});},addEvent:function(A){A=typeof(A)=='undefined'?false:A;this.scope.undoManager.transact({scope:this.scope,oldHTML:this.current_html,newHTML:this.scope.innerHTML,execute:function(){}
-,undo:function(){this.scope.innerHTML=this.current_html=this.oldHTML;},redo:function(){this.scope.innerHTML=this.current_html=this.newHTML;}},false);this.merge=A;this.current_html=this.scope.innerHTML;}};
-// Roo/lib/Range.js
-Roo.lib.Range=function(){};Roo.lib.Range.wrap=function(r){return Roo.apply(r,Roo.lib.Range.prototype);};Roo.apply(Roo.lib.Range.prototype,{closest:function(A){if(typeof(A)!='string'){for(var i=0;i<A.length;i++){var r=this.closest(A[i]);if(r!==false){return r;
-}}return false;}A=A.toLowerCase();var n=this.commonAncestorContainer;while(n.nodeType!=1){n=n.parentNode;}if(n.nodeName.toLowerCase()==A){return n;}if(n.nodeName.toLowerCase()=='body'){return false;}return n.closest(A)||false;},cloneRange:function(){return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
-}});
-// Roo/lib/Selection.js
-Roo.lib.Selection=function(){};Roo.lib.Selection.wrap=function(r,A){Roo.apply(r,Roo.lib.Selection.prototype);r.ownerDocument=A;return r;};Roo.apply(Roo.lib.Selection.prototype,{ownerDocument:false,getRangeAt:function(n){return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
-},insertNode:function(A,B){if(typeof(A)=='string'){A=this.ownerDocument.createElement(A);if(B=='in'){A.innerHTML='&nbsp;';}}var C=this.getRangeAt(0);if(this.type!='Caret'){C.deleteContents();}var sn=A.childNodes[0];C.insertNode(A);if(B=='after'){A.insertAdjacentHTML('afterend','&nbsp;');
-sn=A.nextSibling;}if(B=='none'){return;}this.cursorText(sn);},cursorText:function(n){range=Roo.lib.Range.wrap(new Range());var ix=Array.from(n.parentNode.childNodes).indexOf(n);range.setStart(n.parentNode,ix);range.setEnd(n.parentNode,ix+1);this.removeAllRanges();
-this.addRange(range);Roo.log([n,range,this,this.baseOffset,this.extentOffset,this.type]);},cursorAfter:function(n){if(!n.nextSibling||n.nextSibling.nodeValue!='&nbsp;'){n.insertAdjacentHTML('afterend','&nbsp;');}this.cursorText(n.nextSibling);}});
 // Roo/DomHelper.js
 if(typeof Range!="undefined"&&typeof Range.prototype.createContextualFragment=="undefined"){Range.prototype.createContextualFragment=function(A){var B=window.document;var C=B.createElement("div");C.innerHTML=A;var D=B.createDocumentFragment(),n;while((n=C.firstChild)){D.appendChild(n);
 }return D;};}Roo.DomHelper=function(){var A=null;var B=/^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;var C=/^table|tbody|tr|td$/i;var D={};var E=function(o){if(typeof o=='string'){return o;}var b="";if(!o.tag){o.tag="div";}b+="<"+o.tag;
 // Roo/DomHelper.js
 if(typeof Range!="undefined"&&typeof Range.prototype.createContextualFragment=="undefined"){Range.prototype.createContextualFragment=function(A){var B=window.document;var C=B.createElement("div");C.innerHTML=A;var D=B.createDocumentFragment(),n;while((n=C.firstChild)){D.appendChild(n);
 }return D;};}Roo.DomHelper=function(){var A=null;var B=/^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;var C=/^table|tbody|tr|td$/i;var D={};var E=function(o){if(typeof o=='string'){return o;}var b="";if(!o.tag){o.tag="div";}b+="<"+o.tag;
@@ -1850,205 +1830,6 @@ this.el.on('DOMAttrModified',this.setFromHidden,this);this.el.on('propertychange
 Roo.form.Radio=function(){Roo.form.Radio.superclass.constructor.apply(this,arguments);};Roo.extend(Roo.form.Radio,Roo.form.Checkbox,{inputType:'radio',getGroupValue:function(){return this.el.up('form').child('input[name='+this.el.dom.name+']:checked',true).value;
 },onRender:function(ct,A){Roo.form.Checkbox.superclass.onRender.call(this,ct,A);if(this.inputValue!==undefined){this.el.dom.value=this.inputValue;}this.wrap=this.el.wrap({cls:"x-form-check-wrap"});if(this.boxLabel){this.wrap.createChild({tag:'label',htmlFor:this.el.id,cls:'x-form-cb-label',html:this.boxLabel}
 );}if(this.checked){this.el.dom.checked='checked';}}});
 Roo.form.Radio=function(){Roo.form.Radio.superclass.constructor.apply(this,arguments);};Roo.extend(Roo.form.Radio,Roo.form.Checkbox,{inputType:'radio',getGroupValue:function(){return this.el.up('form').child('input[name='+this.el.dom.name+']:checked',true).value;
 },onRender:function(ct,A){Roo.form.Checkbox.superclass.onRender.call(this,ct,A);if(this.inputValue!==undefined){this.el.dom.value=this.inputValue;}this.wrap=this.el.wrap({cls:"x-form-check-wrap"});if(this.boxLabel){this.wrap.createChild({tag:'label',htmlFor:this.el.id,cls:'x-form-cb-label',html:this.boxLabel}
 );}if(this.checked){this.el.dom.checked='checked';}}});
-// Roo/rtf/namespace.js
-Roo.rtf={};
-// Roo/rtf/Hex.js
-Roo.rtf.Hex=function(A){this.hexstr=A;};
-// Roo/rtf/Paragraph.js
-Roo.rtf.Paragraph=function(A){this.content=[];};
-// Roo/rtf/Span.js
-Roo.rtf.Span=function(A){this.value=A.value;};
-// Roo/rtf/Group.js
-Roo.rtf.Group=function(A){this.content=[];this.cn=[];};Roo.rtf.Group.prototype={ignorable:false,content:false,cn:false,addContent:function(A){this.content.push(A);},addChild:function(cn){this.cn.push(cn);},toDataURL:function(){var A=false;switch(true){case this.content.filter(function(a){return a.value=='pngblip'}
-).length>0:A="image/png";break;case this.content.filter(function(a){return a.value=='jpegblip'}).length>0:A="image/jpeg";break;default:return 'about:blank';}var B=this.content[this.content.length-1].value;return 'data:'+A+';base64,'+btoa(B.match(/\w{2}/g).map(function(a){return String.fromCharCode(parseInt(a,16));
-}).join(""));}};
-// Roo/rtf/Document.js
-Roo.rtf.Document=function(){this.rtlch=[];this.content=[];this.cn=[];};Roo.extend(Roo.rtf.Document,Roo.rtf.Group,{addChild:function(cn){this.cn.push(cn);switch(cn.type){case 'rtlch':case 'listtext':case 'shpinst':this.rtlch.push(cn);return;default:this[cn.type]=cn;
-}},getElementsByType:function(A){var B=[];this._getElementsByType(A,B,this.cn,'rtf');return B;},_getElementsByType:function(A,B,C,D){C.forEach(function(n,i){if(n.type==A){n.path=D+'/'+n.type+':'+i;B.push(n);}if(n.cn.length>0){this._getElementsByType(A,B,n.cn,D+'/'+n.type+':'+i);
-}},this);}});
-// Roo/rtf/Ctrl.js
-Roo.rtf.Ctrl=function(A){this.value=A.value;this.param=A.param;};
-// Roo/rtf/Parser.js
-Roo.rtf.Parser=function(A){this.text='';this.parserState=this.parseText;this.doc={};this.groupStack=[];this.hexStore=[];this.doc=false;this.groups=[];for(var ii=0;ii<A.length;++ii){++this.cpos;if(A[ii]==='\n'){++this.row;this.col=1;}else{++this.col;}this.parserState(A[ii]);
-}};Roo.rtf.Parser.prototype={text:'',controlWord:'',controlWordParam:'',hexChar:'',doc:false,group:false,groupStack:false,hexStore:false,cpos:0,row:1,col:1,push:function(el){var m='cmd'+el.type;if(typeof(this[m])=='undefined'){Roo.log('invalid cmd:'+el.type);
-return;}this[m](el);},flushHexStore:function(){if(this.hexStore.length<1){return;}var A=this.hexStore.map(function(B){return B.value;}).join('');this.group.addContent(new Roo.rtf.Hex(A));this.hexStore.splice(0)},cmdgroupstart:function(){this.flushHexStore();
-if(this.group){this.groupStack.push(this.group);}if(this.doc===false){this.group=this.doc=new Roo.rtf.Document();return;}this.group=new Roo.rtf.Group(this.group);},cmdignorable:function(){this.flushHexStore();this.group.ignorable=true;},cmdendparagraph:function(){this.flushHexStore();
-this.group.addContent(new Roo.rtf.Paragraph());},cmdgroupend:function(){this.flushHexStore();var A=this.group;this.group=this.groupStack.pop();if(this.group){this.group.addChild(A);}var B=this.group||this.doc;if(A.ignorable===false){this.groups.push(A);}}
-,cmdtext:function(A){this.flushHexStore();if(!this.group){}this.group.addContent(new Roo.rtf.Span(A));},cmdcontrolword:function(A){this.flushHexStore();if(!this.group.type){this.group.type=A.value;return;}this.group.addContent(new Roo.rtf.Ctrl(A));return;
-},cmdhexchar:function(A){this.hexStore.push(A);},cmderror:function(A){throw new Exception(A.value);},parseText:function(c){if(c==='\\'){this.parserState=this.parseEscapes;}else if(c==='{'){this.emitStartGroup();}else if(c==='}'){this.emitEndGroup();}else if(c==='\x0A'||c==='\x0D'){}
-else{this.text+=c;}},parseEscapes:function(c){if(c==='\\'||c==='{'||c==='}'){this.text+=c;this.parserState=this.parseText;}else{this.parserState=this.parseControlSymbol;this.parseControlSymbol(c);}},parseControlSymbol:function(c){if(c==='~'){this.text+='\u00a0';
-this.parserState=this.parseText}else if(c==='-'){this.text+='\u00ad';}else if(c==='_'){this.text+='\u2011';}else if(c==='*'){this.emitIgnorable();this.parserState=this.parseText;}else if(c==="'"){this.parserState=this.parseHexChar;}else if(c==='|'){this.emitFormula();
-this.parserState=this.parseText;}else if(c===':'){this.emitIndexSubEntry();this.parserState=this.parseText;}else if(c==='\x0a'){this.emitEndParagraph();this.parserState=this.parseText;}else if(c==='\x0d'){this.emitEndParagraph();this.parserState=this.parseText;
-}else{this.parserState=this.parseControlWord;this.parseControlWord(c);}},parseHexChar:function(c){if(/^[A-Fa-f0-9]$/.test(c)){this.hexChar+=c;if(this.hexChar.length>=2){this.emitHexChar();this.parserState=this.parseText;}return;}this.emitError("Invalid character \""+c+"\" in hex literal.");
-this.parserState=this.parseText;},parseControlWord:function(c){if(c===' '){this.emitControlWord();this.parserState=this.parseText;}else if(/^[-\d]$/.test(c)){this.parserState=this.parseControlWordParam;this.controlWordParam+=c;}else if(/^[A-Za-z]$/.test(c)){this.controlWord+=c;
-}else{this.emitControlWord();this.parserState=this.parseText;this.parseText(c);}},parseControlWordParam:function(c){if(/^\d$/.test(c)){this.controlWordParam+=c;}else if(c===' '){this.emitControlWord();this.parserState=this.parseText;}else{this.emitControlWord();
-this.parserState=this.parseText;this.parseText(c);}},emitText:function(){if(this.text===''){return;}this.push({type:'text',value:this.text,pos:this.cpos,row:this.row,col:this.col});this.text=''},emitControlWord:function(){this.emitText();if(this.controlWord===''){this.emitError('empty control word');
-}else{this.push({type:'controlword',value:this.controlWord,param:this.controlWordParam!==''&&Number(this.controlWordParam),pos:this.cpos,row:this.row,col:this.col});}this.controlWord='';this.controlWordParam='';},emitStartGroup:function(){this.emitText();
-this.push({type:'groupstart',pos:this.cpos,row:this.row,col:this.col});},emitEndGroup:function(){this.emitText();this.push({type:'groupend',pos:this.cpos,row:this.row,col:this.col});},emitIgnorable:function(){this.emitText();this.push({type:'ignorable',pos:this.cpos,row:this.row,col:this.col}
-);},emitHexChar:function(){this.emitText();this.push({type:'hexchar',value:this.hexChar,pos:this.cpos,row:this.row,col:this.col});this.hexChar=''},emitError:function(A){this.emitText();this.push({type:'error',value:A,row:this.row,col:this.col,char:this.cpos}
-);},emitEndParagraph:function(){this.emitText();this.push({type:'endparagraph',pos:this.cpos,row:this.row,col:this.col});}};
-// Roo/htmleditor/namespace.js
-Roo.htmleditor={};
-// Roo/htmleditor/Filter.js
-Roo.htmleditor.Filter=function(A){Roo.apply(this.cfg);};Roo.htmleditor.Filter.prototype={node:false,tag:false,replaceComment:false,replaceTag:false,walk:function(A){Roo.each(Array.from(A.childNodes),function(e){switch(true){case e.nodeType==8&&this.replaceComment!==false:this.replaceComment(e);
-return;case e.nodeType!=1:return;case this.tag===true:case typeof(this.tag)=='object'&&this.tag.indexOf(e.tagName)>-1:case typeof(this.tag)=='string'&&this.tag==e.tagName:if(this.replaceTag&&false===this.replaceTag(e)){return;}if(e.hasChildNodes()){this.walk(e);
-}return;default:if(e.hasChildNodes()){this.walk(e);}}},this);}};
-// Roo/htmleditor/FilterAttributes.js
-Roo.htmleditor.FilterAttributes=function(A){Roo.apply(this,A);this.attrib_black=this.attrib_black||[];this.attrib_white=this.attrib_white||[];this.attrib_clean=this.attrib_clean||[];this.style_white=this.style_white||[];this.style_black=this.style_black||[];
-this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterAttributes,Roo.htmleditor.Filter,{tag:true,attrib_black:false,attrib_clean:false,attrib_white:false,style_white:false,style_black:false,replaceTag:function(A){if(!A.attributes||!A.attributes.length){return true;
-}for(var i=A.attributes.length-1;i>-1;i--){var a=A.attributes[i];if(this.attrib_white.length&&this.attrib_white.indexOf(a.name.toLowerCase())<0){A.removeAttribute(a.name);continue;}if(a.name.toLowerCase().substr(0,2)=='on'){A.removeAttribute(a.name);continue;
-}if(this.attrib_black.indexOf(a.name.toLowerCase())>-1){A.removeAttribute(a.name);continue;}if(this.attrib_clean.indexOf(a.name.toLowerCase())>-1){this.cleanAttr(A,a.name,a.value);continue;}if(a.name=='style'){this.cleanStyle(A,a.name,a.value);continue;}if(a.name=='class'){if(a.value.match(/^Mso/)){A.removeAttribute('class');
-}if(a.value.match(/^body$/)){A.removeAttribute('class');}continue;}}return true;},cleanAttr:function(A,n,v){if(v.match(/^\./)||v.match(/^\//)){return;}if(v.match(/^(http|https):\/\//)||v.match(/^mailto:/)||v.match(/^ftp:/)||v.match(/^data:/)){return;}if(v.match(/^#/)){return;
-}if(v.match(/^\{/)){return;}A.removeAttribute(n);},cleanStyle:function(A,n,v){if(v.match(/expression/)){A.removeAttribute(n);return;}var B=v.split(/;/);var C=[];Roo.each(B,function(p){p=p.replace(/^\s+/g,'').replace(/\s+$/g,'');if(!p.length){return true;}
-var l=p.split(':').shift().replace(/\s+/g,'');l=l.replace(/^\s+/g,'').replace(/\s+$/g,'');if(this.style_black.length&&(this.style_black.indexOf(l)>-1||this.style_black.indexOf(l.toLowerCase())>-1)){return true;}if(this.style_white.length&&style_white.indexOf(l)<0&&style_white.indexOf(l.toLowerCase())<0){return true;
-}C.push(p);return true;},this);if(C.length){A.setAttribute(n,C.join(';'));}else{A.removeAttribute(n);}}});
-// Roo/htmleditor/FilterBlack.js
-Roo.htmleditor.FilterBlack=function(A){Roo.apply(this,A);this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterBlack,Roo.htmleditor.Filter,{tag:true,replaceTag:function(n){n.parentNode.removeChild(n);}});
-// Roo/htmleditor/FilterComment.js
-Roo.htmleditor.FilterComment=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterComment,Roo.htmleditor.Filter,{replaceComment:function(n){n.parentNode.removeChild(n);}});
-// Roo/htmleditor/FilterKeepChildren.js
-Roo.htmleditor.FilterKeepChildren=function(A){Roo.apply(this,A);if(this.tag===false){return;}this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterKeepChildren,Roo.htmleditor.FilterBlack,{replaceTag:function(A){var ar=Array.from(A.childNodes);for(var i=0;i<ar.length;
-i++){if(ar[i].nodeType==1){if((typeof(this.tag)=='object'&&this.tag.indexOf(ar[i].tagName)>-1)||(typeof(this.tag)=='string'&&this.tag==ar[i].tagName)){this.replaceTag(ar[i]);continue;}}}ar=Array.from(A.childNodes);for(var i=0;i<ar.length;i++){A.removeChild(ar[i]);
-A.parentNode.insertBefore(ar[i],A);if(this.tag!==false){this.walk(ar[i]);}}A.parentNode.removeChild(A);return false;}});
-// Roo/htmleditor/FilterParagraph.js
-Roo.htmleditor.FilterParagraph=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterParagraph,Roo.htmleditor.Filter,{tag:'P',replaceTag:function(A){if(A.childNodes.length==1&&A.childNodes[0].nodeType==3&&A.childNodes[0].textContent.trim().length<1){A.parentNode.replaceChild(A.ownerDocument.createElement('BR'),A);
-return false;}var ar=Array.from(A.childNodes);for(var i=0;i<ar.length;i++){A.removeChild(ar[i]);A.parentNode.insertBefore(ar[i],A);}A.parentNode.insertBefore(A.ownerDocument.createElement('BR'),A);A.parentNode.insertBefore(A.ownerDocument.createElement('BR'),A);
-A.parentNode.removeChild(A);return false;}});
-// Roo/htmleditor/FilterSpan.js
-Roo.htmleditor.FilterSpan=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterSpan,Roo.htmleditor.FilterKeepChildren,{tag:'SPAN',replaceTag:function(A){if(A.attributes&&A.attributes.length>0){return true;}Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this,A);
-return false;}});
-// Roo/htmleditor/FilterTableWidth.js
-Roo.htmleditor.FilterTableWidth=function(A){this.tag=['TABLE','TD','TR','TH','THEAD','TBODY'];this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterTableWidth,Roo.htmleditor.Filter,{replaceTag:function(A){if(A.hasAttribute('width')){A.removeAttribute('width');
-}if(A.hasAttribute("style")){var B=A.getAttribute("style").split(";");var C=[];Roo.each(B,function(s){if(!s.match(/:/)){return;}var kv=s.split(":");if(kv[0].match(/^\s*(width|min-width)\s*$/)){return;}C.push(s);});A.setAttribute("style",C.length?C.join(';'):'');
-if(!C.length){A.removeAttribute('style');}}return true;}});
-// Roo/htmleditor/FilterWord.js
-Roo.htmleditor.FilterWord=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterWord,Roo.htmleditor.Filter,{tag:true,replaceTag:function(A){if(A.nodeName=='SPAN'&&!A.hasAttributes()&&A.childNodes.length==1&&A.firstChild.nodeName=="#text"){var B=A.firstChild;
-A.removeChild(B);if(A.getAttribute('lang')!='zh-CN'){A.parentNode.insertBefore(A.ownerDocument.createTextNode(" "),A);}A.parentNode.insertBefore(B,A);if(A.getAttribute('lang')!='zh-CN'){A.parentNode.insertBefore(A.ownerDocument.createTextNode(" "),A);}A.parentNode.removeChild(A);
-return false;}if(A.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)){A.parentNode.removeChild(A);return false;}if(A.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)){while(A.childNodes.length){var cn=A.childNodes[0];
-A.removeChild(cn);A.parentNode.insertBefore(cn,A);this.replaceTag(cn);}A.parentNode.removeChild(A);return false;}if(A.className.length){var cn=A.className.split(/\W+/);var C=[];Roo.each(cn,function(F){if(F.match(/Mso[a-zA-Z]+/)){return;}C.push(F);});A.className=C.length?C.join(' '):'';
-if(!C.length){A.removeAttribute("class");}}if(A.hasAttribute("lang")){A.removeAttribute("lang");}if(A.hasAttribute("style")){var D=A.getAttribute("style").split(";");var E=[];Roo.each(D,function(s){if(!s.match(/:/)){return;}var kv=s.split(":");if(kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)){return;
-}E.push(s);});A.setAttribute("style",E.length?E.join(';'):'');if(!E.length){A.removeAttribute('style');}}return true;}});
-// Roo/htmleditor/FilterStyleToTag.js
-Roo.htmleditor.FilterStyleToTag=function(A){this.tags={B:['fontWeight','bold'],I:['fontStyle','italic'],SUP:['verticalAlign','super'],SUB:['verticalAlign','sub']};Roo.apply(this,A);this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterStyleToTag,Roo.htmleditor.Filter,{tag:true,tags:false,replaceTag:function(A){if(A.getAttribute("style")===null){return true;
-}var B=[];for(var k in this.tags){if(A.style[this.tags[k][0]]==this.tags[k][1]){B.push(k);A.style.removeProperty(this.tags[k][0]);}}if(!B.length){return true;}var cn=Array.from(A.childNodes);var nn=A;Roo.each(B,function(t){var nc=A.ownerDocument.createElement(t);
-nn.appendChild(nc);nn=nc;});for(var i=0;i<cn.length;cn++){A.removeChild(cn[i]);nn.appendChild(cn[i]);}return true}})
-// Roo/htmleditor/FilterLongBr.js
-Roo.htmleditor.FilterLongBr=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterLongBr,Roo.htmleditor.Filter,{tag:'BR',replaceTag:function(A){var ps=A.nextSibling;while(ps&&ps.nodeType==3&&ps.nodeValue.trim().length<1){ps=ps.nextSibling;}if(!ps&&['TD','TH','LI','H1','H2','H3','H4','H5','H6'].indexOf(A.parentNode.tagName)>-1){A.parentNode.removeChild(A);
-return false;}if(!ps||ps.nodeType!=1){return false;}if(!ps||ps.tagName!='BR'){return false;}if(!A.previousSibling){return false;}var ps=A.previousSibling;while(ps&&ps.nodeType==3&&ps.nodeValue.trim().length<1){ps=ps.previousSibling;}if(!ps||ps.nodeType!=1){return false;
-}if(!ps||['BR','H1','H2','H3','H4','H5','H6'].indexOf(ps.tagName)<0){return false;}A.parentNode.removeChild(A);return false;}});
-// 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/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','A'];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();
-this.core.fireEditorEvent(e);return false;}if(D.innerText.trim()==''&&D.previousSibling&&D.previousSibling.nodeName=='LI'&&D.previousSibling.innerText.trim()==''){D.parentNode.removeChild(D.previousSibling);B.cursorAfter(pc);this.core.undoManager.addEvent();
-this.core.fireEditorEvent(e);return false;}var li=A.createElement('LI');li.innerHTML='&nbsp;';if(!D||!D.firstSibling){pc.appendChild(li);}else{D.parentNode.insertBefore(li,D.firstSibling);}B.cursorText(li.firstChild);this.core.undoManager.addEvent();this.core.fireEditorEvent(e);
-return false;}};
-// Roo/htmleditor/Block.js
-Roo.htmleditor.Block=function(A){};Roo.htmleditor.Block.factory=function(A){var cc=Roo.htmleditor.Block.cache;var id=Roo.get(A).id;if(typeof(cc[id])!='undefined'&&(!cc[id].node||cc[id].node.closest('body'))){Roo.htmleditor.Block.cache[id].readElement(A);return Roo.htmleditor.Block.cache[id];
-}var db=A.getAttribute('data-block');if(!db){db=A.nodeName.toLowerCase().toUpperCaseFirst();}var B=Roo.htmleditor['Block'+db];if(typeof(B)=='undefined'){Roo.log("OOps missing block : "+'Block'+db);return false;}Roo.htmleditor.Block.cache[id]=new B({node:A}
-);return Roo.htmleditor.Block.cache[id];};Roo.htmleditor.Block.initAll=function(A,B){if(typeof(B)=='undefined'){var ia=Roo.htmleditor.Block.initAll;ia(A,'table');ia(A,'td');ia(A,'figure');return;}Roo.each(Roo.get(A).query(B),function(e){Roo.htmleditor.Block.factory(e);
-},this);};Roo.htmleditor.Block.cache={};Roo.htmleditor.Block.prototype={node:false,friendly_name:'Based Block',deleteTitle:false,context:false,updateElement:function(A){Roo.DomHelper.update(A===undefined?this.node:A,this.toObject());},toHTML:function(){return Roo.DomHelper.markup(this.toObject());
-},getVal:function(A,B,C,D){var n=A;if(B!==true&&n.tagName!=B.toUpperCase()){n=A.getElementsByTagName(B).item(0);}if(!n){return '';}if(C=='html'){return n.innerHTML;}if(C=='style'){return n.style[D];}return n.hasAttribute(C)?n.getAttribute(C):'';},toObject:function(){return {}
-;},readElement:function(A){}};
-// Roo/htmleditor/BlockFigure.js
-Roo.htmleditor.BlockFigure=function(A){if(A.node){this.readElement(A.node);this.updateElement(A.node);}Roo.apply(this,A);};Roo.extend(Roo.htmleditor.BlockFigure,Roo.htmleditor.Block,{image_src:'',align:'center',caption:'',caption_display:'block',width:'100%',cls:'',href:'',video_url:'',text_align:'left',friendly_name:'Image with caption',deleteTitle:"Delete Image and Caption",contextMenu:function(A){var B=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode);
-};var C=typeof(Roo.bootstrap)=='undefined'?Roo:Roo.bootstrap;var D=A.editorcore.syncValue;var E={};return [{xtype:'TextItem',text:"Source: ",xns:C.Toolbar},{xtype:'Button',text:'Change Image URL',listeners:{click:function(F,G){var b=B();Roo.MessageBox.show({title:"Image Source URL",msg:"Enter the url for the image",buttons:Roo.MessageBox.OKCANCEL,fn:function(H,I){if(H!='ok'){return;
-}b.image_src=I;b.updateElement();D();A.editorcore.onEditorEvent();},minWidth:250,prompt:true,modal:true,value:b.image_src});}},xns:C.Toolbar},{xtype:'Button',text:'Change Link URL',listeners:{click:function(F,G){var b=B();Roo.MessageBox.show({title:"Link URL",msg:"Enter the url for the link - leave blank to have no link",buttons:Roo.MessageBox.OKCANCEL,fn:function(H,I){if(H!='ok'){return;
-}b.href=I;b.updateElement();D();A.editorcore.onEditorEvent();},minWidth:250,prompt:true,modal:true,value:b.href});}},xns:C.Toolbar},{xtype:'Button',text:'Show Video URL',listeners:{click:function(F,G){Roo.MessageBox.alert("Video URL",B().video_url==''?'This image is not linked ot a video':'The image is linked to: <a target="_new" href="'+B().video_url+'">'+B().video_url+'</a>');
-}},xns:C.Toolbar},{xtype:'TextItem',text:"Width: ",xns:C.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:70,name:'width',listeners:{select:function(F,r,G){A.editorcore.selectNode(A.tb.selectedNode);
-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," ").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]};}var B=this.caption_display=='hidden'?this.caption:(this.caption.length?this.caption:"Caption");
-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',style:{'text-align':'left','margin-top':'16px','font-size':'16px','line-height':'24px',display:this.caption_display}
-,cls:this.cls.length>0?(this.cls+'-thumbnail'):'',cn:[{tag:'i',contenteditable:true,html:B}]}]};},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.caption.trim().match(/^<i[^>]*>/i)){this.caption=this.caption.trim().replace(/^<i[^>]*>/i,'').replace(/^<\/i>$/i,'');}this.width=this.getVal(A,'figure','style','max-width');
-},removeNode:function(){return this.node;}})
-// Roo/htmleditor/BlockTable.js
-Roo.htmleditor.BlockTable=function(A){if(A.node){this.readElement(A.node);this.updateElement(A.node);}Roo.apply(this,A);if(!A.node){this.rows=[];for(var r=0;r<this.no_row;r++){this.rows[r]=[];for(var c=0;c<this.no_col;c++){this.rows[r][c]=this.emptyCell();
-}}}};Roo.extend(Roo.htmleditor.BlockTable,Roo.htmleditor.Block,{rows:false,no_col:1,no_row:1,width:'100%',friendly_name:'Table',deleteTitle:'Delete Table',contextMenu:function(A){var B=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode);};var C=typeof(Roo.bootstrap)=='undefined'?Roo:Roo.bootstrap;
-var D=A.editorcore.syncValue;var E={};return [{xtype:'TextItem',text:"Width: ",xns:C.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:100,name:'width',listeners:{select:function(F,r,G){A.editorcore.selectNode(A.tb.selectedNode);
-var b=B();b.width=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['100%'],['auto']],fields:['val'],xns:Roo.data}},{xtype:'TextItem',text:"Columns: ",xns:C.Toolbar},{xtype:'Button',text:'-',listeners:{click:function(F,e){A.editorcore.selectNode(A.tb.selectedNode);
-B().removeColumn();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar},{xtype:'Button',text:'+',listeners:{click:function(F,e){A.editorcore.selectNode(A.tb.selectedNode);B().addColumn();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar},{xtype:'TextItem',text:"Rows: ",xns:C.Toolbar}
-,{xtype:'Button',text:'-',listeners:{click:function(F,e){A.editorcore.selectNode(A.tb.selectedNode);B().removeRow();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar},{xtype:'Button',text:'+',listeners:{click:function(F,e){B().addRow();D();A.editorcore.onEditorEvent();
-}},xns:C.Toolbar},{xtype:'Button',text:'Reset Column Widths',listeners:{click:function(F,e){B().resetWidths();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar}];},toObject:function(){var A={tag:'table',contenteditable:'false','data-block':'Table',style:{width:this.width,border:'solid 1px #000','border-collapse':'collapse'}
-,cn:[{tag:'tbody',cn:[]}]};var B=0;Roo.each(this.rows,function(C){var tr={tag:'tr',style:{margin:'6px',border:'solid 1px #000',textAlign:'left'},cn:[]};A.cn[0].cn.push(tr);var nc=0;Roo.each(C,function(D){var td={tag:'td',contenteditable:'true','data-block':'Td',html:D.html,style:D.style}
-;if(D.colspan>1){td.colspan=D.colspan;nc+=D.colspan;}else{nc++;}if(D.rowspan>1){td.rowspan=D.rowspan;}tr.cn.push(td);},this);B=Math.max(nc,B);},this);B++;return A;},readElement:function(A){A=A?A:this.node;this.width=this.getVal(A,true,'style','width')||'100%';
-this.rows=[];this.no_row=0;var B=Array.from(A.rows);B.forEach(function(tr){var C=[];this.rows.push(C);this.no_row++;var D=0;Array.from(tr.cells).forEach(function(td){var E={colspan:td.hasAttribute('colspan')?td.getAttribute('colspan')*1:1,rowspan:td.hasAttribute('rowspan')?td.getAttribute('rowspan')*1:1,style:td.hasAttribute('style')?td.getAttribute('style'):'',html:td.innerHTML}
-;D+=E.colspan;C.push(E);},this);this.no_col=Math.max(this.no_col,D);},this);},normalizeRows:function(){var A=[];var B=-1;this.rows.forEach(function(C){B++;A[B]=[];C=this.normalizeRow(C);var D=0;C.forEach(function(c){while(typeof(A[B][D])!='undefined'){D++;
-}if(typeof(A[B])=='undefined'){A[B]=[];}A[B][D]=c;c.row=B;c.col=D;if(c.rowspan<2){return;}for(var i=1;i<c.rowspan;i++){if(typeof(A[B+i])=='undefined'){A[B+i]=[];}A[B+i][D]=c;}});},this);return A;},normalizeRow:function(A){var B=[];A.forEach(function(c){if(c.colspan<2){B.push(c);
-return;}for(var i=0;i<c.colspan;i++){B.push(c);}});return B;},deleteColumn:function(A){if(!A||A.type!='col'){return;}if(this.no_col<2){return;}this.rows.forEach(function(B){var C=this.normalizeRow(B);var D=C[A.col];if(D.colspan>1){D.colspan--;}else{B.remove(D);
-}},this);this.no_col--;},removeColumn:function(){this.deleteColumn({type:'col',col:this.no_col-1});this.updateElement();},addColumn:function(){this.rows.forEach(function(A){A.push(this.emptyCell());},this);this.updateElement();},deleteRow:function(A){if(!A||A.type!='row'){return;
-}if(this.no_row<2){return;}var B=this.normalizeRows();B[A.row].forEach(function(D){if(D.rowspan>1){D.rowspan--;}else{D.remove=1;}},this);var C=[];this.rows.forEach(function(D){newrow=[];D.forEach(function(c){if(typeof(c.remove)=='undefined'){newrow.push(c);
-}});if(newrow.length>0){C.push(D);}});this.rows=C;this.no_row--;this.updateElement();},removeRow:function(){this.deleteRow({type:'row',row:this.no_row-1});},addRow:function(){var A=[];for(var i=0;i<this.no_col;i++){A.push(this.emptyCell());}this.rows.push(A);
-this.updateElement();},emptyCell:function(){return (new Roo.htmleditor.BlockTd({})).toObject();},removeNode:function(){return this.node;},resetWidths:function(){Array.from(this.node.getElementsByTagName('td')).forEach(function(n){var nn=Roo.htmleditor.Block.factory(n);
-nn.width='';nn.updateElement(n);});}})
-// Roo/htmleditor/BlockTd.js
-Roo.htmleditor.BlockTd=function(A){if(A.node){this.readElement(A.node);this.updateElement(A.node);}Roo.apply(this,A);};Roo.extend(Roo.htmleditor.BlockTd,Roo.htmleditor.Block,{node:false,width:'',textAlign:'left',valign:'top',colspan:1,rowspan:1,friendly_name:'Table Cell',deleteTitle:false,contextMenu:function(A){var B=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode);
-};var C=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode.closest('table'));};var lr=false;var D=function(){lr=A.editorcore.getSelection().getRangeAt(0);};var restoreSel=function(){if(lr){(function(){A.editorcore.focus();var cr=A.editorcore.getSelection();
-cr.removeAllRanges();cr.addRange(lr);A.editorcore.onEditorEvent();}).defer(10,this);}};var rooui=typeof(Roo.bootstrap)=='undefined'?Roo:Roo.bootstrap;var E=A.editorcore.syncValue;var F={};return [{xtype:'Button',text:'Edit Table',listeners:{click:function(){var t=A.tb.selectedNode.closest('table');
-A.editorcore.selectNode(t);A.editorcore.onEditorEvent();}}},{xtype:'TextItem',text:"Column Width: ",xns:rooui.Toolbar},{xtype:'Button',text:'-',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);B().shrinkColumn();E();A.editorcore.onEditorEvent();
-}},xns:rooui.Toolbar},{xtype:'Button',text:'+',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);B().growColumn();E();A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'TextItem',text:"Vertical Align: ",xns:rooui.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:100,name:'valign',listeners:{select:function(G,r,H){A.editorcore.selectNode(A.tb.selectedNode);
-var b=B();b.valign=r.get('val');b.updateElement();E();A.editorcore.onEditorEvent();}},xns:rooui.form,store:{xtype:'SimpleStore',data:[['top'],['middle'],['bottom']],fields:['val'],xns:Roo.data}},{xtype:'TextItem',text:"Merge Cells: ",xns:rooui.Toolbar},{xtype:'Button',text:'Right',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);
-B().mergeRight();E();A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'Button',text:'Below',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);B().mergeBelow();E();A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'TextItem',text:"| ",xns:rooui.Toolbar}
-,{xtype:'Button',text:'Split',listeners:{click:function(G,e){B().split();E();A.editorcore.selectNode(A.tb.selectedNode);A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'Fill',xns:rooui.Toolbar},{xtype:'Button',text:'Delete',xns:rooui.Toolbar,menu:{xtype:'Menu',xns:rooui.menu,items:[{xtype:'Item',html:'Column',listeners:{click:function(G,e){var t=C();
-B().deleteColumn();E();A.editorcore.selectNode(t.node);A.editorcore.onEditorEvent();}},xns:rooui.menu},{xtype:'Item',html:'Row',listeners:{click:function(G,e){var t=C();B().deleteRow();E();A.editorcore.selectNode(t.node);A.editorcore.onEditorEvent();}},xns:rooui.menu}
-,{xtype:'Separator',xns:rooui.menu},{xtype:'Item',html:'Table',listeners:{click:function(G,e){var t=C();var nn=t.node.nextSibling||t.node.previousSibling;t.node.parentNode.removeChild(t.node);if(nn){A.editorcore.selectNode(nn,true);}A.editorcore.onEditorEvent();
-}},xns:rooui.menu}]}}];},toObject:function(){var A={tag:'td',contenteditable:'true','data-block':'Td',valign:this.valign,style:{'text-align':this.textAlign,border:'solid 1px rgb(0, 0, 0)','border-collapse':'collapse',padding:'6px','vertical-align':this.valign}
-,html:this.html};if(this.width!=''){A.width=this.width;A.style.width=this.width;}if(this.colspan>1){A.colspan=this.colspan;}if(this.rowspan>1){A.rowspan=this.rowspan;}return A;},readElement:function(A){A=A?A:this.node;this.width=A.style.width;this.colspan=Math.max(1,1*A.getAttribute('colspan'));
-this.rowspan=Math.max(1,1*A.getAttribute('rowspan'));this.html=A.innerHTML;},emptyCell:function(){return {colspan:1,rowspan:1,textAlign:'left',html:"&nbsp;"};},removeNode:function(){return this.node.closest('table');},cellData:false,colWidths:false,toTableArray:function(){var A=[];
-var B=this.node.closest('tr').closest('table');Array.from(B.rows).forEach(function(r,ri){A[ri]=[];});var rn=0;this.colWidths=[];var C=true;Array.from(B.rows).forEach(function(r,ri){var cn=0;Array.from(r.cells).forEach(function(ce,ci){var c={cell:ce,row:rn,col:cn,colspan:ce.colSpan,rowspan:ce.rowSpan}
-;if(ce.isEqualNode(this.node)){this.cellData=c;}if(typeof(A[rn][cn])!='undefined'){while(typeof(A[rn][cn])!='undefined'){cn++;}c.col=cn;}if(typeof(this.colWidths[cn])=='undefined'){this.colWidths[cn]=ce.style.width;if(this.colWidths[cn]!=''){C=false;}}if(c.colspan<2&&c.rowspan<2){A[rn][cn]=c;
-cn++;return;}for(var j=0;j<c.rowspan;j++){if(typeof(A[rn+j])=='undefined'){continue;}A[rn+j][cn]=c;for(var i=0;i<c.colspan;i++){A[rn+j][cn+i]=c;}}cn+=c.colspan;},this);rn++;},this);if(C){this.colWidths[0]=false;}return A;},mergeRight:function(){var tr=this.node.closest('tr');
-var i=Array.prototype.indexOf.call(tr.childNodes,this.node);if(i>=tr.childNodes.length-1){return;}var A=this.toTableArray();if(typeof(A[this.cellData.row][this.cellData.col+this.cellData.colspan])=='undefined'){return;}var rc=A[this.cellData.row][this.cellData.col+this.cellData.colspan];
-if(rc.rowspan!=this.cellData.rowspan||rc.row!=this.cellData.row){return;}this.node.innerHTML+=' '+rc.cell.innerHTML;tr.removeChild(rc.cell);this.colspan+=rc.colspan;this.node.setAttribute('colspan',this.colspan);},mergeBelow:function(){var A=this.toTableArray();
-if(typeof(A[this.cellData.row+this.cellData.rowspan])=='undefined'){return;}if(typeof(A[this.cellData.row+this.cellData.rowspan][this.cellData.col])=='undefined'){return;}var rc=A[this.cellData.row+this.cellData.rowspan][this.cellData.col];if(rc.colspan!=this.cellData.colspan||rc.col!=this.cellData.col){return;
-}this.node.innerHTML=this.node.innerHTML+rc.cell.innerHTML;rc.cell.parentNode.removeChild(rc.cell);this.rowspan+=rc.rowspan;this.node.setAttribute('rowspan',this.rowspan);},split:function(){if(this.node.rowSpan<2&&this.node.colSpan<2){return;}var A=this.toTableArray();
-var cd=this.cellData;this.rowspan=1;this.colspan=1;for(var r=cd.row;r<cd.row+cd.rowspan;r++){for(var c=cd.col;c<cd.col+cd.colspan;c++){if(r==cd.row&&c==cd.col){this.node.removeAttribute('rowspan');this.node.removeAttribute('colspan');continue;}var B=this.node.cloneNode();
-B.removeAttribute('id');B.innerHTML='';A[r][c]={cell:B,col:c,row:r,colspan:1,rowspan:1};}}this.redrawAllCells(A);},redrawAllCells:function(A){var B=this.node.closest('tr').closest('table');var C=B.rows[0].parentNode;Array.from(B.rows).forEach(function(r,ri){Array.from(r.cells).forEach(function(ce,ci){ce.parentNode.removeChild(ce);
-});r.parentNode.removeChild(r);});for(var r=0;r<A.length;r++){var re=B.rows[r];var re=B.ownerDocument.createElement('tr');C.appendChild(re);for(var c=0;c<A[r].length;c++){if(A[r][c].cell===false){continue;}re.appendChild(A[r][c].cell);A[r][c].cell=false;}
-}},updateWidths:function(A){for(var r=0;r<A.length;r++){for(var c=0;c<A[r].length;c++){if(A[r][c].cell===false){continue;}if(this.colWidths[0]!=false&&A[r][c].colspan<2){var el=Roo.htmleditor.Block.factory(A[r][c].cell);el.width=Math.floor(this.colWidths[c])+'%';
-el.updateElement(el.node);}A[r][c].cell=false;}}},normalizeWidths:function(A){if(this.colWidths[0]===false){var nw=100.0/this.colWidths.length;this.colWidths.forEach(function(w,i){this.colWidths[i]=nw;},this);return;}var t=0,B=[];this.colWidths.forEach(function(w,i){this.colWidths[i]=this.colWidths[i]==''?0:(this.colWidths[i]+'').replace(/[^0-9]+/g,'')*1;
-var D=this.colWidths[i];if(D>0){t+=D;return;}B.push(i);},this);var nc=this.colWidths.length;if(B.length){var C=(nc-B.length)/(1.0*nc);var t=C*t;var ew=(100-t)/(1.0*B.length);this.colWidths.forEach(function(w,i){if(w>0){this.colWidths[i]=w*C;return;}this.colWidths[i]=ew;
-},this);}},shrinkColumn:function(){var A=this.toTableArray();this.normalizeWidths(A);var B=this.cellData.col;var nw=this.colWidths[B]*0.8;if(nw<5){return;}var C=(this.colWidths[B]*0.2)/(this.colWidths.length-1);this.colWidths.forEach(function(w,i){if(i==B){this.colWidths[i]=nw;
-return;}this.colWidths[i]+=C},this);this.updateWidths(A);},growColumn:function(){var A=this.toTableArray();this.normalizeWidths(A);var B=this.cellData.col;var nw=this.colWidths[B]*1.2;if(nw>90){return;}var C=(this.colWidths[B]*0.2)/(this.colWidths.length-1);
-this.colWidths.forEach(function(w,i){if(i==B){this.colWidths[i]=nw;return;}this.colWidths[i]-=C},this);this.updateWidths(A);},deleteRow:function(){var A=this.toTableArray();for(var i=0;i<A[this.cellData.row].length;i++){var c=A[this.cellData.row][i];if(c.row!=this.cellData.row){c.rowspan--;
-c.cell.setAttribute('rowspan',c.rowspan);continue;}if(c.rowspan>1){c.rowspan--;c.cell.setAttribute('rowspan',c.rowspan);}}A.splice(this.cellData.row,1);this.redrawAllCells(A);},deleteColumn:function(){var A=this.toTableArray();for(var i=0;i<A.length;i++){var c=A[i][this.cellData.col];
-if(c.col!=this.cellData.col){A[i][this.cellData.col].colspan--;}else if(c.colspan>1){c.colspan--;c.cell.setAttribute('colspan',c.colspan);}A[i].splice(this.cellData.col,1);}this.redrawAllCells(A);}})
 // Roo/HtmlEditorCore.js
 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);
 // Roo/HtmlEditorCore.js
 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);
index 2d53d54..f4ef319 100644 (file)
@@ -1,4 +1,4 @@
-Roo.bootstrap = {};/**
+/**
  * set the version of bootstrap based on the stylesheet...
  *
  */
  * set the version of bootstrap based on the stylesheet...
  *
  */
@@ -25987,2834 +25987,221 @@ Roo.extend(Roo.bootstrap.form.SecurePass, Roo.bootstrap.form.Input, {
         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
     }
           
         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
     }
           
-});
-Roo.htmleditor = {};
+});//<script type="text/javascript">
+
+/*
+ * Based  Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ * LGPL
+ *
+ */
  
 /**
  
 /**
- * @class Roo.htmleditor.Filter
- * Base Class for filtering htmleditor stuff. - do not use this directly - extend it.
- * @cfg {DomElement} node The node to iterate and filter
- * @cfg {boolean|String|Array} tag Tags to replace 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
+ * @class Roo.HtmlEditorCore
+ * @extends Roo.Component
+ * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
+ *
+ * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
  */
 
  */
 
+Roo.HtmlEditorCore = function(config){
+    
+    
+    Roo.HtmlEditorCore.superclass.constructor.call(this, config);
+    
+    
+    this.addEvents({
+        /**
+         * @event initialize
+         * Fires when the editor is fully initialized (including the iframe)
+         * @param {Roo.HtmlEditorCore} this
+         */
+        initialize: true,
+        /**
+         * @event activate
+         * Fires when the editor is first receives the focus. Any insertion must wait
+         * until after this event.
+         * @param {Roo.HtmlEditorCore} this
+         */
+        activate: true,
+         /**
+         * @event beforesync
+         * Fires before the textarea is updated with content from the editor iframe. Return false
+         * to cancel the sync.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        beforesync: true,
+         /**
+         * @event beforepush
+         * Fires before the iframe editor is updated with content from the textarea. Return false
+         * to cancel the push.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        beforepush: true,
+         /**
+         * @event sync
+         * Fires when the textarea is updated with content from the editor iframe.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        sync: true,
+         /**
+         * @event push
+         * Fires when the iframe editor is updated with content from the textarea.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        push: true,
+        
+        /**
+         * @event editorevent
+         * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
+         * @param {Roo.HtmlEditorCore} this
+         */
+        editorevent: true 
+         
+        
+    });
+    
+    // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
+    
+    // defaults : white / black...
+    this.applyBlacklists();
+    
+    
+    
+};
 
 
 
 
-Roo.htmleditor.Filter = function(cfg) {
-    Roo.apply(this.cfg);
-    // this does not actually call walk as it's really just a abstract class
-}
+Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
 
 
 
 
-Roo.htmleditor.Filter.prototype = {
+     /**
+     * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
+     */
     
     
-    node: false,
+    owner : false,
     
     
-    tag: false,
-
-    // overrride to do replace comments.
-    replaceComment : false,
+     /**
+     * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
+     *                        Roo.resizable.
+     */
+    resizable : false,
+     /**
+     * @cfg {Number} height (in pixels)
+     */   
+    height: 300,
+   /**
+     * @cfg {Number} width (in pixels)
+     */   
+    width: 500,
+     /**
+     * @cfg {boolean} autoClean - default true - loading and saving will remove quite a bit of formating,
+     *         if you are doing an email editor, this probably needs disabling, it's designed
+     */
+    autoClean: true,
     
     
-    // overrride to do replace or do stuff with tags..
-    replaceTag : false,
+    /**
+     * @cfg {boolean} enableBlocks - default true - if the block editor (table and figure should be enabled)
+     */
+    enableBlocks : true,
+    /**
+     * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
+     * 
+     */
+    stylesheets: false,
+     /**
+     * @cfg {String} language default en - language of text (usefull for rtl languages)
+     * 
+     */
+    language: 'en',
     
     
-    walk : function(dom)
-    {
-        Roo.each( Array.from(dom.childNodes), function( e ) {
-            switch(true) {
-                
-                case e.nodeType == 8 &&  this.replaceComment  !== false: // comment
-                    this.replaceComment(e);
-                    return;
-                
-                case e.nodeType != 1: //not a node.
-                    return;
-                
-                case this.tag === true: // everything
-                case typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1: // array and it matches.
-                case typeof(this.tag) == 'string' && this.tag == e.tagName: // array and it matches.
-                    if (this.replaceTag && false === this.replaceTag(e)) {
-                        return;
-                    }
-                    if (e.hasChildNodes()) {
-                        this.walk(e);
-                    }
-                    return;
-                
-                default:    // tags .. that do not match.
-                    if (e.hasChildNodes()) {
-                        this.walk(e);
-                    }
-            }
-            
-        }, this);
-        
-    }
-}; 
-
-/**
- * @class Roo.htmleditor.FilterAttributes
- * clean attributes and  styles including http:// etc.. in attribute
- * @constructor
-* Run a new Attribute Filter
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterAttributes = function(cfg)
-{
-    Roo.apply(this, cfg);
-    this.attrib_black = this.attrib_black || [];
-    this.attrib_white = this.attrib_white || [];
-
-    this.attrib_clean = this.attrib_clean || [];
-    this.style_white = this.style_white || [];
-    this.style_black = this.style_black || [];
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterAttributes, Roo.htmleditor.Filter,
-{
-    tag: true, // all tags
+    /**
+     * @cfg {boolean} allowComments - default false - allow comments in HTML source
+     *          - by default they are stripped - if you are editing email you may need this.
+     */
+    allowComments: false,
+    // id of frame..
+    frameId: false,
     
     
-    attrib_black : false, // array
-    attrib_clean : false,
-    attrib_white : false,
-
-    style_white : false,
-    style_black : false,
-     
+    // private properties
+    validationEvent : false,
+    deferHeight: true,
+    initialized : false,
+    activated : false,
+    sourceEditMode : false,
+    onFocus : Roo.emptyFn,
+    iframePad:3,
+    hideMode:'offsets',
+    
+    clearUp: true,
+    
+    // blacklist + whitelisted elements..
+    black: false,
+    white: false,
      
      
-    replaceTag : function(node)
-    {
-        if (!node.attributes || !node.attributes.length) {
-            return true;
-        }
+    bodyCls : '',
+
+    
+    undoManager : false,
+    /**
+     * Protected method that will not generally be called directly. It
+     * is called when the editor initializes the iframe with HTML contents. Override this method if you
+     * want to change the initialization markup of the iframe (e.g. to add stylesheets).
+     */
+    getDocMarkup : function(){
+        // body styles..
+        var st = '';
         
         
-        for (var i = node.attributes.length-1; i > -1 ; i--) {
-            var a = node.attributes[i];
-            //console.log(a);
-            if (this.attrib_white.length && this.attrib_white.indexOf(a.name.toLowerCase()) < 0) {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            
-            
-            
-            if (a.name.toLowerCase().substr(0,2)=='on')  {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            
+        // inherit styels from page...?? 
+        if (this.stylesheets === false) {
             
             
-            if (this.attrib_black.indexOf(a.name.toLowerCase()) > -1) {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            if (this.attrib_clean.indexOf(a.name.toLowerCase()) > -1) {
-                this.cleanAttr(node,a.name,a.value); // fixme..
-                continue;
-            }
-            if (a.name == 'style') {
-                this.cleanStyle(node,a.name,a.value);
-                continue;
-            }
-            /// clean up MS crap..
-            // tecnically this should be a list of valid class'es..
+            Roo.get(document.head).select('style').each(function(node) {
+                st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
+            });
             
             
+            Roo.get(document.head).select('link').each(function(node) { 
+                st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
+            });
             
             
-            if (a.name == 'class') {
-                if (a.value.match(/^Mso/)) {
-                    node.removeAttribute('class');
-                }
-                
-                if (a.value.match(/^body$/)) {
-                    node.removeAttribute('class');
+        } else if (!this.stylesheets.length) {
+                // simple..
+                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;
                 }
                 }
-                continue;
+                st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
             }
             
             }
             
-            
-            // style cleanup!?
-            // class cleanup?
-            
         }
         }
-        return true; // clean children
-    },
         
         
-    cleanAttr: function(node, n,v)
-    {
+        st +=  '<style type="text/css">' +
+            'IMG { cursor: pointer } ' +
+        '</style>';
         
         
-        if (v.match(/^\./) || v.match(/^\//)) {
-            return;
-        }
-        if (v.match(/^(http|https):\/\//)
-            || v.match(/^mailto:/) 
-            || v.match(/^ftp:/)
-            || v.match(/^data:/)
-            ) {
-            return;
-        }
-        if (v.match(/^#/)) {
-            return;
-        }
-        if (v.match(/^\{/)) { // allow template editing.
-            return;
+        st += '<meta name="google" content="notranslate">';
+        
+        var cls = 'notranslate roo-htmleditor-body';
+        
+        if(this.bodyCls.length){
+            cls += ' ' + this.bodyCls;
         }
         }
-//            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
-        node.removeAttribute(n);
         
         
+        return '<html  class="notranslate" translate="no"><head>' + st  +
+            //<style type="text/css">' +
+            //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
+            //'</style>' +
+            ' </head><body contenteditable="true" data-enable-grammerly="true" class="' +  cls + '"></body></html>';
     },
     },
-    cleanStyle : function(node,  n,v)
-    {
-        if (v.match(/expression/)) { //XSS?? should we even bother..
-            node.removeAttribute(n);
-            return;
-        }
-        
-        var parts = v.split(/;/);
-        var clean = [];
-        
-        Roo.each(parts, function(p) {
-            p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
-            if (!p.length) {
-                return true;
-            }
-            var l = p.split(':').shift().replace(/\s+/g,'');
-            l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
-            
-            if ( this.style_black.length && (this.style_black.indexOf(l) > -1 || this.style_black.indexOf(l.toLowerCase()) > -1)) {
-                return true;
-            }
-            //Roo.log()
-            // only allow 'c whitelisted system attributes'
-            if ( this.style_white.length &&  style_white.indexOf(l) < 0 && style_white.indexOf(l.toLowerCase()) < 0 ) {
-                return true;
-            }
-            
-            
-            clean.push(p);
-            return true;
-        },this);
-        if (clean.length) { 
-            node.setAttribute(n, clean.join(';'));
-        } else {
-            node.removeAttribute(n);
-        }
-        
-    }
-        
-        
-        
-    
-});/**
- * @class Roo.htmleditor.FilterBlack
- * remove blacklisted elements.
- * @constructor
- * Run a new Blacklisted Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterBlack = function(cfg)
-{
-    Roo.apply(this, cfg);
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterBlack, Roo.htmleditor.Filter,
-{
-    tag : true, // all elements.
-   
-    replaceTag : function(n)
-    {
-        n.parentNode.removeChild(n);
-    }
-});
-/**
- * @class Roo.htmleditor.FilterComment
- * remove comments.
- * @constructor
-* Run a new Comments Filter
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterComment = function(cfg)
-{
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterComment, Roo.htmleditor.Filter,
-{
-  
-    replaceComment : function(n)
-    {
-        n.parentNode.removeChild(n);
-    }
-});/**
- * @class Roo.htmleditor.FilterKeepChildren
- * remove tags but keep children
- * @constructor
- * Run a new Keep Children Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterKeepChildren = function(cfg)
-{
-    Roo.apply(this, cfg);
-    if (this.tag === false) {
-        return; // dont walk.. (you can use this to use this just to do a child removal on a single tag )
-    }
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterKeepChildren, Roo.htmleditor.FilterBlack,
-{
-    
-  
-    replaceTag : function(node)
-    {
-        // walk children...
-        //Roo.log(node);
-        var ar = Array.from(node.childNodes);
-        //remove first..
-        for (var i = 0; i < ar.length; i++) {
-            if (ar[i].nodeType == 1) {
-                if (
-                    (typeof(this.tag) == 'object' && this.tag.indexOf(ar[i].tagName) > -1)
-                    || // array and it matches
-                    (typeof(this.tag) == 'string' && this.tag == ar[i].tagName)
-                ) {
-                    this.replaceTag(ar[i]); // child is blacklisted as well...
-                    continue;
-                }
-            }
-        }  
-        ar = Array.from(node.childNodes);
-        for (var i = 0; i < ar.length; i++) {
-         
-            node.removeChild(ar[i]);
-            // what if we need to walk these???
-            node.parentNode.insertBefore(ar[i], node);
-            if (this.tag !== false) {
-                this.walk(ar[i]);
-                
-            }
-        }
-        node.parentNode.removeChild(node);
-        return false; // don't walk children
-        
-        
-    }
-});/**
- * @class Roo.htmleditor.FilterParagraph
- * paragraphs cause a nightmare for shared content - this filter is designed to be called ? at various points when editing
- * like on 'push' to remove the <p> tags and replace them with line breaks.
- * @constructor
- * Run a new Paragraph Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterParagraph = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterParagraph, Roo.htmleditor.Filter,
-{
-    
-     
-    tag : 'P',
-    
-     
-    replaceTag : function(node)
-    {
-        
-        if (node.childNodes.length == 1 &&
-            node.childNodes[0].nodeType == 3 &&
-            node.childNodes[0].textContent.trim().length < 1
-            ) {
-            // remove and replace with '<BR>';
-            node.parentNode.replaceChild(node.ownerDocument.createElement('BR'),node);
-            return false; // no need to walk..
-        }
-        var ar = Array.from(node.childNodes);
-        for (var i = 0; i < ar.length; i++) {
-            node.removeChild(ar[i]);
-            // what if we need to walk these???
-            node.parentNode.insertBefore(ar[i], node);
-        }
-        // now what about this?
-        // <p> &nbsp; </p>
-        
-        // double BR.
-        node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
-        node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
-        node.parentNode.removeChild(node);
-        
-        return false;
-
-    }
-    
-});/**
- * @class Roo.htmleditor.FilterSpan
- * filter span's with no attributes out..
- * @constructor
- * Run a new Span Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterSpan = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterSpan, Roo.htmleditor.FilterKeepChildren,
-{
-     
-    tag : 'SPAN',
-     
-    replaceTag : function(node)
-    {
-        if (node.attributes && node.attributes.length > 0) {
-            return true; // walk if there are any.
-        }
-        Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this, node);
-        return false;
-     
-    }
-    
-});/**
- * @class Roo.htmleditor.FilterTableWidth
-  try and remove table width data - as that frequently messes up other stuff.
- * 
- *      was cleanTableWidths.
- *
- * Quite often pasting from word etc.. results in tables with column and widths.
- * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
- *
- * @constructor
- * Run a new Table Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterTableWidth = function(cfg)
-{
-    // no need to apply config.
-    this.tag = ['TABLE', 'TD', 'TR', 'TH', 'THEAD', 'TBODY' ];
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterTableWidth, Roo.htmleditor.Filter,
-{
-     
-     
-    
-    replaceTag: function(node) {
-        
-        
-      
-        if (node.hasAttribute('width')) {
-            node.removeAttribute('width');
-        }
-        
-         
-        if (node.hasAttribute("style")) {
-            // pretty basic...
-            
-            var styles = node.getAttribute("style").split(";");
-            var nstyle = [];
-            Roo.each(styles, function(s) {
-                if (!s.match(/:/)) {
-                    return;
-                }
-                var kv = s.split(":");
-                if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
-                    return;
-                }
-                // what ever is left... we allow.
-                nstyle.push(s);
-            });
-            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
-            if (!nstyle.length) {
-                node.removeAttribute('style');
-            }
-        }
-        
-        return true; // continue doing children..
-    }
-});/**
- * @class Roo.htmleditor.FilterWord
- * try and clean up all the mess that Word generates.
- * 
- * This is the 'nice version' - see 'Heavy' that white lists a very short list of elements, and multi-filters 
- * @constructor
- * Run a new Span Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterWord = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterWord, Roo.htmleditor.Filter,
-{
-    tag: true,
-     
-    
-    /**
-     * Clean up MS wordisms...
-     */
-    replaceTag : function(node)
-    {
-         
-        // no idea what this does - span with text, replaceds with just text.
-        if(
-                node.nodeName == 'SPAN' &&
-                !node.hasAttributes() &&
-                node.childNodes.length == 1 &&
-                node.firstChild.nodeName == "#text"  
-        ) {
-            var textNode = node.firstChild;
-            node.removeChild(textNode);
-            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
-                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
-            }
-            node.parentNode.insertBefore(textNode, node);
-            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
-                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
-            }
-            
-            node.parentNode.removeChild(node);
-            return false; // dont do chidren - we have remove our node - so no need to do chdhilren?
-        }
-        
-   
-        
-        if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
-            node.parentNode.removeChild(node);
-            return false; // dont do chidlren
-        }
-        //Roo.log(node.tagName);
-        // remove - but keep children..
-        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
-            //Roo.log('-- removed');
-            while (node.childNodes.length) {
-                var cn = node.childNodes[0];
-                node.removeChild(cn);
-                node.parentNode.insertBefore(cn, node);
-                // move node to parent - and clean it..
-                this.replaceTag(cn);
-            }
-            node.parentNode.removeChild(node);
-            /// no need to iterate chidlren = it's got none..
-            //this.iterateChildren(node, this.cleanWord);
-            return false; // no need to iterate children.
-        }
-        // clean styles
-        if (node.className.length) {
-            
-            var cn = node.className.split(/\W+/);
-            var cna = [];
-            Roo.each(cn, function(cls) {
-                if (cls.match(/Mso[a-zA-Z]+/)) {
-                    return;
-                }
-                cna.push(cls);
-            });
-            node.className = cna.length ? cna.join(' ') : '';
-            if (!cna.length) {
-                node.removeAttribute("class");
-            }
-        }
-        
-        if (node.hasAttribute("lang")) {
-            node.removeAttribute("lang");
-        }
-        
-        if (node.hasAttribute("style")) {
-            
-            var styles = node.getAttribute("style").split(";");
-            var nstyle = [];
-            Roo.each(styles, function(s) {
-                if (!s.match(/:/)) {
-                    return;
-                }
-                var kv = s.split(":");
-                if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
-                    return;
-                }
-                // what ever is left... we allow.
-                nstyle.push(s);
-            });
-            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
-            if (!nstyle.length) {
-                node.removeAttribute('style');
-            }
-        }
-        return true; // do children
-        
-        
-        
-    }
-});
-/**
- * @class Roo.htmleditor.FilterStyleToTag
- * part of the word stuff... - certain 'styles' should be converted to tags.
- * eg.
- *   font-weight: bold -> bold
- *   ?? super / subscrit etc..
- * 
- * @constructor
-* Run a new style to tag filter.
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterStyleToTag = function(cfg)
-{
-    
-    this.tags = {
-        B  : [ 'fontWeight' , 'bold'],
-        I :  [ 'fontStyle' , 'italic'],
-        //pre :  [ 'font-style' , 'italic'],
-        // h1.. h6 ?? font-size?
-        SUP : [ 'verticalAlign' , 'super' ],
-        SUB : [ 'verticalAlign' , 'sub' ]
-        
-        
-    };
-    
-    Roo.apply(this, cfg);
-     
-    
-    this.walk(cfg.node);
-    
-    
-    
-}
-
-
-Roo.extend(Roo.htmleditor.FilterStyleToTag, Roo.htmleditor.Filter,
-{
-    tag: true, // all tags
-    
-    tags : false,
-    
-    
-    replaceTag : function(node)
-    {
-        
-        
-        if (node.getAttribute("style") === null) {
-            return true;
-        }
-        var inject = [];
-        for (var k in this.tags) {
-            if (node.style[this.tags[k][0]] == this.tags[k][1]) {
-                inject.push(k);
-                node.style.removeProperty(this.tags[k][0]);
-            }
-        }
-        if (!inject.length) {
-            return true; 
-        }
-        var cn = Array.from(node.childNodes);
-        var nn = node;
-        Roo.each(inject, function(t) {
-            var nc = node.ownerDocument.createElement(t);
-            nn.appendChild(nc);
-            nn = nc;
-        });
-        for(var i = 0;i < cn.length;cn++) {
-            node.removeChild(cn[i]);
-            nn.appendChild(cn[i]);
-        }
-        return true /// iterate thru
-    }
-    
-})/**
- * @class Roo.htmleditor.FilterLongBr
- * BR/BR/BR - keep a maximum of 2...
- * @constructor
- * Run a new Long BR Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterLongBr = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterLongBr, Roo.htmleditor.Filter,
-{
-    
-     
-    tag : 'BR',
-    
-     
-    replaceTag : function(node)
-    {
-        
-        var ps = node.nextSibling;
-        while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
-            ps = ps.nextSibling;
-        }
-        
-        if (!ps &&  [ 'TD', 'TH', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(node.parentNode.tagName) > -1) { 
-            node.parentNode.removeChild(node); // remove last BR inside one fo these tags
-            return false;
-        }
-        
-        if (!ps || ps.nodeType != 1) {
-            return false;
-        }
-        
-        if (!ps || ps.tagName != 'BR') {
-           
-            return false;
-        }
-        
-        
-        
-        
-        
-        if (!node.previousSibling) {
-            return false;
-        }
-        var ps = node.previousSibling;
-        
-        while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
-            ps = ps.previousSibling;
-        }
-        if (!ps || ps.nodeType != 1) {
-            return false;
-        }
-        // if header or BR before.. then it's a candidate for removal.. - as we only want '2' of these..
-        if (!ps || [ 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(ps.tagName) < 0) {
-            return false;
-        }
-        
-        node.parentNode.removeChild(node); // remove me...
-        
-        return false; // no need to do children
-
-    }
-    
-}); 
-
-/**
- * @class Roo.htmleditor.FilterBlock
- * removes id / data-block and contenteditable that are associated with blocks
- * usage should be done on a cloned copy of the dom
- * @constructor
-* Run a new Attribute Filter { node : xxxx }}
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterBlock = function(cfg)
-{
-    Roo.apply(this, cfg);
-    var qa = cfg.node.querySelectorAll;
-    this.removeAttributes('data-block');
-    this.removeAttributes('contenteditable');
-    this.removeAttributes('id');
-    
-}
-
-Roo.apply(Roo.htmleditor.FilterBlock.prototype,
-{
-    node: true, // all tags
-     
-     
-    removeAttributes : function(attr)
-    {
-        var ar = this.node.querySelectorAll('*[' + attr + ']');
-        for (var i =0;i<ar.length;i++) {
-            ar[i].removeAttribute(attr);
-        }
-    }
-        
-        
-        
-    
-});
-/**
- * @class Roo.htmleditor.KeyEnter
- * Handle Enter press..
- * @cfg {Roo.HtmlEditorCore} core the editor.
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-
-
-
-
-Roo.htmleditor.KeyEnter = function(cfg) {
-    Roo.apply(this, cfg);
-    // this does not actually call walk as it's really just a abstract class
-    Roo.get(this.core.doc.body).on('keypress', this.keypress, this);
-}
-
-//Roo.htmleditor.KeyEnter.i = 0;
-
-
-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();
-        // https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
-        var doc = this.core.doc;
-          //add a new line
-       
-    
-        var sel = this.core.getSelection();
-        var range = sel.getRangeAt(0);
-        var n = range.commonAncestorContainer;
-        var pc = range.closest([ 'ol', 'ul']);
-        var pli = range.closest('li');
-        if (!pc || e.ctrlKey) {
-            sel.insertNode('br', 'after'); 
-         
-            this.core.undoManager.addEvent();
-            this.core.fireEditorEvent(e);
-            return false;
-        }
-        
-        // deal with <li> insetion
-        if (pli.innerText.trim() == '' &&
-            pli.previousSibling &&
-            pli.previousSibling.nodeName == 'LI' &&
-            pli.previousSibling.innerText.trim() ==  '') {
-            pli.parentNode.removeChild(pli.previousSibling);
-            sel.cursorAfter(pc);
-            this.core.undoManager.addEvent();
-            this.core.fireEditorEvent(e);
-            return false;
-        }
-    
-        var li = doc.createElement('LI');
-        li.innerHTML = '&nbsp;';
-        if (!pli || !pli.firstSibling) {
-            pc.appendChild(li);
-        } else {
-            pli.parentNode.insertBefore(li, pli.firstSibling);
-        }
-        sel.cursorText (li.firstChild);
-      
-        this.core.undoManager.addEvent();
-        this.core.fireEditorEvent(e);
-
-        return false;
-        
-    
-        
-        
-         
-    }
-};
-     
-/**
- * @class Roo.htmleditor.Block
- * Base class for html editor blocks - do not use it directly .. extend it..
- * @cfg {DomElement} node The node to apply stuff to.
- * @cfg {String} friendly_name the name that appears in the context bar about this block
- * @cfg {Object} Context menu - see Roo.form.HtmlEditor.ToolbarContext
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.Block  = function(cfg)
-{
-    // do nothing .. should not be called really.
-}
-/**
- * factory method to get the block from an element (using cache if necessary)
- * @static
- * @param {HtmlElement} the dom element
- */
-Roo.htmleditor.Block.factory = function(node)
-{
-    var cc = Roo.htmleditor.Block.cache;
-    var id = Roo.get(node).id;
-    if (typeof(cc[id]) != 'undefined' && (!cc[id].node || cc[id].node.closest('body'))) {
-        Roo.htmleditor.Block.cache[id].readElement(node);
-        return Roo.htmleditor.Block.cache[id];
-    }
-    var db  = node.getAttribute('data-block');
-    if (!db) {
-        db = node.nodeName.toLowerCase().toUpperCaseFirst();
-    }
-    var cls = Roo.htmleditor['Block' + db];
-    if (typeof(cls) == 'undefined') {
-        //Roo.log(node.getAttribute('data-block'));
-        Roo.log("OOps missing block : " + 'Block' + db);
-        return false;
-    }
-    Roo.htmleditor.Block.cache[id] = new cls({ node: node });
-    return Roo.htmleditor.Block.cache[id];  /// should trigger update element
-};
-
-/**
- * initalize all Elements from content that are 'blockable'
- * @static
- * @param the body element
- */
-Roo.htmleditor.Block.initAll = function(body, type)
-{
-    if (typeof(type) == 'undefined') {
-        var ia = Roo.htmleditor.Block.initAll;
-        ia(body,'table');
-        ia(body,'td');
-        ia(body,'figure');
-        return;
-    }
-    Roo.each(Roo.get(body).query(type), function(e) {
-        Roo.htmleditor.Block.factory(e);    
-    },this);
-};
-// question goes here... do we need to clear out this cache sometimes?
-// or show we make it relivant to the htmleditor.
-Roo.htmleditor.Block.cache = {};
-
-Roo.htmleditor.Block.prototype = {
-    
-    node : false,
-    
-     // used by context menu
-    friendly_name : 'Based Block',
-    
-    // text for button to delete this element
-    deleteTitle : false,
-    
-    context : false,
-    /**
-     * Update a node with values from this object
-     * @param {DomElement} node
-     */
-    updateElement : function(node)
-    {
-        Roo.DomHelper.update(node === undefined ? this.node : node, this.toObject());
-    },
-     /**
-     * convert to plain HTML for calling insertAtCursor..
-     */
-    toHTML : function()
-    {
-        return Roo.DomHelper.markup(this.toObject());
-    },
-    /**
-     * used by readEleemnt to extract data from a node
-     * may need improving as it's pretty basic
-     
-     * @param {DomElement} node
-     * @param {String} tag - tag to find, eg. IMG ?? might be better to use DomQuery ?
-     * @param {String} attribute (use html - for contents, or style for using next param as style)
-     * @param {String} style the style property - eg. text-align
-     */
-    getVal : function(node, tag, attr, style)
-    {
-        var n = node;
-        if (tag !== true && n.tagName != tag.toUpperCase()) {
-            // in theory we could do figure[3] << 3rd figure? or some more complex search..?
-            // but kiss for now.
-            n = node.getElementsByTagName(tag).item(0);
-        }
-        if (!n) {
-            return '';
-        }
-        if (attr == 'html') {
-            return n.innerHTML;
-        }
-        if (attr == 'style') {
-            return n.style[style]; 
-        }
-        
-        return n.hasAttribute(attr) ? n.getAttribute(attr) : '';
-            
-    },
-    /**
-     * create a DomHelper friendly object - for use with 
-     * Roo.DomHelper.markup / overwrite / etc..
-     * (override this)
-     */
-    toObject : function()
-    {
-        return {};
-    },
-      /**
-     * Read a node that has a 'data-block' property - and extract the values from it.
-     * @param {DomElement} node - the node
-     */
-    readElement : function(node)
-    {
-        
-    } 
-    
-    
-};
-
-
-/**
- * @class Roo.htmleditor.BlockFigure
- * Block that has an image and a figcaption
- * @cfg {String} image_src the url for the image
- * @cfg {String} align (left|right) alignment for the block default left
- * @cfg {String} caption the text to appear below  (and in the alt tag)
- * @cfg {String} caption_display (block|none) display or not the caption
- * @cfg {String|number} image_width the width of the image number or %?
- * @cfg {String|number} image_height the height of the image number or %?
- * 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.BlockFigure = function(cfg)
-{
-    if (cfg.node) {
-        this.readElement(cfg.node);
-        this.updateElement(cfg.node);
-    }
-    Roo.apply(this, cfg);
-}
-Roo.extend(Roo.htmleditor.BlockFigure, Roo.htmleditor.Block, {
-    
-    // setable values.
-    image_src: '',
-    align: 'center',
-    caption : '',
-    caption_display : 'block',
-    width : '100%',
-    cls : '',
-    href: '',
-    video_url : '',
-    
-    // margin: '2%', not used
-    
-    text_align: 'left', //   (left|right) alignment for the text caption default left. - not used at present
-
-    
-    // used by context menu
-    friendly_name : 'Image with caption',
-    deleteTitle : "Delete Image and Caption",
-    
-    contextMenu : function(toolbar)
-    {
-        
-        var block = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
-        };
-        
-        
-        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
-        
-        var syncValue = toolbar.editorcore.syncValue;
-        
-        var fields = {};
-        
-        return [
-             {
-                xtype : 'TextItem',
-                text : "Source: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'Button',
-                text: 'Change Image URL',
-                 
-                listeners : {
-                    click: function (btn, state)
-                    {
-                        var b = block();
-                        
-                        Roo.MessageBox.show({
-                            title : "Image Source URL",
-                            msg : "Enter the url for the image",
-                            buttons: Roo.MessageBox.OKCANCEL,
-                            fn: function(btn, val){
-                                if (btn != 'ok') {
-                                    return;
-                                }
-                                b.image_src = val;
-                                b.updateElement();
-                                syncValue();
-                                toolbar.editorcore.onEditorEvent();
-                            },
-                            minWidth:250,
-                            prompt:true,
-                            //multiline: multiline,
-                            modal : true,
-                            value : b.image_src
-                        });
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-         
-            {
-                xtype : 'Button',
-                text: 'Change Link URL',
-                 
-                listeners : {
-                    click: function (btn, state)
-                    {
-                        var b = block();
-                        
-                        Roo.MessageBox.show({
-                            title : "Link URL",
-                            msg : "Enter the url for the link - leave blank to have no link",
-                            buttons: Roo.MessageBox.OKCANCEL,
-                            fn: function(btn, val){
-                                if (btn != 'ok') {
-                                    return;
-                                }
-                                b.href = val;
-                                b.updateElement();
-                                syncValue();
-                                toolbar.editorcore.onEditorEvent();
-                            },
-                            minWidth:250,
-                            prompt:true,
-                            //multiline: multiline,
-                            modal : true,
-                            value : b.href
-                        });
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: 'Show Video URL',
-                 
-                listeners : {
-                    click: function (btn, state)
-                    {
-                        Roo.MessageBox.alert("Video URL",
-                            block().video_url == '' ? 'This image is not linked ot a video' :
-                                'The image is linked to: <a target="_new" href="' + block().video_url + '">' + block().video_url + '</a>');
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            
-            
-            {
-                xtype : 'TextItem',
-                text : "Width: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 70,
-                name : 'width',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = block();
-                        b.width = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.form,
-                store : {
-                    xtype : 'SimpleStore',
-                    data : [
-                        ['auto'],
-                        ['50%'],
-                        ['100%']
-                    ],
-                    fields : [ 'val'],
-                    xns : Roo.data
-                }
-            },
-            {
-                xtype : 'TextItem',
-                text : "Align: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 70,
-                name : 'align',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = block();
-                        b.align = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.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 (btn, state)
-                    {
-                        var b  = block();
-                        b.caption_display = b.caption_display == 'block' ? 'none' : 'block';
-                        this.setText(b.caption_display == 'block' ? "Hide Caption" : "Show Caption");
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            }
-        ];
-        
-    },
-    /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     */
-    toObject : function()
-    {
-        var d = document.createElement('div');
-        d.innerHTML = this.caption;
-        
-        var m = this.width == '50%' && this.align == 'center' ? '0 auto' : 0; 
-        
-        var img =   {
-            tag : 'img',
-            contenteditable : 'false',
-            src : this.image_src,
-            alt : d.innerText.replace(/\n/g, " ").replace(/\s+/g, ' ').trim(), // removeHTML and reduce spaces..
-            style: {
-                width : 'auto',
-                'max-width': '100%',
-                margin : '0px' 
-                
-                
-            }
-        };
-        /*
-        '<div class="{0}" width="420" height="315" src="{1}" frameborder="0" allowfullscreen>' +
-                    '<a href="{2}">' + 
-                        '<img class="{0}-thumbnail" src="{3}/Images/{4}/{5}#image-{4}" />' + 
-                    '</a>' + 
-                '</div>',
-        */
-                
-        if (this.href.length > 0) {
-            img = {
-                tag : 'a',
-                href: this.href,
-                contenteditable : 'true',
-                cn : [
-                    img
-                ]
-            };
-        }
-        
-        
-        if (this.video_url.length > 0) {
-            img = {
-                tag : 'div',
-                cls : this.cls,
-                frameborder : 0,
-                allowfullscreen : true,
-                width : 420,  // these are for video tricks - that we replace the outer
-                height : 315,
-                src : this.video_url,
-                cn : [
-                    img
-                ]
-            };
-        }
-        
-        var captionhtml = this.caption_display == 'hidden' ? this.caption : (this.caption.length ? this.caption : "Caption");
-        
-        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 : [
-                img,
-              
-                {
-                    tag: 'figcaption',
-                    
-                    style : {
-                        'text-align': 'left',
-                        'margin-top' : '16px',
-                        'font-size' : '16px',
-                        'line-height' : '24px',
-                         display : this.caption_display
-                    },
-                    cls : this.cls.length > 0 ? (this.cls  + '-thumbnail' ) : '',
-                    cn : [
-                        {
-                            // we can not rely on yahoo syndication to use CSS elements - so have to use  '<i>' to encase stuff.
-                            tag : 'i',
-                            contenteditable : true,
-                            html : captionhtml
-                        }
-                    ]
-                    
-                }
-            ]
-        };
-         
-    },
-    
-    readElement : function(node)
-    {
-        // this should not really come from the link...
-        this.video_url = this.getVal(node, 'div', 'src');
-        this.cls = this.getVal(node, 'div', 'class');
-        this.href = this.getVal(node, 'a', 'href');
-        
-        this.image_src = this.getVal(node, 'img', 'src');
-         
-        this.align = this.getVal(node, 'figure', 'align');
-        this.caption = this.getVal(node, 'figcaption', 'html');
-        // remove '<i>
-        if (this.caption.trim().match(/^<i[^>]*>/i)) {
-            this.caption = this.caption.trim().replace(/^<i[^>]*>/i, '').replace(/^<\/i>$/i, '');
-        }
-        //this.text_align = this.getVal(node, 'figcaption', 'style','text-align');
-        this.width = this.getVal(node, 'figure', 'style', 'max-width');
-        //this.margin = this.getVal(node, 'figure', 'style', 'margin');
-        
-    },
-    removeNode : function()
-    {
-        return this.node;
-    }
-    
-  
-   
-     
-    
-    
-    
-    
-})
-
-
-/**
- * @class Roo.htmleditor.BlockTable
- * Block that manages a table
- * 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.BlockTable = function(cfg)
-{
-    if (cfg.node) {
-        this.readElement(cfg.node);
-        this.updateElement(cfg.node);
-    }
-    Roo.apply(this, cfg);
-    if (!cfg.node) {
-        this.rows = [];
-        for(var r = 0; r < this.no_row; r++) {
-            this.rows[r] = [];
-            for(var c = 0; c < this.no_col; c++) {
-                this.rows[r][c] = this.emptyCell();
-            }
-        }
-    }
-    
-    
-}
-Roo.extend(Roo.htmleditor.BlockTable, Roo.htmleditor.Block, {
-    rows : false,
-    no_col : 1,
-    no_row : 1,
-    
-    
-    width: '100%',
-    
-    // used by context menu
-    friendly_name : 'Table',
-    deleteTitle : 'Delete Table',
-    // context menu is drawn once..
-    
-    contextMenu : function(toolbar)
-    {
-        
-        var block = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
-        };
-        
-        
-        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
-        
-        var syncValue = toolbar.editorcore.syncValue;
-        
-        var fields = {};
-        
-        return [
-            {
-                xtype : 'TextItem',
-                text : "Width: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 100,
-                name : 'width',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = block();
-                        b.width = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.form,
-                store : {
-                    xtype : 'SimpleStore',
-                    data : [
-                        ['100%'],
-                        ['auto']
-                    ],
-                    fields : [ 'val'],
-                    xns : Roo.data
-                }
-            },
-            // -------- Cols
-            
-            {
-                xtype : 'TextItem',
-                text : "Columns: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-         
-            {
-                xtype : 'Button',
-                text: '-',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        block().removeColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: '+',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        block().addColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            // -------- ROWS
-            {
-                xtype : 'TextItem',
-                text : "Rows: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-         
-            {
-                xtype : 'Button',
-                text: '-',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        block().removeRow();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: '+',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        block().addRow();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            // -------- ROWS
-            {
-                xtype : 'Button',
-                text: 'Reset Column Widths',
-                listeners : {
-                    
-                    click : function (_self, e)
-                    {
-                        block().resetWidths();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            } 
-            
-            
-            
-        ];
-        
-    },
-    
-    
-  /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     * ?? should it be called with option to hide all editing features?
-     */
-    toObject : function()
-    {
-        
-        var ret = {
-            tag : 'table',
-            contenteditable : 'false', // this stops cell selection from picking the table.
-            'data-block' : 'Table',
-            style : {
-                width:  this.width,
-                border : 'solid 1px #000', // ??? hard coded?
-                'border-collapse' : 'collapse' 
-            },
-            cn : [
-                { tag : 'tbody' , cn : [] }
-            ]
-        };
-        
-        // do we have a head = not really 
-        var ncols = 0;
-        Roo.each(this.rows, function( row ) {
-            var tr = {
-                tag: 'tr',
-                style : {
-                    margin: '6px',
-                    border : 'solid 1px #000',
-                    textAlign : 'left' 
-                },
-                cn : [ ]
-            };
-            
-            ret.cn[0].cn.push(tr);
-            // does the row have any properties? ?? height?
-            var nc = 0;
-            Roo.each(row, function( cell ) {
-                
-                var td = {
-                    tag : 'td',
-                    contenteditable :  'true',
-                    'data-block' : 'Td',
-                    html : cell.html,
-                    style : cell.style
-                };
-                if (cell.colspan > 1) {
-                    td.colspan = cell.colspan ;
-                    nc += cell.colspan;
-                } else {
-                    nc++;
-                }
-                if (cell.rowspan > 1) {
-                    td.rowspan = cell.rowspan ;
-                }
-                
-                
-                // widths ?
-                tr.cn.push(td);
-                    
-                
-            }, this);
-            ncols = Math.max(nc, ncols);
-            
-            
-        }, this);
-        // add the header row..
-        
-        ncols++;
-         
-        
-        return ret;
-         
-    },
-    
-    readElement : function(node)
-    {
-        node  = node ? node : this.node ;
-        this.width = this.getVal(node, true, 'style', 'width') || '100%';
-        
-        this.rows = [];
-        this.no_row = 0;
-        var trs = Array.from(node.rows);
-        trs.forEach(function(tr) {
-            var row =  [];
-            this.rows.push(row);
-            
-            this.no_row++;
-            var no_column = 0;
-            Array.from(tr.cells).forEach(function(td) {
-                
-                var add = {
-                    colspan : td.hasAttribute('colspan') ? td.getAttribute('colspan')*1 : 1,
-                    rowspan : td.hasAttribute('rowspan') ? td.getAttribute('rowspan')*1 : 1,
-                    style : td.hasAttribute('style') ? td.getAttribute('style') : '',
-                    html : td.innerHTML
-                };
-                no_column += add.colspan;
-                     
-                
-                row.push(add);
-                
-                
-            },this);
-            this.no_col = Math.max(this.no_col, no_column);
-            
-            
-        },this);
-        
-        
-    },
-    normalizeRows: function()
-    {
-        var ret= [];
-        var rid = -1;
-        this.rows.forEach(function(row) {
-            rid++;
-            ret[rid] = [];
-            row = this.normalizeRow(row);
-            var cid = 0;
-            row.forEach(function(c) {
-                while (typeof(ret[rid][cid]) != 'undefined') {
-                    cid++;
-                }
-                if (typeof(ret[rid]) == 'undefined') {
-                    ret[rid] = [];
-                }
-                ret[rid][cid] = c;
-                c.row = rid;
-                c.col = cid;
-                if (c.rowspan < 2) {
-                    return;
-                }
-                
-                for(var i = 1 ;i < c.rowspan; i++) {
-                    if (typeof(ret[rid+i]) == 'undefined') {
-                        ret[rid+i] = [];
-                    }
-                    ret[rid+i][cid] = c;
-                }
-            });
-        }, this);
-        return ret;
-    
-    },
-    
-    normalizeRow: function(row)
-    {
-        var ret= [];
-        row.forEach(function(c) {
-            if (c.colspan < 2) {
-                ret.push(c);
-                return;
-            }
-            for(var i =0 ;i < c.colspan; i++) {
-                ret.push(c);
-            }
-        });
-        return ret;
-    
-    },
-    
-    deleteColumn : function(sel)
-    {
-        if (!sel || sel.type != 'col') {
-            return;
-        }
-        if (this.no_col < 2) {
-            return;
-        }
-        
-        this.rows.forEach(function(row) {
-            var cols = this.normalizeRow(row);
-            var col = cols[sel.col];
-            if (col.colspan > 1) {
-                col.colspan --;
-            } else {
-                row.remove(col);
-            }
-            
-        }, this);
-        this.no_col--;
-        
-    },
-    removeColumn : function()
-    {
-        this.deleteColumn({
-            type: 'col',
-            col : this.no_col-1
-        });
-        this.updateElement();
-    },
-    
-     
-    addColumn : function()
-    {
-        
-        this.rows.forEach(function(row) {
-            row.push(this.emptyCell());
-           
-        }, this);
-        this.updateElement();
-    },
-    
-    deleteRow : function(sel)
-    {
-        if (!sel || sel.type != 'row') {
-            return;
-        }
-        
-        if (this.no_row < 2) {
-            return;
-        }
-        
-        var rows = this.normalizeRows();
-        
-        
-        rows[sel.row].forEach(function(col) {
-            if (col.rowspan > 1) {
-                col.rowspan--;
-            } else {
-                col.remove = 1; // flage it as removed.
-            }
-            
-        }, this);
-        var newrows = [];
-        this.rows.forEach(function(row) {
-            newrow = [];
-            row.forEach(function(c) {
-                if (typeof(c.remove) == 'undefined') {
-                    newrow.push(c);
-                }
-                
-            });
-            if (newrow.length > 0) {
-                newrows.push(row);
-            }
-        });
-        this.rows =  newrows;
-        
-        
-        
-        this.no_row--;
-        this.updateElement();
-        
-    },
-    removeRow : function()
-    {
-        this.deleteRow({
-            type: 'row',
-            row : this.no_row-1
-        });
-        
-    },
-    
-     
-    addRow : function()
-    {
-        
-        var row = [];
-        for (var i = 0; i < this.no_col; i++ ) {
-            
-            row.push(this.emptyCell());
-           
-        }
-        this.rows.push(row);
-        this.updateElement();
-        
-    },
-     
-    // the default cell object... at present...
-    emptyCell : function() {
-        return (new Roo.htmleditor.BlockTd({})).toObject();
-        
-     
-    },
-    
-    removeNode : function()
-    {
-        return this.node;
-    },
-    
-    
-    
-    resetWidths : function()
-    {
-        Array.from(this.node.getElementsByTagName('td')).forEach(function(n) {
-            var nn = Roo.htmleditor.Block.factory(n);
-            nn.width = '';
-            nn.updateElement(n);
-        });
-    }
-    
-    
-    
-    
-})
-
-/**
- *
- * editing a TD?
- *
- * since selections really work on the table cell, then editing really should work from there
- *
- * The original plan was to support merging etc... - but that may not be needed yet..
- *
- * So this simple version will support:
- *   add/remove cols
- *   adjust the width +/-
- *   reset the width...
- *   
- *
- */
-
-
-
-/**
- * @class Roo.htmleditor.BlockTable
- * Block that manages a table
- * 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.BlockTd = function(cfg)
-{
-    if (cfg.node) {
-        this.readElement(cfg.node);
-        this.updateElement(cfg.node);
-    }
-    Roo.apply(this, cfg);
-     
-    
-    
-}
-Roo.extend(Roo.htmleditor.BlockTd, Roo.htmleditor.Block, {
-    node : false,
-    
-    width: '',
-    textAlign : 'left',
-    valign : 'top',
-    
-    colspan : 1,
-    rowspan : 1,
-    
-    
-    // used by context menu
-    friendly_name : 'Table Cell',
-    deleteTitle : false, // use our customer delete
-    
-    // context menu is drawn once..
-    
-    contextMenu : function(toolbar)
-    {
-        
-        var cell = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
-        };
-        
-        var table = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode.closest('table'));
-        };
-        
-        var lr = false;
-        var saveSel = function()
-        {
-            lr = toolbar.editorcore.getSelection().getRangeAt(0);
-        }
-        var restoreSel = function()
-        {
-            if (lr) {
-                (function() {
-                    toolbar.editorcore.focus();
-                    var cr = toolbar.editorcore.getSelection();
-                    cr.removeAllRanges();
-                    cr.addRange(lr);
-                    toolbar.editorcore.onEditorEvent();
-                }).defer(10, this);
-                
-                
-            }
-        }
-        
-        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
-        
-        var syncValue = toolbar.editorcore.syncValue;
-        
-        var fields = {};
-        
-        return [
-            {
-                xtype : 'Button',
-                text : 'Edit Table',
-                listeners : {
-                    click : function() {
-                        var t = toolbar.tb.selectedNode.closest('table');
-                        toolbar.editorcore.selectNode(t);
-                        toolbar.editorcore.onEditorEvent();                        
-                    }
-                }
-                
-            },
-              
-           
-             
-            {
-                xtype : 'TextItem',
-                text : "Column Width: ",
-                 xns : rooui.Toolbar 
-               
-            },
-            {
-                xtype : 'Button',
-                text: '-',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().shrinkColumn();
-                        syncValue();
-                         toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: '+',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().growColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            
-            {
-                xtype : 'TextItem',
-                text : "Vertical Align: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 100,
-                name : 'valign',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = cell();
-                        b.valign = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.form,
-                store : {
-                    xtype : 'SimpleStore',
-                    data : [
-                        ['top'],
-                        ['middle'],
-                        ['bottom'] // there are afew more... 
-                    ],
-                    fields : [ 'val'],
-                    xns : Roo.data
-                }
-            },
-            
-            {
-                xtype : 'TextItem',
-                text : "Merge Cells: ",
-                 xns : rooui.Toolbar 
-               
-            },
-            
-            
-            {
-                xtype : 'Button',
-                text: 'Right',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().mergeRight();
-                        //block().growColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-             
-            {
-                xtype : 'Button',
-                text: 'Below',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().mergeBelow();
-                        //block().growColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'TextItem',
-                text : "| ",
-                 xns : rooui.Toolbar 
-               
-            },
-            
-            {
-                xtype : 'Button',
-                text: 'Split',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        //toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().split();
-                        syncValue();
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        toolbar.editorcore.onEditorEvent();
-                                             
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Fill',
-                xns : rooui.Toolbar 
-               
-            },
-        
-          
-            {
-                xtype : 'Button',
-                text: 'Delete',
-                 
-                xns : rooui.Toolbar,
-                menu : {
-                    xtype : 'Menu',
-                    xns : rooui.menu,
-                    items : [
-                        {
-                            xtype : 'Item',
-                            html: 'Column',
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var t = table();
-                                    
-                                    cell().deleteColumn();
-                                    syncValue();
-                                    toolbar.editorcore.selectNode(t.node);
-                                    toolbar.editorcore.onEditorEvent();   
-                                }
-                            },
-                            xns : rooui.menu
-                        },
-                        {
-                            xtype : 'Item',
-                            html: 'Row',
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var t = table();
-                                    cell().deleteRow();
-                                    syncValue();
-                                    
-                                    toolbar.editorcore.selectNode(t.node);
-                                    toolbar.editorcore.onEditorEvent();   
-                                                         
-                                }
-                            },
-                            xns : rooui.menu
-                        },
-                       {
-                            xtype : 'Separator',
-                            xns : rooui.menu
-                        },
-                        {
-                            xtype : 'Item',
-                            html: 'Table',
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var t = table();
-                                    var nn = t.node.nextSibling || t.node.previousSibling;
-                                    t.node.parentNode.removeChild(t.node);
-                                    if (nn) { 
-                                        toolbar.editorcore.selectNode(nn, true);
-                                    }
-                                    toolbar.editorcore.onEditorEvent();   
-                                                         
-                                }
-                            },
-                            xns : rooui.menu
-                        }
-                    ]
-                }
-            }
-            
-            // align... << fixme
-            
-        ];
-        
-    },
-    
-    
-  /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     * ?? should it be called with option to hide all editing features?
-     */
- /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     * ?? should it be called with option to hide all editing features?
-     */
-    toObject : function()
-    {
-        
-        var ret = {
-            tag : 'td',
-            contenteditable : 'true', // this stops cell selection from picking the table.
-            'data-block' : 'Td',
-            valign : this.valign,
-            style : {  
-                'text-align' :  this.textAlign,
-                border : 'solid 1px rgb(0, 0, 0)', // ??? hard coded?
-                'border-collapse' : 'collapse',
-                padding : '6px', // 8 for desktop / 4 for mobile
-                'vertical-align': this.valign
-            },
-            html : this.html
-        };
-        if (this.width != '') {
-            ret.width = this.width;
-            ret.style.width = this.width;
-        }
-        
-        
-        if (this.colspan > 1) {
-            ret.colspan = this.colspan ;
-        } 
-        if (this.rowspan > 1) {
-            ret.rowspan = this.rowspan ;
-        }
-        
-           
-        
-        return ret;
-         
-    },
-    
-    readElement : function(node)
-    {
-        node  = node ? node : this.node ;
-        this.width = node.style.width;
-        this.colspan = Math.max(1,1*node.getAttribute('colspan'));
-        this.rowspan = Math.max(1,1*node.getAttribute('rowspan'));
-        this.html = node.innerHTML;
-        
-        
-    },
-     
-    // the default cell object... at present...
-    emptyCell : function() {
-        return {
-            colspan :  1,
-            rowspan :  1,
-            textAlign : 'left',
-            html : "&nbsp;" // is this going to be editable now?
-        };
-     
-    },
-    
-    removeNode : function()
-    {
-        return this.node.closest('table');
-         
-    },
-    
-    cellData : false,
-    
-    colWidths : false,
-    
-    toTableArray  : function()
-    {
-        var ret = [];
-        var tab = this.node.closest('tr').closest('table');
-        Array.from(tab.rows).forEach(function(r, ri){
-            ret[ri] = [];
-        });
-        var rn = 0;
-        this.colWidths = [];
-        var all_auto = true;
-        Array.from(tab.rows).forEach(function(r, ri){
-            
-            var cn = 0;
-            Array.from(r.cells).forEach(function(ce, ci){
-                var c =  {
-                    cell : ce,
-                    row : rn,
-                    col: cn,
-                    colspan : ce.colSpan,
-                    rowspan : ce.rowSpan
-                };
-                if (ce.isEqualNode(this.node)) {
-                    this.cellData = c;
-                }
-                // if we have been filled up by a row?
-                if (typeof(ret[rn][cn]) != 'undefined') {
-                    while(typeof(ret[rn][cn]) != 'undefined') {
-                        cn++;
-                    }
-                    c.col = cn;
-                }
-                
-                if (typeof(this.colWidths[cn]) == 'undefined') {
-                    this.colWidths[cn] =   ce.style.width;
-                    if (this.colWidths[cn] != '') {
-                        all_auto = false;
-                    }
-                }
-                
-                
-                if (c.colspan < 2 && c.rowspan < 2 ) {
-                    ret[rn][cn] = c;
-                    cn++;
-                    return;
-                }
-                for(var j = 0; j < c.rowspan; j++) {
-                    if (typeof(ret[rn+j]) == 'undefined') {
-                        continue; // we have a problem..
-                    }
-                    ret[rn+j][cn] = c;
-                    for(var i = 0; i < c.colspan; i++) {
-                        ret[rn+j][cn+i] = c;
-                    }
-                }
-                
-                cn += c.colspan;
-            }, this);
-            rn++;
-        }, this);
-        
-        // initalize widths.?
-        // either all widths or no widths..
-        if (all_auto) {
-            this.colWidths[0] = false; // no widths flag.
-        }
-        
-        
-        return ret;
-        
-    },
-    
-    
-    
-    
-    mergeRight: function()
-    {
-         
-        // get the contents of the next cell along..
-        var tr = this.node.closest('tr');
-        var i = Array.prototype.indexOf.call(tr.childNodes, this.node);
-        if (i >= tr.childNodes.length - 1) {
-            return; // no cells on right to merge with.
-        }
-        var table = this.toTableArray();
-        
-        if (typeof(table[this.cellData.row][this.cellData.col+this.cellData.colspan]) == 'undefined') {
-            return; // nothing right?
-        }
-        var rc = table[this.cellData.row][this.cellData.col+this.cellData.colspan];
-        // right cell - must be same rowspan and on the same row.
-        if (rc.rowspan != this.cellData.rowspan || rc.row != this.cellData.row) {
-            return; // right hand side is not same rowspan.
-        }
-        
-        
-        
-        this.node.innerHTML += ' ' + rc.cell.innerHTML;
-        tr.removeChild(rc.cell);
-        this.colspan += rc.colspan;
-        this.node.setAttribute('colspan', this.colspan);
-
-    },
-    
-    
-    mergeBelow : function()
-    {
-        var table = this.toTableArray();
-        if (typeof(table[this.cellData.row+this.cellData.rowspan]) == 'undefined') {
-            return; // no row below
-        }
-        if (typeof(table[this.cellData.row+this.cellData.rowspan][this.cellData.col]) == 'undefined') {
-            return; // nothing right?
-        }
-        var rc = table[this.cellData.row+this.cellData.rowspan][this.cellData.col];
-        
-        if (rc.colspan != this.cellData.colspan || rc.col != this.cellData.col) {
-            return; // right hand side is not same rowspan.
-        }
-        this.node.innerHTML =  this.node.innerHTML + rc.cell.innerHTML ;
-        rc.cell.parentNode.removeChild(rc.cell);
-        this.rowspan += rc.rowspan;
-        this.node.setAttribute('rowspan', this.rowspan);
-    },
-    
-    split: function()
-    {
-        if (this.node.rowSpan < 2 && this.node.colSpan < 2) {
-            return;
-        }
-        var table = this.toTableArray();
-        var cd = this.cellData;
-        this.rowspan = 1;
-        this.colspan = 1;
-        
-        for(var r = cd.row; r < cd.row + cd.rowspan; r++) {
-            
-            
-            
-            for(var c = cd.col; c < cd.col + cd.colspan; c++) {
-                if (r == cd.row && c == cd.col) {
-                    this.node.removeAttribute('rowspan');
-                    this.node.removeAttribute('colspan');
-                    continue;
-                }
-                 
-                var ntd = this.node.cloneNode(); // which col/row should be 0..
-                ntd.removeAttribute('id'); //
-                //ntd.style.width  = '';
-                ntd.innerHTML = '';
-                table[r][c] = { cell : ntd, col : c, row: r , colspan : 1 , rowspan : 1   };
-            }
-            
-        }
-        this.redrawAllCells(table);
-        
-         
-        
-    },
-    
-    
-    
-    redrawAllCells: function(table)
-    {
-        
-         
-        var tab = this.node.closest('tr').closest('table');
-        var ctr = tab.rows[0].parentNode;
-        Array.from(tab.rows).forEach(function(r, ri){
-            
-            Array.from(r.cells).forEach(function(ce, ci){
-                ce.parentNode.removeChild(ce);
-            });
-            r.parentNode.removeChild(r);
-        });
-        for(var r = 0 ; r < table.length; r++) {
-            var re = tab.rows[r];
-            
-            var re = tab.ownerDocument.createElement('tr');
-            ctr.appendChild(re);
-            for(var c = 0 ; c < table[r].length; c++) {
-                if (table[r][c].cell === false) {
-                    continue;
-                }
-                
-                re.appendChild(table[r][c].cell);
-                 
-                table[r][c].cell = false;
-            }
-        }
-        
-    },
-    updateWidths : function(table)
-    {
-        for(var r = 0 ; r < table.length; r++) {
-           
-            for(var c = 0 ; c < table[r].length; c++) {
-                if (table[r][c].cell === false) {
-                    continue;
-                }
-                
-                if (this.colWidths[0] != false && table[r][c].colspan < 2) {
-                    var el = Roo.htmleditor.Block.factory(table[r][c].cell);
-                    el.width = Math.floor(this.colWidths[c])  +'%';
-                    el.updateElement(el.node);
-                }
-                table[r][c].cell = false; // done
-            }
-        }
-    },
-    normalizeWidths : function(table)
-    {
-    
-        if (this.colWidths[0] === false) {
-            var nw = 100.0 / this.colWidths.length;
-            this.colWidths.forEach(function(w,i) {
-                this.colWidths[i] = nw;
-            },this);
-            return;
-        }
-    
-        var t = 0, missing = [];
-        
-        this.colWidths.forEach(function(w,i) {
-            //if you mix % and
-            this.colWidths[i] = this.colWidths[i] == '' ? 0 : (this.colWidths[i]+'').replace(/[^0-9]+/g,'')*1;
-            var add =  this.colWidths[i];
-            if (add > 0) {
-                t+=add;
-                return;
-            }
-            missing.push(i);
-            
-            
-        },this);
-        var nc = this.colWidths.length;
-        if (missing.length) {
-            var mult = (nc - missing.length) / (1.0 * nc);
-            var t = mult * t;
-            var ew = (100 -t) / (1.0 * missing.length);
-            this.colWidths.forEach(function(w,i) {
-                if (w > 0) {
-                    this.colWidths[i] = w * mult;
-                    return;
-                }
-                
-                this.colWidths[i] = ew;
-            }, this);
-            // have to make up numbers..
-             
-        }
-        // now we should have all the widths..
-        
-    
-    },
-    
-    shrinkColumn : function()
-    {
-        var table = this.toTableArray();
-        this.normalizeWidths(table);
-        var col = this.cellData.col;
-        var nw = this.colWidths[col] * 0.8;
-        if (nw < 5) {
-            return;
-        }
-        var otherAdd = (this.colWidths[col]  * 0.2) / (this.colWidths.length -1);
-        this.colWidths.forEach(function(w,i) {
-            if (i == col) {
-                 this.colWidths[i] = nw;
-                return;
-            }
-            this.colWidths[i] += otherAdd
-        }, this);
-        this.updateWidths(table);
-         
-    },
-    growColumn : function()
-    {
-        var table = this.toTableArray();
-        this.normalizeWidths(table);
-        var col = this.cellData.col;
-        var nw = this.colWidths[col] * 1.2;
-        if (nw > 90) {
-            return;
-        }
-        var otherSub = (this.colWidths[col]  * 0.2) / (this.colWidths.length -1);
-        this.colWidths.forEach(function(w,i) {
-            if (i == col) {
-                this.colWidths[i] = nw;
-                return;
-            }
-            this.colWidths[i] -= otherSub
-        }, this);
-        this.updateWidths(table);
-         
-    },
-    deleteRow : function()
-    {
-        // delete this rows 'tr'
-        // if any of the cells in this row have a rowspan > 1 && row!= this row..
-        // then reduce the rowspan.
-        var table = this.toTableArray();
-        // this.cellData.row;
-        for (var i =0;i< table[this.cellData.row].length ; i++) {
-            var c = table[this.cellData.row][i];
-            if (c.row != this.cellData.row) {
-                
-                c.rowspan--;
-                c.cell.setAttribute('rowspan', c.rowspan);
-                continue;
-            }
-            if (c.rowspan > 1) {
-                c.rowspan--;
-                c.cell.setAttribute('rowspan', c.rowspan);
-            }
-        }
-        table.splice(this.cellData.row,1);
-        this.redrawAllCells(table);
-        
-    },
-    deleteColumn : function()
-    {
-        var table = this.toTableArray();
-        
-        for (var i =0;i< table.length ; i++) {
-            var c = table[i][this.cellData.col];
-            if (c.col != this.cellData.col) {
-                table[i][this.cellData.col].colspan--;
-            } else if (c.colspan > 1) {
-                c.colspan--;
-                c.cell.setAttribute('colspan', c.colspan);
-            }
-            table[i].splice(this.cellData.col,1);
-        }
-        
-        this.redrawAllCells(table);
-    }
-    
-    
-    
-    
-})
-
-//<script type="text/javascript">
-
-/*
- * Based  Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- * LGPL
- *
- */
-/**
- * @class Roo.HtmlEditorCore
- * @extends Roo.Component
- * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
- *
- * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
- */
-
-Roo.HtmlEditorCore = function(config){
-    
-    
-    Roo.HtmlEditorCore.superclass.constructor.call(this, config);
-    
-    
-    this.addEvents({
-        /**
-         * @event initialize
-         * Fires when the editor is fully initialized (including the iframe)
-         * @param {Roo.HtmlEditorCore} this
-         */
-        initialize: true,
-        /**
-         * @event activate
-         * Fires when the editor is first receives the focus. Any insertion must wait
-         * until after this event.
-         * @param {Roo.HtmlEditorCore} this
-         */
-        activate: true,
-         /**
-         * @event beforesync
-         * Fires before the textarea is updated with content from the editor iframe. Return false
-         * to cancel the sync.
-         * @param {Roo.HtmlEditorCore} this
-         * @param {String} html
-         */
-        beforesync: true,
-         /**
-         * @event beforepush
-         * Fires before the iframe editor is updated with content from the textarea. Return false
-         * to cancel the push.
-         * @param {Roo.HtmlEditorCore} this
-         * @param {String} html
-         */
-        beforepush: true,
-         /**
-         * @event sync
-         * Fires when the textarea is updated with content from the editor iframe.
-         * @param {Roo.HtmlEditorCore} this
-         * @param {String} html
-         */
-        sync: true,
-         /**
-         * @event push
-         * Fires when the iframe editor is updated with content from the textarea.
-         * @param {Roo.HtmlEditorCore} this
-         * @param {String} html
-         */
-        push: true,
-        
-        /**
-         * @event editorevent
-         * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
-         * @param {Roo.HtmlEditorCore} this
-         */
-        editorevent: true 
-         
-        
-    });
-    
-    // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
-    
-    // defaults : white / black...
-    this.applyBlacklists();
-    
-    
-    
-};
-
-
-Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
-
-
-     /**
-     * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
-     */
-    
-    owner : false,
-    
-     /**
-     * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
-     *                        Roo.resizable.
-     */
-    resizable : false,
-     /**
-     * @cfg {Number} height (in pixels)
-     */   
-    height: 300,
-   /**
-     * @cfg {Number} width (in pixels)
-     */   
-    width: 500,
-     /**
-     * @cfg {boolean} autoClean - default true - loading and saving will remove quite a bit of formating,
-     *         if you are doing an email editor, this probably needs disabling, it's designed
-     */
-    autoClean: true,
-    
-    /**
-     * @cfg {boolean} enableBlocks - default true - if the block editor (table and figure should be enabled)
-     */
-    enableBlocks : true,
-    /**
-     * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
-     * 
-     */
-    stylesheets: false,
-     /**
-     * @cfg {String} language default en - language of text (usefull for rtl languages)
-     * 
-     */
-    language: 'en',
-    
-    /**
-     * @cfg {boolean} allowComments - default false - allow comments in HTML source
-     *          - by default they are stripped - if you are editing email you may need this.
-     */
-    allowComments: false,
-    // id of frame..
-    frameId: false,
-    
-    // private properties
-    validationEvent : false,
-    deferHeight: true,
-    initialized : false,
-    activated : false,
-    sourceEditMode : false,
-    onFocus : Roo.emptyFn,
-    iframePad:3,
-    hideMode:'offsets',
-    
-    clearUp: true,
-    
-    // blacklist + whitelisted elements..
-    black: false,
-    white: false,
-     
-    bodyCls : '',
-
-    
-    undoManager : false,
-    /**
-     * Protected method that will not generally be called directly. It
-     * is called when the editor initializes the iframe with HTML contents. Override this method if you
-     * want to change the initialization markup of the iframe (e.g. to add stylesheets).
-     */
-    getDocMarkup : function(){
-        // body styles..
-        var st = '';
-        
-        // inherit styels from page...?? 
-        if (this.stylesheets === false) {
-            
-            Roo.get(document.head).select('style').each(function(node) {
-                st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
-            });
-            
-            Roo.get(document.head).select('link').each(function(node) { 
-                st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
-            });
-            
-        } else if (!this.stylesheets.length) {
-                // simple..
-                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>';
-        
-        st += '<meta name="google" content="notranslate">';
-        
-        var cls = 'notranslate roo-htmleditor-body';
-        
-        if(this.bodyCls.length){
-            cls += ' ' + this.bodyCls;
-        }
-        
-        return '<html  class="notranslate" translate="no"><head>' + st  +
-            //<style type="text/css">' +
-            //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
-            //'</style>' +
-            ' </head><body contenteditable="true" data-enable-grammerly="true" class="' +  cls + '"></body></html>';
-    },
-
-    // private
-    onRender : function(ct, position)
+
+    // private
+    onRender : function(ct, position)
     {
         var _t = this;
         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
     {
         var _t = this;
         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
@@ -31722,7 +29109,7 @@ Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
 });
 
  
 });
 
  
-Roo.bootstrap.dash = {};/*
+/*
  * - LGPL
  *
  * numberBox
  * - LGPL
  *
  * numberBox
index 15d5c60..2cef406 100644 (file)
@@ -1,5 +1,3 @@
-// Roo/bootstrap/namespace.js
-Roo.bootstrap={};
 // Roo/bootstrap/version.js
 Roo.bootstrap.version=(function(){var A=3;Roo.each(document.styleSheets,function(s){if(s.href&&s.href.match(/css-bootstrap4/)){A=4;}});if(A>3){Roo.Element.prototype.visibilityMode=Roo.Element.DISPLAY;}return A;})();
 // Roo/bootstrap/menu/namespace.js
 // Roo/bootstrap/version.js
 Roo.bootstrap.version=(function(){var A=3;Roo.each(document.styleSheets,function(s){if(s.href&&s.href.match(/css-bootstrap4/)){A=4;}});if(A>3){Roo.Element.prototype.visibilityMode=Roo.Element.DISPLAY;}return A;})();
 // Roo/bootstrap/menu/namespace.js
@@ -1108,137 +1106,6 @@ pt.innerHTML=this.meterLabel+'&nbsp;'+this.pwdStrengths[B];this.errorMsg='';retu
 }var B=new Array(new this.CharacterSetChecks(this.kCapitalLetter),new this.CharacterSetChecks(this.kSmallLetter),new this.CharacterSetChecks(this.kDigit),new this.CharacterSetChecks(this.kPunctuation));for(var C=0;C<A.length;++C){for(var D=0;D<B.length;++D){if(!B[D].fResult&&this.isctype(A.charAt(C),B[D].type)){B[D].fResult=true;
 break;}}}var E=0;for(var D=0;D<B.length;++D){if(B[D].fResult){++E;}}if(E<nb){return false;}return true;},ClientSideStrongPassword:function(A){return this.IsLongEnough(A,8)&&this.SpansEnoughCharacterSets(A,3);},ClientSideMediumPassword:function(A){return this.IsLongEnough(A,7)&&this.SpansEnoughCharacterSets(A,2);
 },ClientSideWeakPassword:function(A){return this.IsLongEnough(A,6)||!this.IsLongEnough(A,0);}});
 }var B=new Array(new this.CharacterSetChecks(this.kCapitalLetter),new this.CharacterSetChecks(this.kSmallLetter),new this.CharacterSetChecks(this.kDigit),new this.CharacterSetChecks(this.kPunctuation));for(var C=0;C<A.length;++C){for(var D=0;D<B.length;++D){if(!B[D].fResult&&this.isctype(A.charAt(C),B[D].type)){B[D].fResult=true;
 break;}}}var E=0;for(var D=0;D<B.length;++D){if(B[D].fResult){++E;}}if(E<nb){return false;}return true;},ClientSideStrongPassword:function(A){return this.IsLongEnough(A,8)&&this.SpansEnoughCharacterSets(A,3);},ClientSideMediumPassword:function(A){return this.IsLongEnough(A,7)&&this.SpansEnoughCharacterSets(A,2);
 },ClientSideWeakPassword:function(A){return this.IsLongEnough(A,6)||!this.IsLongEnough(A,0);}});
-// Roo/htmleditor/namespace.js
-Roo.htmleditor={};
-// Roo/htmleditor/Filter.js
-Roo.htmleditor.Filter=function(A){Roo.apply(this.cfg);};Roo.htmleditor.Filter.prototype={node:false,tag:false,replaceComment:false,replaceTag:false,walk:function(A){Roo.each(Array.from(A.childNodes),function(e){switch(true){case e.nodeType==8&&this.replaceComment!==false:this.replaceComment(e);
-return;case e.nodeType!=1:return;case this.tag===true:case typeof(this.tag)=='object'&&this.tag.indexOf(e.tagName)>-1:case typeof(this.tag)=='string'&&this.tag==e.tagName:if(this.replaceTag&&false===this.replaceTag(e)){return;}if(e.hasChildNodes()){this.walk(e);
-}return;default:if(e.hasChildNodes()){this.walk(e);}}},this);}};
-// Roo/htmleditor/FilterAttributes.js
-Roo.htmleditor.FilterAttributes=function(A){Roo.apply(this,A);this.attrib_black=this.attrib_black||[];this.attrib_white=this.attrib_white||[];this.attrib_clean=this.attrib_clean||[];this.style_white=this.style_white||[];this.style_black=this.style_black||[];
-this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterAttributes,Roo.htmleditor.Filter,{tag:true,attrib_black:false,attrib_clean:false,attrib_white:false,style_white:false,style_black:false,replaceTag:function(A){if(!A.attributes||!A.attributes.length){return true;
-}for(var i=A.attributes.length-1;i>-1;i--){var a=A.attributes[i];if(this.attrib_white.length&&this.attrib_white.indexOf(a.name.toLowerCase())<0){A.removeAttribute(a.name);continue;}if(a.name.toLowerCase().substr(0,2)=='on'){A.removeAttribute(a.name);continue;
-}if(this.attrib_black.indexOf(a.name.toLowerCase())>-1){A.removeAttribute(a.name);continue;}if(this.attrib_clean.indexOf(a.name.toLowerCase())>-1){this.cleanAttr(A,a.name,a.value);continue;}if(a.name=='style'){this.cleanStyle(A,a.name,a.value);continue;}if(a.name=='class'){if(a.value.match(/^Mso/)){A.removeAttribute('class');
-}if(a.value.match(/^body$/)){A.removeAttribute('class');}continue;}}return true;},cleanAttr:function(A,n,v){if(v.match(/^\./)||v.match(/^\//)){return;}if(v.match(/^(http|https):\/\//)||v.match(/^mailto:/)||v.match(/^ftp:/)||v.match(/^data:/)){return;}if(v.match(/^#/)){return;
-}if(v.match(/^\{/)){return;}A.removeAttribute(n);},cleanStyle:function(A,n,v){if(v.match(/expression/)){A.removeAttribute(n);return;}var B=v.split(/;/);var C=[];Roo.each(B,function(p){p=p.replace(/^\s+/g,'').replace(/\s+$/g,'');if(!p.length){return true;}
-var l=p.split(':').shift().replace(/\s+/g,'');l=l.replace(/^\s+/g,'').replace(/\s+$/g,'');if(this.style_black.length&&(this.style_black.indexOf(l)>-1||this.style_black.indexOf(l.toLowerCase())>-1)){return true;}if(this.style_white.length&&style_white.indexOf(l)<0&&style_white.indexOf(l.toLowerCase())<0){return true;
-}C.push(p);return true;},this);if(C.length){A.setAttribute(n,C.join(';'));}else{A.removeAttribute(n);}}});
-// Roo/htmleditor/FilterBlack.js
-Roo.htmleditor.FilterBlack=function(A){Roo.apply(this,A);this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterBlack,Roo.htmleditor.Filter,{tag:true,replaceTag:function(n){n.parentNode.removeChild(n);}});
-// Roo/htmleditor/FilterComment.js
-Roo.htmleditor.FilterComment=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterComment,Roo.htmleditor.Filter,{replaceComment:function(n){n.parentNode.removeChild(n);}});
-// Roo/htmleditor/FilterKeepChildren.js
-Roo.htmleditor.FilterKeepChildren=function(A){Roo.apply(this,A);if(this.tag===false){return;}this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterKeepChildren,Roo.htmleditor.FilterBlack,{replaceTag:function(A){var ar=Array.from(A.childNodes);for(var i=0;i<ar.length;
-i++){if(ar[i].nodeType==1){if((typeof(this.tag)=='object'&&this.tag.indexOf(ar[i].tagName)>-1)||(typeof(this.tag)=='string'&&this.tag==ar[i].tagName)){this.replaceTag(ar[i]);continue;}}}ar=Array.from(A.childNodes);for(var i=0;i<ar.length;i++){A.removeChild(ar[i]);
-A.parentNode.insertBefore(ar[i],A);if(this.tag!==false){this.walk(ar[i]);}}A.parentNode.removeChild(A);return false;}});
-// Roo/htmleditor/FilterParagraph.js
-Roo.htmleditor.FilterParagraph=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterParagraph,Roo.htmleditor.Filter,{tag:'P',replaceTag:function(A){if(A.childNodes.length==1&&A.childNodes[0].nodeType==3&&A.childNodes[0].textContent.trim().length<1){A.parentNode.replaceChild(A.ownerDocument.createElement('BR'),A);
-return false;}var ar=Array.from(A.childNodes);for(var i=0;i<ar.length;i++){A.removeChild(ar[i]);A.parentNode.insertBefore(ar[i],A);}A.parentNode.insertBefore(A.ownerDocument.createElement('BR'),A);A.parentNode.insertBefore(A.ownerDocument.createElement('BR'),A);
-A.parentNode.removeChild(A);return false;}});
-// Roo/htmleditor/FilterSpan.js
-Roo.htmleditor.FilterSpan=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterSpan,Roo.htmleditor.FilterKeepChildren,{tag:'SPAN',replaceTag:function(A){if(A.attributes&&A.attributes.length>0){return true;}Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this,A);
-return false;}});
-// Roo/htmleditor/FilterTableWidth.js
-Roo.htmleditor.FilterTableWidth=function(A){this.tag=['TABLE','TD','TR','TH','THEAD','TBODY'];this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterTableWidth,Roo.htmleditor.Filter,{replaceTag:function(A){if(A.hasAttribute('width')){A.removeAttribute('width');
-}if(A.hasAttribute("style")){var B=A.getAttribute("style").split(";");var C=[];Roo.each(B,function(s){if(!s.match(/:/)){return;}var kv=s.split(":");if(kv[0].match(/^\s*(width|min-width)\s*$/)){return;}C.push(s);});A.setAttribute("style",C.length?C.join(';'):'');
-if(!C.length){A.removeAttribute('style');}}return true;}});
-// Roo/htmleditor/FilterWord.js
-Roo.htmleditor.FilterWord=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterWord,Roo.htmleditor.Filter,{tag:true,replaceTag:function(A){if(A.nodeName=='SPAN'&&!A.hasAttributes()&&A.childNodes.length==1&&A.firstChild.nodeName=="#text"){var B=A.firstChild;
-A.removeChild(B);if(A.getAttribute('lang')!='zh-CN'){A.parentNode.insertBefore(A.ownerDocument.createTextNode(" "),A);}A.parentNode.insertBefore(B,A);if(A.getAttribute('lang')!='zh-CN'){A.parentNode.insertBefore(A.ownerDocument.createTextNode(" "),A);}A.parentNode.removeChild(A);
-return false;}if(A.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)){A.parentNode.removeChild(A);return false;}if(A.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)){while(A.childNodes.length){var cn=A.childNodes[0];
-A.removeChild(cn);A.parentNode.insertBefore(cn,A);this.replaceTag(cn);}A.parentNode.removeChild(A);return false;}if(A.className.length){var cn=A.className.split(/\W+/);var C=[];Roo.each(cn,function(F){if(F.match(/Mso[a-zA-Z]+/)){return;}C.push(F);});A.className=C.length?C.join(' '):'';
-if(!C.length){A.removeAttribute("class");}}if(A.hasAttribute("lang")){A.removeAttribute("lang");}if(A.hasAttribute("style")){var D=A.getAttribute("style").split(";");var E=[];Roo.each(D,function(s){if(!s.match(/:/)){return;}var kv=s.split(":");if(kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)){return;
-}E.push(s);});A.setAttribute("style",E.length?E.join(';'):'');if(!E.length){A.removeAttribute('style');}}return true;}});
-// Roo/htmleditor/FilterStyleToTag.js
-Roo.htmleditor.FilterStyleToTag=function(A){this.tags={B:['fontWeight','bold'],I:['fontStyle','italic'],SUP:['verticalAlign','super'],SUB:['verticalAlign','sub']};Roo.apply(this,A);this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterStyleToTag,Roo.htmleditor.Filter,{tag:true,tags:false,replaceTag:function(A){if(A.getAttribute("style")===null){return true;
-}var B=[];for(var k in this.tags){if(A.style[this.tags[k][0]]==this.tags[k][1]){B.push(k);A.style.removeProperty(this.tags[k][0]);}}if(!B.length){return true;}var cn=Array.from(A.childNodes);var nn=A;Roo.each(B,function(t){var nc=A.ownerDocument.createElement(t);
-nn.appendChild(nc);nn=nc;});for(var i=0;i<cn.length;cn++){A.removeChild(cn[i]);nn.appendChild(cn[i]);}return true}})
-// Roo/htmleditor/FilterLongBr.js
-Roo.htmleditor.FilterLongBr=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterLongBr,Roo.htmleditor.Filter,{tag:'BR',replaceTag:function(A){var ps=A.nextSibling;while(ps&&ps.nodeType==3&&ps.nodeValue.trim().length<1){ps=ps.nextSibling;}if(!ps&&['TD','TH','LI','H1','H2','H3','H4','H5','H6'].indexOf(A.parentNode.tagName)>-1){A.parentNode.removeChild(A);
-return false;}if(!ps||ps.nodeType!=1){return false;}if(!ps||ps.tagName!='BR'){return false;}if(!A.previousSibling){return false;}var ps=A.previousSibling;while(ps&&ps.nodeType==3&&ps.nodeValue.trim().length<1){ps=ps.previousSibling;}if(!ps||ps.nodeType!=1){return false;
-}if(!ps||['BR','H1','H2','H3','H4','H5','H6'].indexOf(ps.tagName)<0){return false;}A.parentNode.removeChild(A);return false;}});
-// 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/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();
-this.core.fireEditorEvent(e);return false;}if(D.innerText.trim()==''&&D.previousSibling&&D.previousSibling.nodeName=='LI'&&D.previousSibling.innerText.trim()==''){D.parentNode.removeChild(D.previousSibling);B.cursorAfter(pc);this.core.undoManager.addEvent();
-this.core.fireEditorEvent(e);return false;}var li=A.createElement('LI');li.innerHTML='&nbsp;';if(!D||!D.firstSibling){pc.appendChild(li);}else{D.parentNode.insertBefore(li,D.firstSibling);}B.cursorText(li.firstChild);this.core.undoManager.addEvent();this.core.fireEditorEvent(e);
-return false;}};
-// Roo/htmleditor/Block.js
-Roo.htmleditor.Block=function(A){};Roo.htmleditor.Block.factory=function(A){var cc=Roo.htmleditor.Block.cache;var id=Roo.get(A).id;if(typeof(cc[id])!='undefined'&&(!cc[id].node||cc[id].node.closest('body'))){Roo.htmleditor.Block.cache[id].readElement(A);return Roo.htmleditor.Block.cache[id];
-}var db=A.getAttribute('data-block');if(!db){db=A.nodeName.toLowerCase().toUpperCaseFirst();}var B=Roo.htmleditor['Block'+db];if(typeof(B)=='undefined'){Roo.log("OOps missing block : "+'Block'+db);return false;}Roo.htmleditor.Block.cache[id]=new B({node:A}
-);return Roo.htmleditor.Block.cache[id];};Roo.htmleditor.Block.initAll=function(A,B){if(typeof(B)=='undefined'){var ia=Roo.htmleditor.Block.initAll;ia(A,'table');ia(A,'td');ia(A,'figure');return;}Roo.each(Roo.get(A).query(B),function(e){Roo.htmleditor.Block.factory(e);
-},this);};Roo.htmleditor.Block.cache={};Roo.htmleditor.Block.prototype={node:false,friendly_name:'Based Block',deleteTitle:false,context:false,updateElement:function(A){Roo.DomHelper.update(A===undefined?this.node:A,this.toObject());},toHTML:function(){return Roo.DomHelper.markup(this.toObject());
-},getVal:function(A,B,C,D){var n=A;if(B!==true&&n.tagName!=B.toUpperCase()){n=A.getElementsByTagName(B).item(0);}if(!n){return '';}if(C=='html'){return n.innerHTML;}if(C=='style'){return n.style[D];}return n.hasAttribute(C)?n.getAttribute(C):'';},toObject:function(){return {}
-;},readElement:function(A){}};
-// Roo/htmleditor/BlockFigure.js
-Roo.htmleditor.BlockFigure=function(A){if(A.node){this.readElement(A.node);this.updateElement(A.node);}Roo.apply(this,A);};Roo.extend(Roo.htmleditor.BlockFigure,Roo.htmleditor.Block,{image_src:'',align:'center',caption:'',caption_display:'block',width:'100%',cls:'',href:'',video_url:'',text_align:'left',friendly_name:'Image with caption',deleteTitle:"Delete Image and Caption",contextMenu:function(A){var B=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode);
-};var C=typeof(Roo.bootstrap)=='undefined'?Roo:Roo.bootstrap;var D=A.editorcore.syncValue;var E={};return [{xtype:'TextItem',text:"Source: ",xns:C.Toolbar},{xtype:'Button',text:'Change Image URL',listeners:{click:function(F,G){var b=B();Roo.MessageBox.show({title:"Image Source URL",msg:"Enter the url for the image",buttons:Roo.MessageBox.OKCANCEL,fn:function(H,I){if(H!='ok'){return;
-}b.image_src=I;b.updateElement();D();A.editorcore.onEditorEvent();},minWidth:250,prompt:true,modal:true,value:b.image_src});}},xns:C.Toolbar},{xtype:'Button',text:'Change Link URL',listeners:{click:function(F,G){var b=B();Roo.MessageBox.show({title:"Link URL",msg:"Enter the url for the link - leave blank to have no link",buttons:Roo.MessageBox.OKCANCEL,fn:function(H,I){if(H!='ok'){return;
-}b.href=I;b.updateElement();D();A.editorcore.onEditorEvent();},minWidth:250,prompt:true,modal:true,value:b.href});}},xns:C.Toolbar},{xtype:'Button',text:'Show Video URL',listeners:{click:function(F,G){Roo.MessageBox.alert("Video URL",B().video_url==''?'This image is not linked ot a video':'The image is linked to: <a target="_new" href="'+B().video_url+'">'+B().video_url+'</a>');
-}},xns:C.Toolbar},{xtype:'TextItem',text:"Width: ",xns:C.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:70,name:'width',listeners:{select:function(F,r,G){A.editorcore.selectNode(A.tb.selectedNode);
-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," ").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]};}var B=this.caption_display=='hidden'?this.caption:(this.caption.length?this.caption:"Caption");
-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',style:{'text-align':'left','margin-top':'16px','font-size':'16px','line-height':'24px',display:this.caption_display}
-,cls:this.cls.length>0?(this.cls+'-thumbnail'):'',cn:[{tag:'i',contenteditable:true,html:B}]}]};},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.caption.trim().match(/^<i[^>]*>/i)){this.caption=this.caption.trim().replace(/^<i[^>]*>/i,'').replace(/^<\/i>$/i,'');}this.width=this.getVal(A,'figure','style','max-width');
-},removeNode:function(){return this.node;}})
-// Roo/htmleditor/BlockTable.js
-Roo.htmleditor.BlockTable=function(A){if(A.node){this.readElement(A.node);this.updateElement(A.node);}Roo.apply(this,A);if(!A.node){this.rows=[];for(var r=0;r<this.no_row;r++){this.rows[r]=[];for(var c=0;c<this.no_col;c++){this.rows[r][c]=this.emptyCell();
-}}}};Roo.extend(Roo.htmleditor.BlockTable,Roo.htmleditor.Block,{rows:false,no_col:1,no_row:1,width:'100%',friendly_name:'Table',deleteTitle:'Delete Table',contextMenu:function(A){var B=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode);};var C=typeof(Roo.bootstrap)=='undefined'?Roo:Roo.bootstrap;
-var D=A.editorcore.syncValue;var E={};return [{xtype:'TextItem',text:"Width: ",xns:C.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:100,name:'width',listeners:{select:function(F,r,G){A.editorcore.selectNode(A.tb.selectedNode);
-var b=B();b.width=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['100%'],['auto']],fields:['val'],xns:Roo.data}},{xtype:'TextItem',text:"Columns: ",xns:C.Toolbar},{xtype:'Button',text:'-',listeners:{click:function(F,e){A.editorcore.selectNode(A.tb.selectedNode);
-B().removeColumn();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar},{xtype:'Button',text:'+',listeners:{click:function(F,e){A.editorcore.selectNode(A.tb.selectedNode);B().addColumn();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar},{xtype:'TextItem',text:"Rows: ",xns:C.Toolbar}
-,{xtype:'Button',text:'-',listeners:{click:function(F,e){A.editorcore.selectNode(A.tb.selectedNode);B().removeRow();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar},{xtype:'Button',text:'+',listeners:{click:function(F,e){B().addRow();D();A.editorcore.onEditorEvent();
-}},xns:C.Toolbar},{xtype:'Button',text:'Reset Column Widths',listeners:{click:function(F,e){B().resetWidths();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar}];},toObject:function(){var A={tag:'table',contenteditable:'false','data-block':'Table',style:{width:this.width,border:'solid 1px #000','border-collapse':'collapse'}
-,cn:[{tag:'tbody',cn:[]}]};var B=0;Roo.each(this.rows,function(C){var tr={tag:'tr',style:{margin:'6px',border:'solid 1px #000',textAlign:'left'},cn:[]};A.cn[0].cn.push(tr);var nc=0;Roo.each(C,function(D){var td={tag:'td',contenteditable:'true','data-block':'Td',html:D.html,style:D.style}
-;if(D.colspan>1){td.colspan=D.colspan;nc+=D.colspan;}else{nc++;}if(D.rowspan>1){td.rowspan=D.rowspan;}tr.cn.push(td);},this);B=Math.max(nc,B);},this);B++;return A;},readElement:function(A){A=A?A:this.node;this.width=this.getVal(A,true,'style','width')||'100%';
-this.rows=[];this.no_row=0;var B=Array.from(A.rows);B.forEach(function(tr){var C=[];this.rows.push(C);this.no_row++;var D=0;Array.from(tr.cells).forEach(function(td){var E={colspan:td.hasAttribute('colspan')?td.getAttribute('colspan')*1:1,rowspan:td.hasAttribute('rowspan')?td.getAttribute('rowspan')*1:1,style:td.hasAttribute('style')?td.getAttribute('style'):'',html:td.innerHTML}
-;D+=E.colspan;C.push(E);},this);this.no_col=Math.max(this.no_col,D);},this);},normalizeRows:function(){var A=[];var B=-1;this.rows.forEach(function(C){B++;A[B]=[];C=this.normalizeRow(C);var D=0;C.forEach(function(c){while(typeof(A[B][D])!='undefined'){D++;
-}if(typeof(A[B])=='undefined'){A[B]=[];}A[B][D]=c;c.row=B;c.col=D;if(c.rowspan<2){return;}for(var i=1;i<c.rowspan;i++){if(typeof(A[B+i])=='undefined'){A[B+i]=[];}A[B+i][D]=c;}});},this);return A;},normalizeRow:function(A){var B=[];A.forEach(function(c){if(c.colspan<2){B.push(c);
-return;}for(var i=0;i<c.colspan;i++){B.push(c);}});return B;},deleteColumn:function(A){if(!A||A.type!='col'){return;}if(this.no_col<2){return;}this.rows.forEach(function(B){var C=this.normalizeRow(B);var D=C[A.col];if(D.colspan>1){D.colspan--;}else{B.remove(D);
-}},this);this.no_col--;},removeColumn:function(){this.deleteColumn({type:'col',col:this.no_col-1});this.updateElement();},addColumn:function(){this.rows.forEach(function(A){A.push(this.emptyCell());},this);this.updateElement();},deleteRow:function(A){if(!A||A.type!='row'){return;
-}if(this.no_row<2){return;}var B=this.normalizeRows();B[A.row].forEach(function(D){if(D.rowspan>1){D.rowspan--;}else{D.remove=1;}},this);var C=[];this.rows.forEach(function(D){newrow=[];D.forEach(function(c){if(typeof(c.remove)=='undefined'){newrow.push(c);
-}});if(newrow.length>0){C.push(D);}});this.rows=C;this.no_row--;this.updateElement();},removeRow:function(){this.deleteRow({type:'row',row:this.no_row-1});},addRow:function(){var A=[];for(var i=0;i<this.no_col;i++){A.push(this.emptyCell());}this.rows.push(A);
-this.updateElement();},emptyCell:function(){return (new Roo.htmleditor.BlockTd({})).toObject();},removeNode:function(){return this.node;},resetWidths:function(){Array.from(this.node.getElementsByTagName('td')).forEach(function(n){var nn=Roo.htmleditor.Block.factory(n);
-nn.width='';nn.updateElement(n);});}})
-// Roo/htmleditor/BlockTd.js
-Roo.htmleditor.BlockTd=function(A){if(A.node){this.readElement(A.node);this.updateElement(A.node);}Roo.apply(this,A);};Roo.extend(Roo.htmleditor.BlockTd,Roo.htmleditor.Block,{node:false,width:'',textAlign:'left',valign:'top',colspan:1,rowspan:1,friendly_name:'Table Cell',deleteTitle:false,contextMenu:function(A){var B=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode);
-};var C=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode.closest('table'));};var lr=false;var D=function(){lr=A.editorcore.getSelection().getRangeAt(0);};var restoreSel=function(){if(lr){(function(){A.editorcore.focus();var cr=A.editorcore.getSelection();
-cr.removeAllRanges();cr.addRange(lr);A.editorcore.onEditorEvent();}).defer(10,this);}};var rooui=typeof(Roo.bootstrap)=='undefined'?Roo:Roo.bootstrap;var E=A.editorcore.syncValue;var F={};return [{xtype:'Button',text:'Edit Table',listeners:{click:function(){var t=A.tb.selectedNode.closest('table');
-A.editorcore.selectNode(t);A.editorcore.onEditorEvent();}}},{xtype:'TextItem',text:"Column Width: ",xns:rooui.Toolbar},{xtype:'Button',text:'-',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);B().shrinkColumn();E();A.editorcore.onEditorEvent();
-}},xns:rooui.Toolbar},{xtype:'Button',text:'+',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);B().growColumn();E();A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'TextItem',text:"Vertical Align: ",xns:rooui.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:100,name:'valign',listeners:{select:function(G,r,H){A.editorcore.selectNode(A.tb.selectedNode);
-var b=B();b.valign=r.get('val');b.updateElement();E();A.editorcore.onEditorEvent();}},xns:rooui.form,store:{xtype:'SimpleStore',data:[['top'],['middle'],['bottom']],fields:['val'],xns:Roo.data}},{xtype:'TextItem',text:"Merge Cells: ",xns:rooui.Toolbar},{xtype:'Button',text:'Right',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);
-B().mergeRight();E();A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'Button',text:'Below',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);B().mergeBelow();E();A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'TextItem',text:"| ",xns:rooui.Toolbar}
-,{xtype:'Button',text:'Split',listeners:{click:function(G,e){B().split();E();A.editorcore.selectNode(A.tb.selectedNode);A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'Fill',xns:rooui.Toolbar},{xtype:'Button',text:'Delete',xns:rooui.Toolbar,menu:{xtype:'Menu',xns:rooui.menu,items:[{xtype:'Item',html:'Column',listeners:{click:function(G,e){var t=C();
-B().deleteColumn();E();A.editorcore.selectNode(t.node);A.editorcore.onEditorEvent();}},xns:rooui.menu},{xtype:'Item',html:'Row',listeners:{click:function(G,e){var t=C();B().deleteRow();E();A.editorcore.selectNode(t.node);A.editorcore.onEditorEvent();}},xns:rooui.menu}
-,{xtype:'Separator',xns:rooui.menu},{xtype:'Item',html:'Table',listeners:{click:function(G,e){var t=C();var nn=t.node.nextSibling||t.node.previousSibling;t.node.parentNode.removeChild(t.node);if(nn){A.editorcore.selectNode(nn,true);}A.editorcore.onEditorEvent();
-}},xns:rooui.menu}]}}];},toObject:function(){var A={tag:'td',contenteditable:'true','data-block':'Td',valign:this.valign,style:{'text-align':this.textAlign,border:'solid 1px rgb(0, 0, 0)','border-collapse':'collapse',padding:'6px','vertical-align':this.valign}
-,html:this.html};if(this.width!=''){A.width=this.width;A.style.width=this.width;}if(this.colspan>1){A.colspan=this.colspan;}if(this.rowspan>1){A.rowspan=this.rowspan;}return A;},readElement:function(A){A=A?A:this.node;this.width=A.style.width;this.colspan=Math.max(1,1*A.getAttribute('colspan'));
-this.rowspan=Math.max(1,1*A.getAttribute('rowspan'));this.html=A.innerHTML;},emptyCell:function(){return {colspan:1,rowspan:1,textAlign:'left',html:"&nbsp;"};},removeNode:function(){return this.node.closest('table');},cellData:false,colWidths:false,toTableArray:function(){var A=[];
-var B=this.node.closest('tr').closest('table');Array.from(B.rows).forEach(function(r,ri){A[ri]=[];});var rn=0;this.colWidths=[];var C=true;Array.from(B.rows).forEach(function(r,ri){var cn=0;Array.from(r.cells).forEach(function(ce,ci){var c={cell:ce,row:rn,col:cn,colspan:ce.colSpan,rowspan:ce.rowSpan}
-;if(ce.isEqualNode(this.node)){this.cellData=c;}if(typeof(A[rn][cn])!='undefined'){while(typeof(A[rn][cn])!='undefined'){cn++;}c.col=cn;}if(typeof(this.colWidths[cn])=='undefined'){this.colWidths[cn]=ce.style.width;if(this.colWidths[cn]!=''){C=false;}}if(c.colspan<2&&c.rowspan<2){A[rn][cn]=c;
-cn++;return;}for(var j=0;j<c.rowspan;j++){if(typeof(A[rn+j])=='undefined'){continue;}A[rn+j][cn]=c;for(var i=0;i<c.colspan;i++){A[rn+j][cn+i]=c;}}cn+=c.colspan;},this);rn++;},this);if(C){this.colWidths[0]=false;}return A;},mergeRight:function(){var tr=this.node.closest('tr');
-var i=Array.prototype.indexOf.call(tr.childNodes,this.node);if(i>=tr.childNodes.length-1){return;}var A=this.toTableArray();if(typeof(A[this.cellData.row][this.cellData.col+this.cellData.colspan])=='undefined'){return;}var rc=A[this.cellData.row][this.cellData.col+this.cellData.colspan];
-if(rc.rowspan!=this.cellData.rowspan||rc.row!=this.cellData.row){return;}this.node.innerHTML+=' '+rc.cell.innerHTML;tr.removeChild(rc.cell);this.colspan+=rc.colspan;this.node.setAttribute('colspan',this.colspan);},mergeBelow:function(){var A=this.toTableArray();
-if(typeof(A[this.cellData.row+this.cellData.rowspan])=='undefined'){return;}if(typeof(A[this.cellData.row+this.cellData.rowspan][this.cellData.col])=='undefined'){return;}var rc=A[this.cellData.row+this.cellData.rowspan][this.cellData.col];if(rc.colspan!=this.cellData.colspan||rc.col!=this.cellData.col){return;
-}this.node.innerHTML=this.node.innerHTML+rc.cell.innerHTML;rc.cell.parentNode.removeChild(rc.cell);this.rowspan+=rc.rowspan;this.node.setAttribute('rowspan',this.rowspan);},split:function(){if(this.node.rowSpan<2&&this.node.colSpan<2){return;}var A=this.toTableArray();
-var cd=this.cellData;this.rowspan=1;this.colspan=1;for(var r=cd.row;r<cd.row+cd.rowspan;r++){for(var c=cd.col;c<cd.col+cd.colspan;c++){if(r==cd.row&&c==cd.col){this.node.removeAttribute('rowspan');this.node.removeAttribute('colspan');continue;}var B=this.node.cloneNode();
-B.removeAttribute('id');B.innerHTML='';A[r][c]={cell:B,col:c,row:r,colspan:1,rowspan:1};}}this.redrawAllCells(A);},redrawAllCells:function(A){var B=this.node.closest('tr').closest('table');var C=B.rows[0].parentNode;Array.from(B.rows).forEach(function(r,ri){Array.from(r.cells).forEach(function(ce,ci){ce.parentNode.removeChild(ce);
-});r.parentNode.removeChild(r);});for(var r=0;r<A.length;r++){var re=B.rows[r];var re=B.ownerDocument.createElement('tr');C.appendChild(re);for(var c=0;c<A[r].length;c++){if(A[r][c].cell===false){continue;}re.appendChild(A[r][c].cell);A[r][c].cell=false;}
-}},updateWidths:function(A){for(var r=0;r<A.length;r++){for(var c=0;c<A[r].length;c++){if(A[r][c].cell===false){continue;}if(this.colWidths[0]!=false&&A[r][c].colspan<2){var el=Roo.htmleditor.Block.factory(A[r][c].cell);el.width=Math.floor(this.colWidths[c])+'%';
-el.updateElement(el.node);}A[r][c].cell=false;}}},normalizeWidths:function(A){if(this.colWidths[0]===false){var nw=100.0/this.colWidths.length;this.colWidths.forEach(function(w,i){this.colWidths[i]=nw;},this);return;}var t=0,B=[];this.colWidths.forEach(function(w,i){this.colWidths[i]=this.colWidths[i]==''?0:(this.colWidths[i]+'').replace(/[^0-9]+/g,'')*1;
-var D=this.colWidths[i];if(D>0){t+=D;return;}B.push(i);},this);var nc=this.colWidths.length;if(B.length){var C=(nc-B.length)/(1.0*nc);var t=C*t;var ew=(100-t)/(1.0*B.length);this.colWidths.forEach(function(w,i){if(w>0){this.colWidths[i]=w*C;return;}this.colWidths[i]=ew;
-},this);}},shrinkColumn:function(){var A=this.toTableArray();this.normalizeWidths(A);var B=this.cellData.col;var nw=this.colWidths[B]*0.8;if(nw<5){return;}var C=(this.colWidths[B]*0.2)/(this.colWidths.length-1);this.colWidths.forEach(function(w,i){if(i==B){this.colWidths[i]=nw;
-return;}this.colWidths[i]+=C},this);this.updateWidths(A);},growColumn:function(){var A=this.toTableArray();this.normalizeWidths(A);var B=this.cellData.col;var nw=this.colWidths[B]*1.2;if(nw>90){return;}var C=(this.colWidths[B]*0.2)/(this.colWidths.length-1);
-this.colWidths.forEach(function(w,i){if(i==B){this.colWidths[i]=nw;return;}this.colWidths[i]-=C},this);this.updateWidths(A);},deleteRow:function(){var A=this.toTableArray();for(var i=0;i<A[this.cellData.row].length;i++){var c=A[this.cellData.row][i];if(c.row!=this.cellData.row){c.rowspan--;
-c.cell.setAttribute('rowspan',c.rowspan);continue;}if(c.rowspan>1){c.rowspan--;c.cell.setAttribute('rowspan',c.rowspan);}}A.splice(this.cellData.row,1);this.redrawAllCells(A);},deleteColumn:function(){var A=this.toTableArray();for(var i=0;i<A.length;i++){var c=A[i][this.cellData.col];
-if(c.col!=this.cellData.col){A[i][this.cellData.col].colspan--;}else if(c.colspan>1){c.colspan--;c.cell.setAttribute('colspan',c.colspan);}A[i].splice(this.cellData.col,1);}this.redrawAllCells(A);}})
 // Roo/HtmlEditorCore.js
 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);
 // Roo/HtmlEditorCore.js
 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);
@@ -1371,8 +1238,6 @@ return;}this.raphael=Raphael(this.el.dom);},load:function(A,B,C){this.raphael.cl
 ,500,"bounce");if(this.label){this.label[0].animate({r:5},500,"bounce");this.label[1].attr({"font-weight":400});}};switch(A){case 'bar':this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,B,C).hover(D,E);break;case 'hbar':this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,B,C).hover(D,E);
 break;case 'pie':this.raphael.piechart(this.g_x,this.g_y,this.g_r,B,C).hover(F,G);break;}if(this.title){this.raphael.text(this.title.x,this.title.y,this.title.text).attr(this.title.attr);}},setTitle:function(o){this.title=o;},initEvents:function(){if(!this.href){this.el.on('click',this.onClick,this);
 }},onClick:function(e){Roo.log('img onclick');this.fireEvent('click',this,e);}});
 ,500,"bounce");if(this.label){this.label[0].animate({r:5},500,"bounce");this.label[1].attr({"font-weight":400});}};switch(A){case 'bar':this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,B,C).hover(D,E);break;case 'hbar':this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,B,C).hover(D,E);
 break;case 'pie':this.raphael.piechart(this.g_x,this.g_y,this.g_r,B,C).hover(F,G);break;}if(this.title){this.raphael.text(this.title.x,this.title.y,this.title.text).attr(this.title.attr);}},setTitle:function(o){this.title=o;},initEvents:function(){if(!this.href){this.el.on('click',this.onClick,this);
 }},onClick:function(e){Roo.log('img onclick');this.fireEvent('click',this,e);}});
-// Roo/bootstrap/dash/namespace.js
-Roo.bootstrap.dash={};
 // Roo/bootstrap/dash/NumberBox.js
 Roo.bootstrap.dash=Roo.bootstrap.dash||{};Roo.bootstrap.dash.NumberBox=function(A){Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this,A);};Roo.extend(Roo.bootstrap.dash.NumberBox,Roo.bootstrap.Component,{headline:'',content:'',icon:'',footer:'',fhref:'',ficon:'',getAutoCreate:function(){var A={tag:'div',cls:'small-box ',cn:[{tag:'div',cls:'inner',cn:[{tag:'h3',cls:'roo-headline',html:this.headline}
 ,{tag:'p',cls:'roo-content',html:this.content}]}]};if(this.icon){A.cn.push({tag:'div',cls:'icon',cn:[{tag:'i',cls:'ion '+this.icon}]});}if(this.footer){var B={tag:'a',cls:'small-box-footer',href:this.fhref||'#',html:this.footer};A.cn.push(B);}return A;},onRender:function(ct,A){Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,A);
 // Roo/bootstrap/dash/NumberBox.js
 Roo.bootstrap.dash=Roo.bootstrap.dash||{};Roo.bootstrap.dash.NumberBox=function(A){Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this,A);};Roo.extend(Roo.bootstrap.dash.NumberBox,Roo.bootstrap.Component,{headline:'',content:'',icon:'',footer:'',fhref:'',ficon:'',getAutoCreate:function(){var A={tag:'div',cls:'small-box ',cn:[{tag:'div',cls:'inner',cn:[{tag:'h3',cls:'roo-headline',html:this.headline}
 ,{tag:'p',cls:'roo-content',html:this.content}]}]};if(this.icon){A.cn.push({tag:'div',cls:'icon',cn:[{tag:'i',cls:'ion '+this.icon}]});}if(this.footer){var B={tag:'a',cls:'small-box-footer',href:this.fhref||'#',html:this.footer};A.cn.push(B);}return A;},onRender:function(ct,A){Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,A);
index e655f12..fd3afc4 100644 (file)
@@ -4907,468 +4907,7 @@ Roo.lib.Easing = {
             }
         };
     })();
             }
         };
     })();
-/**
- * Originally based of this code... - refactored for Roo...
- * https://github.com/aaalsaleh/undo-manager
- * undo-manager.js
- * @author  Abdulrahman Alsaleh 
- * @copyright 2015 Abdulrahman Alsaleh 
- * @license  MIT License (c) 
- *
- * Hackily modifyed by alan@roojs.com
- *
- *
- *  
- *
- *  TOTALLY UNTESTED...
- *
- *  Documentation to be done....
- */
-
-/**
-* @class Roo.lib.UndoManager
-* An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
-* Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
-
- * Usage:
- * <pre><code>
-
-
-editor.undoManager = new Roo.lib.UndoManager(1000, editor);
-</code></pre>
-
-* For more information see this blog post with examples:
-*  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
-     - Create Elements using DOM, HTML fragments and Templates</a>. 
-* @constructor
-* @param {Number} limit how far back to go ... use 1000?
-* @param {Object} scope usually use document..
-*/
-
-Roo.lib.UndoManager = function (limit, undoScopeHost)
-{
-    this.stack = [];
-    this.limit = limit;
-    this.scope = undoScopeHost;
-    this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
-    if (this.fireEvent) {
-        this.bindEvents();
-    }
-    this.reset();
-    
-};
-        
-Roo.lib.UndoManager.prototype = {
-    
-    limit : false,
-    stack : false,
-    scope :  false,
-    fireEvent : false,
-    position : 0,
-    length : 0,
-    
-    
-     /**
-     * To push and execute a transaction, the method undoManager.transact
-     * must be called by passing a transaction object as the first argument, and a merge
-     * flag as the second argument. A transaction object has the following properties:
-     *
-     * Usage:
-<pre><code>
-undoManager.transact({
-    label: 'Typing',
-    execute: function() { ... },
-    undo: function() { ... },
-    // redo same as execute
-    redo: function() { this.execute(); }
-}, false);
-
-// merge transaction
-undoManager.transact({
-    label: 'Typing',
-    execute: function() { ... },  // this will be run...
-    undo: function() { ... }, // what to do when undo is run.
-    // redo same as execute
-    redo: function() { this.execute(); }
-}, true); 
-</code></pre> 
-     *
-     * 
-     * @param {Object} transaction The transaction to add to the stack.
-     * @return {String} The HTML fragment
-     */
-    
-    
-    transact : function (transaction, merge)
-    {
-        if (arguments.length < 2) {
-            throw new TypeError('Not enough arguments to UndoManager.transact.');
-        }
-
-        transaction.execute();
-
-        this.stack.splice(0, this.position);
-        if (merge && this.length) {
-            this.stack[0].push(transaction);
-        } else {
-            this.stack.unshift([transaction]);
-        }
-    
-        this.position = 0;
-
-        if (this.limit && this.stack.length > this.limit) {
-            this.length = this.stack.length = this.limit;
-        } else {
-            this.length = this.stack.length;
-        }
-
-        if (this.fireEvent) {
-            this.scope.dispatchEvent(
-                new CustomEvent('DOMTransaction', {
-                    detail: {
-                        transactions: this.stack[0].slice()
-                    },
-                    bubbles: true,
-                    cancelable: false
-                })
-            );
-        }
-        
-        //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
-      
-        
-    },
-
-    undo : function ()
-    {
-        //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
-        
-        if (this.position < this.length) {
-            for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
-                this.stack[this.position][i].undo();
-            }
-            this.position++;
-
-            if (this.fireEvent) {
-                this.scope.dispatchEvent(
-                    new CustomEvent('undo', {
-                        detail: {
-                            transactions: this.stack[this.position - 1].slice()
-                        },
-                        bubbles: true,
-                        cancelable: false
-                    })
-                );
-            }
-        }
-    },
-
-    redo : function ()
-    {
-        if (this.position > 0) {
-            for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
-                this.stack[this.position - 1][i].redo();
-            }
-            this.position--;
-
-            if (this.fireEvent) {
-                this.scope.dispatchEvent(
-                    new CustomEvent('redo', {
-                        detail: {
-                            transactions: this.stack[this.position].slice()
-                        },
-                        bubbles: true,
-                        cancelable: false
-                    })
-                );
-            }
-        }
-    },
-
-    item : function (index)
-    {
-        if (index >= 0 && index < this.length) {
-            return this.stack[index].slice();
-        }
-        return null;
-    },
-
-    clearUndo : function () {
-        this.stack.length = this.length = this.position;
-    },
-
-    clearRedo : function () {
-        this.stack.splice(0, this.position);
-        this.position = 0;
-        this.length = this.stack.length;
-    },
-    /**
-     * Reset the undo - probaly done on load to clear all history.
-     */
-    reset : function()
-    {
-        this.stack = [];
-        this.position = 0;
-        this.length = 0;
-        this.current_html = this.scope.innerHTML;
-        if (this.timer !== false) {
-            clearTimeout(this.timer);
-        }
-        this.timer = false;
-        this.merge = false;
-        this.addEvent();
-        
-    },
-    current_html : '',
-    timer : false,
-    merge : false,
-    
-    
-    // this will handle the undo/redo on the element.?
-    bindEvents : function()
-    {
-        var el  = this.scope;
-        el.undoManager = this;
-        
-        
-        this.scope.addEventListener('keydown', function(e) {
-            if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
-                if (e.shiftKey) {
-                    el.undoManager.redo(); // Ctrl/Command + Shift + Z
-                } else {
-                    el.undoManager.undo(); // Ctrl/Command + Z
-                }
-        
-                e.preventDefault();
-            }
-        });
-        /// ignore keyup..
-        this.scope.addEventListener('keyup', function(e) {
-            if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
-                e.preventDefault();
-            }
-        });
-        
-        
-        
-        var t = this;
-        
-        el.addEventListener('input', function(e) {
-            if(el.innerHTML == t.current_html) {
-                return;
-            }
-            // only record events every second.
-            if (t.timer !== false) {
-               clearTimeout(t.timer);
-               t.timer = false;
-            }
-            t.timer = setTimeout(function() { t.merge = false; }, 1000);
-            
-            t.addEvent(t.merge);
-            t.merge = true; // ignore changes happening every second..
-        });
-       },
-    /**
-     * Manually add an event.
-     * Normall called without arguements - and it will just get added to the stack.
-     * 
-     */
-    
-    addEvent : function(merge)
-    {
-        //Roo.log("undomanager +" + (merge ? 'Y':'n'));
-        // not sure if this should clear the timer 
-        merge = typeof(merge) == 'undefined' ? false : merge; 
-        
-        this.scope.undoManager.transact({
-            scope : this.scope,
-            oldHTML: this.current_html,
-            newHTML: this.scope.innerHTML,
-            // nothing to execute (content already changed when input is fired)
-            execute: function() { },
-            undo: function() {
-                this.scope.innerHTML = this.current_html = this.oldHTML;
-            },
-            redo: function() {
-                this.scope.innerHTML = this.current_html = this.newHTML;
-            }
-        }, false); //merge);
-        
-        this.merge = merge;
-        
-        this.current_html = this.scope.innerHTML;
-    }
-    
-    
-     
-    
-    
-    
-};
-/**
- * @class Roo.lib.Range
- * @constructor
- * This is a toolkit, normally used to copy features into a Dom Range element
- * Roo.lib.Range.wrap(x);
- *
- *
- *
- */
-Roo.lib.Range = function() { };
-
-/**
- * Wrap a Dom Range object, to give it new features...
- * @static
- * @param {Range} the range to wrap
- */
-Roo.lib.Range.wrap = function(r) {
-    return Roo.apply(r, Roo.lib.Range.prototype);
-};
-/**
- * find a parent node eg. LI / OL
- * @param {string|Array} node name or array of nodenames
- * @return {DomElement|false}
- */
-Roo.apply(Roo.lib.Range.prototype,
-{
-    
-    closest : function(str)
-    {
-        if (typeof(str) != 'string') {
-            // assume it's a array.
-            for(var i = 0;i < str.length;i++) {
-                var r = this.closest(str[i]);
-                if (r !== false) {
-                    return r;
-                }
-                
-            }
-            return false;
-        }
-        str = str.toLowerCase();
-        var n = this.commonAncestorContainer; // might not be a node
-        while (n.nodeType != 1) {
-            n = n.parentNode;
-        }
-        
-        if (n.nodeName.toLowerCase() == str ) {
-            return n;
-        }
-        if (n.nodeName.toLowerCase() == 'body') {
-            return false;
-        }
-            
-        return n.closest(str) || false;
-        
-    },
-    cloneRange : function()
-    {
-        return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
-    }
-});/**
- * @class Roo.lib.Selection
- * @constructor
- * This is a toolkit, normally used to copy features into a Dom Selection element
- * Roo.lib.Selection.wrap(x);
- *
- *
- *
- */
-Roo.lib.Selection = function() { };
-
-/**
- * Wrap a Dom Range object, to give it new features...
- * @static
- * @param {Range} the range to wrap
- */
-Roo.lib.Selection.wrap = function(r, doc) {
-    Roo.apply(r, Roo.lib.Selection.prototype);
-    r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
-    return r;
-};
-/**
- * find a parent node eg. LI / OL
- * @param {string|Array} node name or array of nodenames
- * @return {DomElement|false}
- */
-Roo.apply(Roo.lib.Selection.prototype,
-{
-    /**
-     * the owner document
-     */
-    ownerDocument : false,
-    
-    getRangeAt : function(n)
-    {
-        return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
-    },
-    
-    /**
-     * insert node at selection 
-     * @param {DomElement|string} node
-     * @param {string} cursor (after|in|none) where to place the cursor after inserting.
-     */
-    insertNode: function(node, cursor)
-    {
-        if (typeof(node) == 'string') {
-            node = this.ownerDocument.createElement(node);
-            if (cursor == 'in') {
-                node.innerHTML = '&nbsp;';
-            }
-        }
-        
-        var range = this.getRangeAt(0);
-        
-        if (this.type != 'Caret') {
-            range.deleteContents();
-        }
-        var sn = node.childNodes[0]; // select the contents.
-
-        
-        
-        range.insertNode(node);
-        if (cursor == 'after') {
-            node.insertAdjacentHTML('afterend', '&nbsp;');
-            sn = node.nextSibling;
-        }
-        
-        if (cursor == 'none') {
-            return;
-        }
-        
-        this.cursorText(sn);
-    },
-    
-    cursorText : function(n)
-    {
-       
-        //var range = this.getRangeAt(0);
-        range = Roo.lib.Range.wrap(new Range());
-        //range.selectNode(n);
-        
-        var ix = Array.from(n.parentNode.childNodes).indexOf(n);
-        range.setStart(n.parentNode,ix);
-        range.setEnd(n.parentNode,ix+1);
-        //range.collapse(false);
-         
-        this.removeAllRanges();
-        this.addRange(range);
-        
-        Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
-    },
-    cursorAfter : function(n)
-    {
-        if (!n.nextSibling || n.nextSibling.nodeValue != '&nbsp;') {
-            n.insertAdjacentHTML('afterend', '&nbsp;');
-        }
-        this.cursorText (n.nextSibling);
-    }
-        
-    
-});/*
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
index 051147b..92ff2e2 100644 (file)
@@ -209,26 +209,6 @@ i<J;++i){H[i]=[G[0]+H[i][0],G[1]+H[i][1]];}}this.runtimeAttributes[E]=[G];if(H.l
 var id=el.id||el.tagName;return ("Scroll "+id);};B.doMethod=function(C,D,E){var F=null;if(C=='scroll'){F=[this.method(this.currentFrame,D[0],E[0]-D[0],this.totalFrames),this.method(this.currentFrame,D[1],E[1]-D[1],this.totalFrames)];}else{F=A.doMethod.call(this,C,D,E);
 }return F;};B.getAttribute=function(C){var D=null;var el=this.getEl();if(C=='scroll'){D=[el.scrollLeft,el.scrollTop];}else{D=A.getAttribute.call(this,C);}return D;};B.setAttribute=function(C,D,E){var el=this.getEl();if(C=='scroll'){el.scrollLeft=D[0];el.scrollTop=D[1];
 }else{A.setAttribute.call(this,C,D,E);}};})();
 var id=el.id||el.tagName;return ("Scroll "+id);};B.doMethod=function(C,D,E){var F=null;if(C=='scroll'){F=[this.method(this.currentFrame,D[0],E[0]-D[0],this.totalFrames),this.method(this.currentFrame,D[1],E[1]-D[1],this.totalFrames)];}else{F=A.doMethod.call(this,C,D,E);
 }return F;};B.getAttribute=function(C){var D=null;var el=this.getEl();if(C=='scroll'){D=[el.scrollLeft,el.scrollTop];}else{D=A.getAttribute.call(this,C);}return D;};B.setAttribute=function(C,D,E){var el=this.getEl();if(C=='scroll'){el.scrollLeft=D[0];el.scrollTop=D[1];
 }else{A.setAttribute.call(this,C,D,E);}};})();
-// Roo/lib/UndoManager.js
-Roo.lib.UndoManager=function(A,B){this.stack=[];this.limit=A;this.scope=B;this.fireEvent=typeof CustomEvent!='undefined'&&B&&B.dispatchEvent;if(this.fireEvent){this.bindEvents();}this.reset();};Roo.lib.UndoManager.prototype={limit:false,stack:false,scope:false,fireEvent:false,position:0,length:0,transact:function(A,B){if(arguments.length<2){throw new TypeError('Not enough arguments to UndoManager.transact.');
-}A.execute();this.stack.splice(0,this.position);if(B&&this.length){this.stack[0].push(A);}else{this.stack.unshift([A]);}this.position=0;if(this.limit&&this.stack.length>this.limit){this.length=this.stack.length=this.limit;}else{this.length=this.stack.length;
-}if(this.fireEvent){this.scope.dispatchEvent(new CustomEvent('DOMTransaction',{detail:{transactions:this.stack[0].slice()},bubbles:true,cancelable:false}));}},undo:function(){if(this.position<this.length){for(var i=this.stack[this.position].length-1;i>=0;
-i--){this.stack[this.position][i].undo();}this.position++;if(this.fireEvent){this.scope.dispatchEvent(new CustomEvent('undo',{detail:{transactions:this.stack[this.position-1].slice()},bubbles:true,cancelable:false}));}}},redo:function(){if(this.position>0){for(var i=0,n=this.stack[this.position-1].length;
-i<n;i++){this.stack[this.position-1][i].redo();}this.position--;if(this.fireEvent){this.scope.dispatchEvent(new CustomEvent('redo',{detail:{transactions:this.stack[this.position].slice()},bubbles:true,cancelable:false}));}}},item:function(A){if(A>=0&&A<this.length){return this.stack[A].slice();
-}return null;},clearUndo:function(){this.stack.length=this.length=this.position;},clearRedo:function(){this.stack.splice(0,this.position);this.position=0;this.length=this.stack.length;},reset:function(){this.stack=[];this.position=0;this.length=0;this.current_html=this.scope.innerHTML;
-if(this.timer!==false){clearTimeout(this.timer);}this.timer=false;this.merge=false;this.addEvent();},current_html:'',timer:false,merge:false,bindEvents:function(){var el=this.scope;el.undoManager=this;this.scope.addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.keyCode===90){if(e.shiftKey){el.undoManager.redo();
-}else{el.undoManager.undo();}e.preventDefault();}});this.scope.addEventListener('keyup',function(e){if((e.ctrlKey||e.metaKey)&&e.keyCode===90){e.preventDefault();}});var t=this;el.addEventListener('input',function(e){if(el.innerHTML==t.current_html){return;
-}if(t.timer!==false){clearTimeout(t.timer);t.timer=false;}t.timer=setTimeout(function(){t.merge=false;},1000);t.addEvent(t.merge);t.merge=true;});},addEvent:function(A){A=typeof(A)=='undefined'?false:A;this.scope.undoManager.transact({scope:this.scope,oldHTML:this.current_html,newHTML:this.scope.innerHTML,execute:function(){}
-,undo:function(){this.scope.innerHTML=this.current_html=this.oldHTML;},redo:function(){this.scope.innerHTML=this.current_html=this.newHTML;}},false);this.merge=A;this.current_html=this.scope.innerHTML;}};
-// Roo/lib/Range.js
-Roo.lib.Range=function(){};Roo.lib.Range.wrap=function(r){return Roo.apply(r,Roo.lib.Range.prototype);};Roo.apply(Roo.lib.Range.prototype,{closest:function(A){if(typeof(A)!='string'){for(var i=0;i<A.length;i++){var r=this.closest(A[i]);if(r!==false){return r;
-}}return false;}A=A.toLowerCase();var n=this.commonAncestorContainer;while(n.nodeType!=1){n=n.parentNode;}if(n.nodeName.toLowerCase()==A){return n;}if(n.nodeName.toLowerCase()=='body'){return false;}return n.closest(A)||false;},cloneRange:function(){return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
-}});
-// Roo/lib/Selection.js
-Roo.lib.Selection=function(){};Roo.lib.Selection.wrap=function(r,A){Roo.apply(r,Roo.lib.Selection.prototype);r.ownerDocument=A;return r;};Roo.apply(Roo.lib.Selection.prototype,{ownerDocument:false,getRangeAt:function(n){return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
-},insertNode:function(A,B){if(typeof(A)=='string'){A=this.ownerDocument.createElement(A);if(B=='in'){A.innerHTML='&nbsp;';}}var C=this.getRangeAt(0);if(this.type!='Caret'){C.deleteContents();}var sn=A.childNodes[0];C.insertNode(A);if(B=='after'){A.insertAdjacentHTML('afterend','&nbsp;');
-sn=A.nextSibling;}if(B=='none'){return;}this.cursorText(sn);},cursorText:function(n){range=Roo.lib.Range.wrap(new Range());var ix=Array.from(n.parentNode.childNodes).indexOf(n);range.setStart(n.parentNode,ix);range.setEnd(n.parentNode,ix+1);this.removeAllRanges();
-this.addRange(range);Roo.log([n,range,this,this.baseOffset,this.extentOffset,this.type]);},cursorAfter:function(n){if(!n.nextSibling||n.nextSibling.nodeValue!='&nbsp;'){n.insertAdjacentHTML('afterend','&nbsp;');}this.cursorText(n.nextSibling);}});
 // Roo/DomHelper.js
 if(typeof Range!="undefined"&&typeof Range.prototype.createContextualFragment=="undefined"){Range.prototype.createContextualFragment=function(A){var B=window.document;var C=B.createElement("div");C.innerHTML=A;var D=B.createDocumentFragment(),n;while((n=C.firstChild)){D.appendChild(n);
 }return D;};}Roo.DomHelper=function(){var A=null;var B=/^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;var C=/^table|tbody|tr|td$/i;var D={};var E=function(o){if(typeof o=='string'){return o;}var b="";if(!o.tag){o.tag="div";}b+="<"+o.tag;
 // Roo/DomHelper.js
 if(typeof Range!="undefined"&&typeof Range.prototype.createContextualFragment=="undefined"){Range.prototype.createContextualFragment=function(A){var B=window.document;var C=B.createElement("div");C.innerHTML=A;var D=B.createDocumentFragment(),n;while((n=C.firstChild)){D.appendChild(n);
 }return D;};}Roo.DomHelper=function(){var A=null;var B=/^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;var C=/^table|tbody|tr|td$/i;var D={};var E=function(o){if(typeof o=='string'){return o;}var b="";if(!o.tag){o.tag="div";}b+="<"+o.tag;
index d2b15cc..f903c90 100644 (file)
@@ -4907,468 +4907,7 @@ Roo.lib.Easing = {
             }
         };
     })();
             }
         };
     })();
-/**
- * Originally based of this code... - refactored for Roo...
- * https://github.com/aaalsaleh/undo-manager
- * undo-manager.js
- * @author  Abdulrahman Alsaleh 
- * @copyright 2015 Abdulrahman Alsaleh 
- * @license  MIT License (c) 
- *
- * Hackily modifyed by alan@roojs.com
- *
- *
- *  
- *
- *  TOTALLY UNTESTED...
- *
- *  Documentation to be done....
- */
-
-/**
-* @class Roo.lib.UndoManager
-* An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
-* Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
-
- * Usage:
- * <pre><code>
-
-
-editor.undoManager = new Roo.lib.UndoManager(1000, editor);
-</code></pre>
-
-* For more information see this blog post with examples:
-*  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
-     - Create Elements using DOM, HTML fragments and Templates</a>. 
-* @constructor
-* @param {Number} limit how far back to go ... use 1000?
-* @param {Object} scope usually use document..
-*/
-
-Roo.lib.UndoManager = function (limit, undoScopeHost)
-{
-    this.stack = [];
-    this.limit = limit;
-    this.scope = undoScopeHost;
-    this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
-    if (this.fireEvent) {
-        this.bindEvents();
-    }
-    this.reset();
-    
-};
-        
-Roo.lib.UndoManager.prototype = {
-    
-    limit : false,
-    stack : false,
-    scope :  false,
-    fireEvent : false,
-    position : 0,
-    length : 0,
-    
-    
-     /**
-     * To push and execute a transaction, the method undoManager.transact
-     * must be called by passing a transaction object as the first argument, and a merge
-     * flag as the second argument. A transaction object has the following properties:
-     *
-     * Usage:
-<pre><code>
-undoManager.transact({
-    label: 'Typing',
-    execute: function() { ... },
-    undo: function() { ... },
-    // redo same as execute
-    redo: function() { this.execute(); }
-}, false);
-
-// merge transaction
-undoManager.transact({
-    label: 'Typing',
-    execute: function() { ... },  // this will be run...
-    undo: function() { ... }, // what to do when undo is run.
-    // redo same as execute
-    redo: function() { this.execute(); }
-}, true); 
-</code></pre> 
-     *
-     * 
-     * @param {Object} transaction The transaction to add to the stack.
-     * @return {String} The HTML fragment
-     */
-    
-    
-    transact : function (transaction, merge)
-    {
-        if (arguments.length < 2) {
-            throw new TypeError('Not enough arguments to UndoManager.transact.');
-        }
-
-        transaction.execute();
-
-        this.stack.splice(0, this.position);
-        if (merge && this.length) {
-            this.stack[0].push(transaction);
-        } else {
-            this.stack.unshift([transaction]);
-        }
-    
-        this.position = 0;
-
-        if (this.limit && this.stack.length > this.limit) {
-            this.length = this.stack.length = this.limit;
-        } else {
-            this.length = this.stack.length;
-        }
-
-        if (this.fireEvent) {
-            this.scope.dispatchEvent(
-                new CustomEvent('DOMTransaction', {
-                    detail: {
-                        transactions: this.stack[0].slice()
-                    },
-                    bubbles: true,
-                    cancelable: false
-                })
-            );
-        }
-        
-        //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
-      
-        
-    },
-
-    undo : function ()
-    {
-        //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
-        
-        if (this.position < this.length) {
-            for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
-                this.stack[this.position][i].undo();
-            }
-            this.position++;
-
-            if (this.fireEvent) {
-                this.scope.dispatchEvent(
-                    new CustomEvent('undo', {
-                        detail: {
-                            transactions: this.stack[this.position - 1].slice()
-                        },
-                        bubbles: true,
-                        cancelable: false
-                    })
-                );
-            }
-        }
-    },
-
-    redo : function ()
-    {
-        if (this.position > 0) {
-            for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
-                this.stack[this.position - 1][i].redo();
-            }
-            this.position--;
-
-            if (this.fireEvent) {
-                this.scope.dispatchEvent(
-                    new CustomEvent('redo', {
-                        detail: {
-                            transactions: this.stack[this.position].slice()
-                        },
-                        bubbles: true,
-                        cancelable: false
-                    })
-                );
-            }
-        }
-    },
-
-    item : function (index)
-    {
-        if (index >= 0 && index < this.length) {
-            return this.stack[index].slice();
-        }
-        return null;
-    },
-
-    clearUndo : function () {
-        this.stack.length = this.length = this.position;
-    },
-
-    clearRedo : function () {
-        this.stack.splice(0, this.position);
-        this.position = 0;
-        this.length = this.stack.length;
-    },
-    /**
-     * Reset the undo - probaly done on load to clear all history.
-     */
-    reset : function()
-    {
-        this.stack = [];
-        this.position = 0;
-        this.length = 0;
-        this.current_html = this.scope.innerHTML;
-        if (this.timer !== false) {
-            clearTimeout(this.timer);
-        }
-        this.timer = false;
-        this.merge = false;
-        this.addEvent();
-        
-    },
-    current_html : '',
-    timer : false,
-    merge : false,
-    
-    
-    // this will handle the undo/redo on the element.?
-    bindEvents : function()
-    {
-        var el  = this.scope;
-        el.undoManager = this;
-        
-        
-        this.scope.addEventListener('keydown', function(e) {
-            if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
-                if (e.shiftKey) {
-                    el.undoManager.redo(); // Ctrl/Command + Shift + Z
-                } else {
-                    el.undoManager.undo(); // Ctrl/Command + Z
-                }
-        
-                e.preventDefault();
-            }
-        });
-        /// ignore keyup..
-        this.scope.addEventListener('keyup', function(e) {
-            if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
-                e.preventDefault();
-            }
-        });
-        
-        
-        
-        var t = this;
-        
-        el.addEventListener('input', function(e) {
-            if(el.innerHTML == t.current_html) {
-                return;
-            }
-            // only record events every second.
-            if (t.timer !== false) {
-               clearTimeout(t.timer);
-               t.timer = false;
-            }
-            t.timer = setTimeout(function() { t.merge = false; }, 1000);
-            
-            t.addEvent(t.merge);
-            t.merge = true; // ignore changes happening every second..
-        });
-       },
-    /**
-     * Manually add an event.
-     * Normall called without arguements - and it will just get added to the stack.
-     * 
-     */
-    
-    addEvent : function(merge)
-    {
-        //Roo.log("undomanager +" + (merge ? 'Y':'n'));
-        // not sure if this should clear the timer 
-        merge = typeof(merge) == 'undefined' ? false : merge; 
-        
-        this.scope.undoManager.transact({
-            scope : this.scope,
-            oldHTML: this.current_html,
-            newHTML: this.scope.innerHTML,
-            // nothing to execute (content already changed when input is fired)
-            execute: function() { },
-            undo: function() {
-                this.scope.innerHTML = this.current_html = this.oldHTML;
-            },
-            redo: function() {
-                this.scope.innerHTML = this.current_html = this.newHTML;
-            }
-        }, false); //merge);
-        
-        this.merge = merge;
-        
-        this.current_html = this.scope.innerHTML;
-    }
-    
-    
-     
-    
-    
-    
-};
-/**
- * @class Roo.lib.Range
- * @constructor
- * This is a toolkit, normally used to copy features into a Dom Range element
- * Roo.lib.Range.wrap(x);
- *
- *
- *
- */
-Roo.lib.Range = function() { };
-
-/**
- * Wrap a Dom Range object, to give it new features...
- * @static
- * @param {Range} the range to wrap
- */
-Roo.lib.Range.wrap = function(r) {
-    return Roo.apply(r, Roo.lib.Range.prototype);
-};
-/**
- * find a parent node eg. LI / OL
- * @param {string|Array} node name or array of nodenames
- * @return {DomElement|false}
- */
-Roo.apply(Roo.lib.Range.prototype,
-{
-    
-    closest : function(str)
-    {
-        if (typeof(str) != 'string') {
-            // assume it's a array.
-            for(var i = 0;i < str.length;i++) {
-                var r = this.closest(str[i]);
-                if (r !== false) {
-                    return r;
-                }
-                
-            }
-            return false;
-        }
-        str = str.toLowerCase();
-        var n = this.commonAncestorContainer; // might not be a node
-        while (n.nodeType != 1) {
-            n = n.parentNode;
-        }
-        
-        if (n.nodeName.toLowerCase() == str ) {
-            return n;
-        }
-        if (n.nodeName.toLowerCase() == 'body') {
-            return false;
-        }
-            
-        return n.closest(str) || false;
-        
-    },
-    cloneRange : function()
-    {
-        return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
-    }
-});/**
- * @class Roo.lib.Selection
- * @constructor
- * This is a toolkit, normally used to copy features into a Dom Selection element
- * Roo.lib.Selection.wrap(x);
- *
- *
- *
- */
-Roo.lib.Selection = function() { };
-
-/**
- * Wrap a Dom Range object, to give it new features...
- * @static
- * @param {Range} the range to wrap
- */
-Roo.lib.Selection.wrap = function(r, doc) {
-    Roo.apply(r, Roo.lib.Selection.prototype);
-    r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
-    return r;
-};
-/**
- * find a parent node eg. LI / OL
- * @param {string|Array} node name or array of nodenames
- * @return {DomElement|false}
- */
-Roo.apply(Roo.lib.Selection.prototype,
-{
-    /**
-     * the owner document
-     */
-    ownerDocument : false,
-    
-    getRangeAt : function(n)
-    {
-        return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
-    },
-    
-    /**
-     * insert node at selection 
-     * @param {DomElement|string} node
-     * @param {string} cursor (after|in|none) where to place the cursor after inserting.
-     */
-    insertNode: function(node, cursor)
-    {
-        if (typeof(node) == 'string') {
-            node = this.ownerDocument.createElement(node);
-            if (cursor == 'in') {
-                node.innerHTML = '&nbsp;';
-            }
-        }
-        
-        var range = this.getRangeAt(0);
-        
-        if (this.type != 'Caret') {
-            range.deleteContents();
-        }
-        var sn = node.childNodes[0]; // select the contents.
-
-        
-        
-        range.insertNode(node);
-        if (cursor == 'after') {
-            node.insertAdjacentHTML('afterend', '&nbsp;');
-            sn = node.nextSibling;
-        }
-        
-        if (cursor == 'none') {
-            return;
-        }
-        
-        this.cursorText(sn);
-    },
-    
-    cursorText : function(n)
-    {
-       
-        //var range = this.getRangeAt(0);
-        range = Roo.lib.Range.wrap(new Range());
-        //range.selectNode(n);
-        
-        var ix = Array.from(n.parentNode.childNodes).indexOf(n);
-        range.setStart(n.parentNode,ix);
-        range.setEnd(n.parentNode,ix+1);
-        //range.collapse(false);
-         
-        this.removeAllRanges();
-        this.addRange(range);
-        
-        Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
-    },
-    cursorAfter : function(n)
-    {
-        if (!n.nextSibling || n.nextSibling.nodeValue != '&nbsp;') {
-            n.insertAdjacentHTML('afterend', '&nbsp;');
-        }
-        this.cursorText (n.nextSibling);
-    }
-        
-    
-});/*
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -45066,4377 +44605,7 @@ Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
     } 
     
     
     } 
     
     
-});Roo.rtf = {}; // namespace
-Roo.rtf.Hex = function(hex)
-{
-    this.hexstr = hex;
-};
-Roo.rtf.Paragraph = function(opts)
-{
-    this.content = []; ///??? is that used?
-};Roo.rtf.Span = function(opts)
-{
-    this.value = opts.value;
-};
-
-Roo.rtf.Group = function(parent)
-{
-    // we dont want to acutally store parent - it will make debug a nightmare..
-    this.content = [];
-    this.cn  = [];
-     
-       
-    
-};
-
-Roo.rtf.Group.prototype = {
-    ignorable : false,
-    content: false,
-    cn: false,
-    addContent : function(node) {
-        // could set styles...
-        this.content.push(node);
-    },
-    addChild : function(cn)
-    {
-        this.cn.push(cn);
-    },
-    // only for images really...
-    toDataURL : function()
-    {
-        var mimetype = false;
-        switch(true) {
-            case this.content.filter(function(a) { return a.value == 'pngblip' } ).length > 0: 
-                mimetype = "image/png";
-                break;
-             case this.content.filter(function(a) { return a.value == 'jpegblip' } ).length > 0:
-                mimetype = "image/jpeg";
-                break;
-            default :
-                return 'about:blank'; // ?? error?
-        }
-        
-        
-        var hexstring = this.content[this.content.length-1].value;
-        
-        return 'data:' + mimetype + ';base64,' + btoa(hexstring.match(/\w{2}/g).map(function(a) {
-            return String.fromCharCode(parseInt(a, 16));
-        }).join(""));
-    }
-    
-};
-// this looks like it's normally the {rtf{ .... }}
-Roo.rtf.Document = function()
-{
-    // we dont want to acutally store parent - it will make debug a nightmare..
-    this.rtlch  = [];
-    this.content = [];
-    this.cn = [];
-    
-};
-Roo.extend(Roo.rtf.Document, Roo.rtf.Group, { 
-    addChild : function(cn)
-    {
-        this.cn.push(cn);
-        switch(cn.type) {
-            case 'rtlch': // most content seems to be inside this??
-            case 'listtext':
-            case 'shpinst':
-                this.rtlch.push(cn);
-                return;
-            default:
-                this[cn.type] = cn;
-        }
-        
-    },
-    
-    getElementsByType : function(type)
-    {
-        var ret =  [];
-        this._getElementsByType(type, ret, this.cn, 'rtf');
-        return ret;
-    },
-    _getElementsByType : function (type, ret, search_array, path)
-    {
-        search_array.forEach(function(n,i) {
-            if (n.type == type) {
-                n.path = path + '/' + n.type + ':' + i;
-                ret.push(n);
-            }
-            if (n.cn.length > 0) {
-                this._getElementsByType(type, ret, n.cn, path + '/' + n.type+':'+i);
-            }
-        },this);
-    }
-    
-});
-Roo.rtf.Ctrl = function(opts)
-{
-    this.value = opts.value;
-    this.param = opts.param;
-};
-/**
- *
- *
- * based on this https://github.com/iarna/rtf-parser
- * it's really only designed to extract pict from pasted RTF 
- *
- * usage:
- *
- *  var images = new Roo.rtf.Parser().parse(a_string).filter(function(g) { return g.type == 'pict'; });
- *  
- *
- */
-
-
-
-
-Roo.rtf.Parser = function(text) {
-    //super({objectMode: true})
-    this.text = '';
-    this.parserState = this.parseText;
-    
-    // these are for interpeter...
-    this.doc = {};
-    ///this.parserState = this.parseTop
-    this.groupStack = [];
-    this.hexStore = [];
-    this.doc = false;
-    
-    this.groups = []; // where we put the return.
-    
-    for (var ii = 0; ii < text.length; ++ii) {
-        ++this.cpos;
-        
-        if (text[ii] === '\n') {
-            ++this.row;
-            this.col = 1;
-        } else {
-            ++this.col;
-        }
-        this.parserState(text[ii]);
-    }
-    
-    
-    
-};
-Roo.rtf.Parser.prototype = {
-    text : '', // string being parsed..
-    controlWord : '',
-    controlWordParam :  '',
-    hexChar : '',
-    doc : false,
-    group: false,
-    groupStack : false,
-    hexStore : false,
-    
-    
-    cpos : 0, 
-    row : 1, // reportin?
-    col : 1, //
-
-     
-    push : function (el)
-    {
-        var m = 'cmd'+ el.type;
-        if (typeof(this[m]) == 'undefined') {
-            Roo.log('invalid cmd:' + el.type);
-            return;
-        }
-        this[m](el);
-        //Roo.log(el);
-    },
-    flushHexStore : function()
-    {
-        if (this.hexStore.length < 1) {
-            return;
-        }
-        var hexstr = this.hexStore.map(
-            function(cmd) {
-                return cmd.value;
-        }).join('');
-        
-        this.group.addContent( new Roo.rtf.Hex( hexstr ));
-              
-            
-        this.hexStore.splice(0)
-        
-    },
-    
-    cmdgroupstart : function()
-    {
-        this.flushHexStore();
-        if (this.group) {
-            this.groupStack.push(this.group);
-        }
-         // parent..
-        if (this.doc === false) {
-            this.group = this.doc = new Roo.rtf.Document();
-            return;
-            
-        }
-        this.group = new Roo.rtf.Group(this.group);
-    },
-    cmdignorable : function()
-    {
-        this.flushHexStore();
-        this.group.ignorable = true;
-    },
-    cmdendparagraph : function()
-    {
-        this.flushHexStore();
-        this.group.addContent(new Roo.rtf.Paragraph());
-    },
-    cmdgroupend : function ()
-    {
-        this.flushHexStore();
-        var endingGroup = this.group;
-        
-        
-        this.group = this.groupStack.pop();
-        if (this.group) {
-            this.group.addChild(endingGroup);
-        }
-        
-        
-        
-        var doc = this.group || this.doc;
-        //if (endingGroup instanceof FontTable) {
-        //  doc.fonts = endingGroup.table
-        //} else if (endingGroup instanceof ColorTable) {
-        //  doc.colors = endingGroup.table
-        //} else if (endingGroup !== this.doc && !endingGroup.get('ignorable')) {
-        if (endingGroup.ignorable === false) {
-            //code
-            this.groups.push(endingGroup);
-           // Roo.log( endingGroup );
-        }
-            //Roo.each(endingGroup.content, function(item)) {
-            //    doc.addContent(item);
-            //}
-            //process.emit('debug', 'GROUP END', endingGroup.type, endingGroup.get('ignorable'))
-        //}
-    },
-    cmdtext : function (cmd)
-    {
-        this.flushHexStore();
-        if (!this.group) { // an RTF fragment, missing the {\rtf1 header
-            //this.group = this.doc
-        }
-        this.group.addContent(new Roo.rtf.Span(cmd));
-    },
-    cmdcontrolword : function (cmd)
-    {
-        this.flushHexStore();
-        if (!this.group.type) {
-            this.group.type = cmd.value;
-            return;
-        }
-        this.group.addContent(new Roo.rtf.Ctrl(cmd));
-        // we actually don't care about ctrl words...
-        return ;
-        /*
-        var method = 'ctrl$' + cmd.value.replace(/-(.)/g, (_, char) => char.toUpperCase())
-        if (this[method]) {
-            this[method](cmd.param)
-        } else {
-            if (!this.group.get('ignorable')) process.emit('debug', method, cmd.param)
-        }
-        */
-    },
-    cmdhexchar : function(cmd) {
-        this.hexStore.push(cmd);
-    },
-    cmderror : function(cmd) {
-        throw new Exception (cmd.value);
-    },
-    
-    /*
-      _flush (done) {
-        if (this.text !== '\u0000') this.emitText()
-        done()
-      }
-      */
-      
-      
-    parseText : function(c)
-    {
-        if (c === '\\') {
-            this.parserState = this.parseEscapes;
-        } else if (c === '{') {
-            this.emitStartGroup();
-        } else if (c === '}') {
-            this.emitEndGroup();
-        } else if (c === '\x0A' || c === '\x0D') {
-            // cr/lf are noise chars
-        } else {
-            this.text += c;
-        }
-    },
-    
-    parseEscapes: function (c)
-    {
-        if (c === '\\' || c === '{' || c === '}') {
-            this.text += c;
-            this.parserState = this.parseText;
-        } else {
-            this.parserState = this.parseControlSymbol;
-            this.parseControlSymbol(c);
-        }
-    },
-    parseControlSymbol: function(c)
-    {
-        if (c === '~') {
-            this.text += '\u00a0'; // nbsp
-            this.parserState = this.parseText
-        } else if (c === '-') {
-             this.text += '\u00ad'; // soft hyphen
-        } else if (c === '_') {
-            this.text += '\u2011'; // non-breaking hyphen
-        } else if (c === '*') {
-            this.emitIgnorable();
-            this.parserState = this.parseText;
-        } else if (c === "'") {
-            this.parserState = this.parseHexChar;
-        } else if (c === '|') { // formula cacter
-            this.emitFormula();
-            this.parserState = this.parseText;
-        } else if (c === ':') { // subentry in an index entry
-            this.emitIndexSubEntry();
-            this.parserState = this.parseText;
-        } else if (c === '\x0a') {
-            this.emitEndParagraph();
-            this.parserState = this.parseText;
-        } else if (c === '\x0d') {
-            this.emitEndParagraph();
-            this.parserState = this.parseText;
-        } else {
-            this.parserState = this.parseControlWord;
-            this.parseControlWord(c);
-        }
-    },
-    parseHexChar: function (c)
-    {
-        if (/^[A-Fa-f0-9]$/.test(c)) {
-            this.hexChar += c;
-            if (this.hexChar.length >= 2) {
-              this.emitHexChar();
-              this.parserState = this.parseText;
-            }
-            return;
-        }
-        this.emitError("Invalid character \"" + c + "\" in hex literal.");
-        this.parserState = this.parseText;
-        
-    },
-    parseControlWord : function(c)
-    {
-        if (c === ' ') {
-            this.emitControlWord();
-            this.parserState = this.parseText;
-        } else if (/^[-\d]$/.test(c)) {
-            this.parserState = this.parseControlWordParam;
-            this.controlWordParam += c;
-        } else if (/^[A-Za-z]$/.test(c)) {
-          this.controlWord += c;
-        } else {
-          this.emitControlWord();
-          this.parserState = this.parseText;
-          this.parseText(c);
-        }
-    },
-    parseControlWordParam : function (c) {
-        if (/^\d$/.test(c)) {
-          this.controlWordParam += c;
-        } else if (c === ' ') {
-          this.emitControlWord();
-          this.parserState = this.parseText;
-        } else {
-          this.emitControlWord();
-          this.parserState = this.parseText;
-          this.parseText(c);
-        }
-    },
-    
-    
-    
-    
-    emitText : function () {
-        if (this.text === '') {
-            return;
-        }
-        this.push({
-            type: 'text',
-            value: this.text,
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-        this.text = ''
-    },
-    emitControlWord : function ()
-    {
-        this.emitText();
-        if (this.controlWord === '') {
-            this.emitError('empty control word');
-        } else {
-            this.push({
-                  type: 'controlword',
-                  value: this.controlWord,
-                  param: this.controlWordParam !== '' && Number(this.controlWordParam),
-                  pos: this.cpos,
-                  row: this.row,
-                  col: this.col
-            });
-        }
-        this.controlWord = '';
-        this.controlWordParam = '';
-    },
-    emitStartGroup : function ()
-    {
-        this.emitText();
-        this.push({
-            type: 'groupstart',
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-    },
-    emitEndGroup : function ()
-    {
-        this.emitText();
-        this.push({
-            type: 'groupend',
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-    },
-    emitIgnorable : function ()
-    {
-        this.emitText();
-        this.push({
-            type: 'ignorable',
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-    },
-    emitHexChar : function ()
-    {
-        this.emitText();
-        this.push({
-            type: 'hexchar',
-            value: this.hexChar,
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-        this.hexChar = ''
-    },
-    emitError : function (message)
-    {
-      this.emitText();
-      this.push({
-            type: 'error',
-            value: message,
-            row: this.row,
-            col: this.col,
-            char: this.cpos //,
-            //stack: new Error().stack
-        });
-    },
-    emitEndParagraph : function () {
-        this.emitText();
-        this.push({
-            type: 'endparagraph',
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-    }
-     
-} ;
-Roo.htmleditor = {};
-/**
- * @class Roo.htmleditor.Filter
- * Base Class for filtering htmleditor stuff. - do not use this directly - extend it.
- * @cfg {DomElement} node The node to iterate and filter
- * @cfg {boolean|String|Array} tag Tags to replace 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-
-
-Roo.htmleditor.Filter = function(cfg) {
-    Roo.apply(this.cfg);
-    // this does not actually call walk as it's really just a abstract class
-}
-
-
-Roo.htmleditor.Filter.prototype = {
-    
-    node: false,
-    
-    tag: false,
-
-    // overrride to do replace comments.
-    replaceComment : false,
-    
-    // overrride to do replace or do stuff with tags..
-    replaceTag : false,
-    
-    walk : function(dom)
-    {
-        Roo.each( Array.from(dom.childNodes), function( e ) {
-            switch(true) {
-                
-                case e.nodeType == 8 &&  this.replaceComment  !== false: // comment
-                    this.replaceComment(e);
-                    return;
-                
-                case e.nodeType != 1: //not a node.
-                    return;
-                
-                case this.tag === true: // everything
-                case typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1: // array and it matches.
-                case typeof(this.tag) == 'string' && this.tag == e.tagName: // array and it matches.
-                    if (this.replaceTag && false === this.replaceTag(e)) {
-                        return;
-                    }
-                    if (e.hasChildNodes()) {
-                        this.walk(e);
-                    }
-                    return;
-                
-                default:    // tags .. that do not match.
-                    if (e.hasChildNodes()) {
-                        this.walk(e);
-                    }
-            }
-            
-        }, this);
-        
-    }
-}; 
-
-/**
- * @class Roo.htmleditor.FilterAttributes
- * clean attributes and  styles including http:// etc.. in attribute
- * @constructor
-* Run a new Attribute Filter
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterAttributes = function(cfg)
-{
-    Roo.apply(this, cfg);
-    this.attrib_black = this.attrib_black || [];
-    this.attrib_white = this.attrib_white || [];
-
-    this.attrib_clean = this.attrib_clean || [];
-    this.style_white = this.style_white || [];
-    this.style_black = this.style_black || [];
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterAttributes, Roo.htmleditor.Filter,
-{
-    tag: true, // all tags
-    
-    attrib_black : false, // array
-    attrib_clean : false,
-    attrib_white : false,
-
-    style_white : false,
-    style_black : false,
-     
-     
-    replaceTag : function(node)
-    {
-        if (!node.attributes || !node.attributes.length) {
-            return true;
-        }
-        
-        for (var i = node.attributes.length-1; i > -1 ; i--) {
-            var a = node.attributes[i];
-            //console.log(a);
-            if (this.attrib_white.length && this.attrib_white.indexOf(a.name.toLowerCase()) < 0) {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            
-            
-            
-            if (a.name.toLowerCase().substr(0,2)=='on')  {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            
-            
-            if (this.attrib_black.indexOf(a.name.toLowerCase()) > -1) {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            if (this.attrib_clean.indexOf(a.name.toLowerCase()) > -1) {
-                this.cleanAttr(node,a.name,a.value); // fixme..
-                continue;
-            }
-            if (a.name == 'style') {
-                this.cleanStyle(node,a.name,a.value);
-                continue;
-            }
-            /// clean up MS crap..
-            // tecnically this should be a list of valid class'es..
-            
-            
-            if (a.name == 'class') {
-                if (a.value.match(/^Mso/)) {
-                    node.removeAttribute('class');
-                }
-                
-                if (a.value.match(/^body$/)) {
-                    node.removeAttribute('class');
-                }
-                continue;
-            }
-            
-            
-            // style cleanup!?
-            // class cleanup?
-            
-        }
-        return true; // clean children
-    },
-        
-    cleanAttr: function(node, n,v)
-    {
-        
-        if (v.match(/^\./) || v.match(/^\//)) {
-            return;
-        }
-        if (v.match(/^(http|https):\/\//)
-            || v.match(/^mailto:/) 
-            || v.match(/^ftp:/)
-            || v.match(/^data:/)
-            ) {
-            return;
-        }
-        if (v.match(/^#/)) {
-            return;
-        }
-        if (v.match(/^\{/)) { // allow template editing.
-            return;
-        }
-//            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
-        node.removeAttribute(n);
-        
-    },
-    cleanStyle : function(node,  n,v)
-    {
-        if (v.match(/expression/)) { //XSS?? should we even bother..
-            node.removeAttribute(n);
-            return;
-        }
-        
-        var parts = v.split(/;/);
-        var clean = [];
-        
-        Roo.each(parts, function(p) {
-            p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
-            if (!p.length) {
-                return true;
-            }
-            var l = p.split(':').shift().replace(/\s+/g,'');
-            l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
-            
-            if ( this.style_black.length && (this.style_black.indexOf(l) > -1 || this.style_black.indexOf(l.toLowerCase()) > -1)) {
-                return true;
-            }
-            //Roo.log()
-            // only allow 'c whitelisted system attributes'
-            if ( this.style_white.length &&  style_white.indexOf(l) < 0 && style_white.indexOf(l.toLowerCase()) < 0 ) {
-                return true;
-            }
-            
-            
-            clean.push(p);
-            return true;
-        },this);
-        if (clean.length) { 
-            node.setAttribute(n, clean.join(';'));
-        } else {
-            node.removeAttribute(n);
-        }
-        
-    }
-        
-        
-        
-    
-});/**
- * @class Roo.htmleditor.FilterBlack
- * remove blacklisted elements.
- * @constructor
- * Run a new Blacklisted Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterBlack = function(cfg)
-{
-    Roo.apply(this, cfg);
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterBlack, Roo.htmleditor.Filter,
-{
-    tag : true, // all elements.
-   
-    replaceTag : function(n)
-    {
-        n.parentNode.removeChild(n);
-    }
-});
-/**
- * @class Roo.htmleditor.FilterComment
- * remove comments.
- * @constructor
-* Run a new Comments Filter
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterComment = function(cfg)
-{
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterComment, Roo.htmleditor.Filter,
-{
-  
-    replaceComment : function(n)
-    {
-        n.parentNode.removeChild(n);
-    }
-});/**
- * @class Roo.htmleditor.FilterKeepChildren
- * remove tags but keep children
- * @constructor
- * Run a new Keep Children Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterKeepChildren = function(cfg)
-{
-    Roo.apply(this, cfg);
-    if (this.tag === false) {
-        return; // dont walk.. (you can use this to use this just to do a child removal on a single tag )
-    }
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterKeepChildren, Roo.htmleditor.FilterBlack,
-{
-    
-  
-    replaceTag : function(node)
-    {
-        // walk children...
-        //Roo.log(node);
-        var ar = Array.from(node.childNodes);
-        //remove first..
-        for (var i = 0; i < ar.length; i++) {
-            if (ar[i].nodeType == 1) {
-                if (
-                    (typeof(this.tag) == 'object' && this.tag.indexOf(ar[i].tagName) > -1)
-                    || // array and it matches
-                    (typeof(this.tag) == 'string' && this.tag == ar[i].tagName)
-                ) {
-                    this.replaceTag(ar[i]); // child is blacklisted as well...
-                    continue;
-                }
-            }
-        }  
-        ar = Array.from(node.childNodes);
-        for (var i = 0; i < ar.length; i++) {
-         
-            node.removeChild(ar[i]);
-            // what if we need to walk these???
-            node.parentNode.insertBefore(ar[i], node);
-            if (this.tag !== false) {
-                this.walk(ar[i]);
-                
-            }
-        }
-        node.parentNode.removeChild(node);
-        return false; // don't walk children
-        
-        
-    }
-});/**
- * @class Roo.htmleditor.FilterParagraph
- * paragraphs cause a nightmare for shared content - this filter is designed to be called ? at various points when editing
- * like on 'push' to remove the <p> tags and replace them with line breaks.
- * @constructor
- * Run a new Paragraph Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterParagraph = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterParagraph, Roo.htmleditor.Filter,
-{
-    
-     
-    tag : 'P',
-    
-     
-    replaceTag : function(node)
-    {
-        
-        if (node.childNodes.length == 1 &&
-            node.childNodes[0].nodeType == 3 &&
-            node.childNodes[0].textContent.trim().length < 1
-            ) {
-            // remove and replace with '<BR>';
-            node.parentNode.replaceChild(node.ownerDocument.createElement('BR'),node);
-            return false; // no need to walk..
-        }
-        var ar = Array.from(node.childNodes);
-        for (var i = 0; i < ar.length; i++) {
-            node.removeChild(ar[i]);
-            // what if we need to walk these???
-            node.parentNode.insertBefore(ar[i], node);
-        }
-        // now what about this?
-        // <p> &nbsp; </p>
-        
-        // double BR.
-        node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
-        node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
-        node.parentNode.removeChild(node);
-        
-        return false;
-
-    }
-    
-});/**
- * @class Roo.htmleditor.FilterSpan
- * filter span's with no attributes out..
- * @constructor
- * Run a new Span Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterSpan = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterSpan, Roo.htmleditor.FilterKeepChildren,
-{
-     
-    tag : 'SPAN',
-     
-    replaceTag : function(node)
-    {
-        if (node.attributes && node.attributes.length > 0) {
-            return true; // walk if there are any.
-        }
-        Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this, node);
-        return false;
-     
-    }
-    
-});/**
- * @class Roo.htmleditor.FilterTableWidth
-  try and remove table width data - as that frequently messes up other stuff.
- * 
- *      was cleanTableWidths.
- *
- * Quite often pasting from word etc.. results in tables with column and widths.
- * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
- *
- * @constructor
- * Run a new Table Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterTableWidth = function(cfg)
-{
-    // no need to apply config.
-    this.tag = ['TABLE', 'TD', 'TR', 'TH', 'THEAD', 'TBODY' ];
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterTableWidth, Roo.htmleditor.Filter,
-{
-     
-     
-    
-    replaceTag: function(node) {
-        
-        
-      
-        if (node.hasAttribute('width')) {
-            node.removeAttribute('width');
-        }
-        
-         
-        if (node.hasAttribute("style")) {
-            // pretty basic...
-            
-            var styles = node.getAttribute("style").split(";");
-            var nstyle = [];
-            Roo.each(styles, function(s) {
-                if (!s.match(/:/)) {
-                    return;
-                }
-                var kv = s.split(":");
-                if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
-                    return;
-                }
-                // what ever is left... we allow.
-                nstyle.push(s);
-            });
-            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
-            if (!nstyle.length) {
-                node.removeAttribute('style');
-            }
-        }
-        
-        return true; // continue doing children..
-    }
-});/**
- * @class Roo.htmleditor.FilterWord
- * try and clean up all the mess that Word generates.
- * 
- * This is the 'nice version' - see 'Heavy' that white lists a very short list of elements, and multi-filters 
- * @constructor
- * Run a new Span Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterWord = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterWord, Roo.htmleditor.Filter,
-{
-    tag: true,
-     
-    
-    /**
-     * Clean up MS wordisms...
-     */
-    replaceTag : function(node)
-    {
-         
-        // no idea what this does - span with text, replaceds with just text.
-        if(
-                node.nodeName == 'SPAN' &&
-                !node.hasAttributes() &&
-                node.childNodes.length == 1 &&
-                node.firstChild.nodeName == "#text"  
-        ) {
-            var textNode = node.firstChild;
-            node.removeChild(textNode);
-            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
-                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
-            }
-            node.parentNode.insertBefore(textNode, node);
-            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
-                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
-            }
-            
-            node.parentNode.removeChild(node);
-            return false; // dont do chidren - we have remove our node - so no need to do chdhilren?
-        }
-        
-   
-        
-        if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
-            node.parentNode.removeChild(node);
-            return false; // dont do chidlren
-        }
-        //Roo.log(node.tagName);
-        // remove - but keep children..
-        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
-            //Roo.log('-- removed');
-            while (node.childNodes.length) {
-                var cn = node.childNodes[0];
-                node.removeChild(cn);
-                node.parentNode.insertBefore(cn, node);
-                // move node to parent - and clean it..
-                this.replaceTag(cn);
-            }
-            node.parentNode.removeChild(node);
-            /// no need to iterate chidlren = it's got none..
-            //this.iterateChildren(node, this.cleanWord);
-            return false; // no need to iterate children.
-        }
-        // clean styles
-        if (node.className.length) {
-            
-            var cn = node.className.split(/\W+/);
-            var cna = [];
-            Roo.each(cn, function(cls) {
-                if (cls.match(/Mso[a-zA-Z]+/)) {
-                    return;
-                }
-                cna.push(cls);
-            });
-            node.className = cna.length ? cna.join(' ') : '';
-            if (!cna.length) {
-                node.removeAttribute("class");
-            }
-        }
-        
-        if (node.hasAttribute("lang")) {
-            node.removeAttribute("lang");
-        }
-        
-        if (node.hasAttribute("style")) {
-            
-            var styles = node.getAttribute("style").split(";");
-            var nstyle = [];
-            Roo.each(styles, function(s) {
-                if (!s.match(/:/)) {
-                    return;
-                }
-                var kv = s.split(":");
-                if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
-                    return;
-                }
-                // what ever is left... we allow.
-                nstyle.push(s);
-            });
-            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
-            if (!nstyle.length) {
-                node.removeAttribute('style');
-            }
-        }
-        return true; // do children
-        
-        
-        
-    }
-});
-/**
- * @class Roo.htmleditor.FilterStyleToTag
- * part of the word stuff... - certain 'styles' should be converted to tags.
- * eg.
- *   font-weight: bold -> bold
- *   ?? super / subscrit etc..
- * 
- * @constructor
-* Run a new style to tag filter.
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterStyleToTag = function(cfg)
-{
-    
-    this.tags = {
-        B  : [ 'fontWeight' , 'bold'],
-        I :  [ 'fontStyle' , 'italic'],
-        //pre :  [ 'font-style' , 'italic'],
-        // h1.. h6 ?? font-size?
-        SUP : [ 'verticalAlign' , 'super' ],
-        SUB : [ 'verticalAlign' , 'sub' ]
-        
-        
-    };
-    
-    Roo.apply(this, cfg);
-     
-    
-    this.walk(cfg.node);
-    
-    
-    
-}
-
-
-Roo.extend(Roo.htmleditor.FilterStyleToTag, Roo.htmleditor.Filter,
-{
-    tag: true, // all tags
-    
-    tags : false,
-    
-    
-    replaceTag : function(node)
-    {
-        
-        
-        if (node.getAttribute("style") === null) {
-            return true;
-        }
-        var inject = [];
-        for (var k in this.tags) {
-            if (node.style[this.tags[k][0]] == this.tags[k][1]) {
-                inject.push(k);
-                node.style.removeProperty(this.tags[k][0]);
-            }
-        }
-        if (!inject.length) {
-            return true; 
-        }
-        var cn = Array.from(node.childNodes);
-        var nn = node;
-        Roo.each(inject, function(t) {
-            var nc = node.ownerDocument.createElement(t);
-            nn.appendChild(nc);
-            nn = nc;
-        });
-        for(var i = 0;i < cn.length;cn++) {
-            node.removeChild(cn[i]);
-            nn.appendChild(cn[i]);
-        }
-        return true /// iterate thru
-    }
-    
-})/**
- * @class Roo.htmleditor.FilterLongBr
- * BR/BR/BR - keep a maximum of 2...
- * @constructor
- * Run a new Long BR Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterLongBr = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterLongBr, Roo.htmleditor.Filter,
-{
-    
-     
-    tag : 'BR',
-    
-     
-    replaceTag : function(node)
-    {
-        
-        var ps = node.nextSibling;
-        while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
-            ps = ps.nextSibling;
-        }
-        
-        if (!ps &&  [ 'TD', 'TH', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(node.parentNode.tagName) > -1) { 
-            node.parentNode.removeChild(node); // remove last BR inside one fo these tags
-            return false;
-        }
-        
-        if (!ps || ps.nodeType != 1) {
-            return false;
-        }
-        
-        if (!ps || ps.tagName != 'BR') {
-           
-            return false;
-        }
-        
-        
-        
-        
-        
-        if (!node.previousSibling) {
-            return false;
-        }
-        var ps = node.previousSibling;
-        
-        while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
-            ps = ps.previousSibling;
-        }
-        if (!ps || ps.nodeType != 1) {
-            return false;
-        }
-        // if header or BR before.. then it's a candidate for removal.. - as we only want '2' of these..
-        if (!ps || [ 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(ps.tagName) < 0) {
-            return false;
-        }
-        
-        node.parentNode.removeChild(node); // remove me...
-        
-        return false; // no need to do children
-
-    }
-    
-}); 
-
-/**
- * @class Roo.htmleditor.FilterBlock
- * removes id / data-block and contenteditable that are associated with blocks
- * usage should be done on a cloned copy of the dom
- * @constructor
-* Run a new Attribute Filter { node : xxxx }}
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterBlock = function(cfg)
-{
-    Roo.apply(this, cfg);
-    var qa = cfg.node.querySelectorAll;
-    this.removeAttributes('data-block');
-    this.removeAttributes('contenteditable');
-    this.removeAttributes('id');
-    
-}
-
-Roo.apply(Roo.htmleditor.FilterBlock.prototype,
-{
-    node: true, // all tags
-     
-     
-    removeAttributes : function(attr)
-    {
-        var ar = this.node.querySelectorAll('*[' + attr + ']');
-        for (var i =0;i<ar.length;i++) {
-            ar[i].removeAttribute(attr);
-        }
-    }
-        
-        
-        
-    
-});
-/***
- * This is based loosely on tinymce 
- * @class Roo.htmleditor.TidySerializer
- * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
- * @constructor
- * @method Serializer
- * @param {Object} settings Name/value settings object.
- */
-
-
-Roo.htmleditor.TidySerializer = function(settings)
-{
-    Roo.apply(this, settings);
-    
-    this.writer = new Roo.htmleditor.TidyWriter(settings);
-    
-    
-
-};
-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
-        
-        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)
-{
-    
-    // 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 = {
-
-    state : false,
-    
-    indent :  '  ',
-    
-    // part of state...
-    indentstr : '',
-    in_pre: false,
-    in_inline : false,
-    last_inline : false,
-    encode : false,
-     
-    
-            /**
-    * 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', 'A'
-];
-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..
- * @cfg {Roo.HtmlEditorCore} core the editor.
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-
-
-
-
-Roo.htmleditor.KeyEnter = function(cfg) {
-    Roo.apply(this, cfg);
-    // this does not actually call walk as it's really just a abstract class
-    Roo.get(this.core.doc.body).on('keypress', this.keypress, this);
-}
-
-//Roo.htmleditor.KeyEnter.i = 0;
-
-
-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();
-        // https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
-        var doc = this.core.doc;
-          //add a new line
-       
-    
-        var sel = this.core.getSelection();
-        var range = sel.getRangeAt(0);
-        var n = range.commonAncestorContainer;
-        var pc = range.closest([ 'ol', 'ul']);
-        var pli = range.closest('li');
-        if (!pc || e.ctrlKey) {
-            sel.insertNode('br', 'after'); 
-         
-            this.core.undoManager.addEvent();
-            this.core.fireEditorEvent(e);
-            return false;
-        }
-        
-        // deal with <li> insetion
-        if (pli.innerText.trim() == '' &&
-            pli.previousSibling &&
-            pli.previousSibling.nodeName == 'LI' &&
-            pli.previousSibling.innerText.trim() ==  '') {
-            pli.parentNode.removeChild(pli.previousSibling);
-            sel.cursorAfter(pc);
-            this.core.undoManager.addEvent();
-            this.core.fireEditorEvent(e);
-            return false;
-        }
-    
-        var li = doc.createElement('LI');
-        li.innerHTML = '&nbsp;';
-        if (!pli || !pli.firstSibling) {
-            pc.appendChild(li);
-        } else {
-            pli.parentNode.insertBefore(li, pli.firstSibling);
-        }
-        sel.cursorText (li.firstChild);
-      
-        this.core.undoManager.addEvent();
-        this.core.fireEditorEvent(e);
-
-        return false;
-        
-    
-        
-        
-         
-    }
-};
-     
-/**
- * @class Roo.htmleditor.Block
- * Base class for html editor blocks - do not use it directly .. extend it..
- * @cfg {DomElement} node The node to apply stuff to.
- * @cfg {String} friendly_name the name that appears in the context bar about this block
- * @cfg {Object} Context menu - see Roo.form.HtmlEditor.ToolbarContext
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.Block  = function(cfg)
-{
-    // do nothing .. should not be called really.
-}
-/**
- * factory method to get the block from an element (using cache if necessary)
- * @static
- * @param {HtmlElement} the dom element
- */
-Roo.htmleditor.Block.factory = function(node)
-{
-    var cc = Roo.htmleditor.Block.cache;
-    var id = Roo.get(node).id;
-    if (typeof(cc[id]) != 'undefined' && (!cc[id].node || cc[id].node.closest('body'))) {
-        Roo.htmleditor.Block.cache[id].readElement(node);
-        return Roo.htmleditor.Block.cache[id];
-    }
-    var db  = node.getAttribute('data-block');
-    if (!db) {
-        db = node.nodeName.toLowerCase().toUpperCaseFirst();
-    }
-    var cls = Roo.htmleditor['Block' + db];
-    if (typeof(cls) == 'undefined') {
-        //Roo.log(node.getAttribute('data-block'));
-        Roo.log("OOps missing block : " + 'Block' + db);
-        return false;
-    }
-    Roo.htmleditor.Block.cache[id] = new cls({ node: node });
-    return Roo.htmleditor.Block.cache[id];  /// should trigger update element
-};
-
-/**
- * initalize all Elements from content that are 'blockable'
- * @static
- * @param the body element
- */
-Roo.htmleditor.Block.initAll = function(body, type)
-{
-    if (typeof(type) == 'undefined') {
-        var ia = Roo.htmleditor.Block.initAll;
-        ia(body,'table');
-        ia(body,'td');
-        ia(body,'figure');
-        return;
-    }
-    Roo.each(Roo.get(body).query(type), function(e) {
-        Roo.htmleditor.Block.factory(e);    
-    },this);
-};
-// question goes here... do we need to clear out this cache sometimes?
-// or show we make it relivant to the htmleditor.
-Roo.htmleditor.Block.cache = {};
-
-Roo.htmleditor.Block.prototype = {
-    
-    node : false,
-    
-     // used by context menu
-    friendly_name : 'Based Block',
-    
-    // text for button to delete this element
-    deleteTitle : false,
-    
-    context : false,
-    /**
-     * Update a node with values from this object
-     * @param {DomElement} node
-     */
-    updateElement : function(node)
-    {
-        Roo.DomHelper.update(node === undefined ? this.node : node, this.toObject());
-    },
-     /**
-     * convert to plain HTML for calling insertAtCursor..
-     */
-    toHTML : function()
-    {
-        return Roo.DomHelper.markup(this.toObject());
-    },
-    /**
-     * used by readEleemnt to extract data from a node
-     * may need improving as it's pretty basic
-     
-     * @param {DomElement} node
-     * @param {String} tag - tag to find, eg. IMG ?? might be better to use DomQuery ?
-     * @param {String} attribute (use html - for contents, or style for using next param as style)
-     * @param {String} style the style property - eg. text-align
-     */
-    getVal : function(node, tag, attr, style)
-    {
-        var n = node;
-        if (tag !== true && n.tagName != tag.toUpperCase()) {
-            // in theory we could do figure[3] << 3rd figure? or some more complex search..?
-            // but kiss for now.
-            n = node.getElementsByTagName(tag).item(0);
-        }
-        if (!n) {
-            return '';
-        }
-        if (attr == 'html') {
-            return n.innerHTML;
-        }
-        if (attr == 'style') {
-            return n.style[style]; 
-        }
-        
-        return n.hasAttribute(attr) ? n.getAttribute(attr) : '';
-            
-    },
-    /**
-     * create a DomHelper friendly object - for use with 
-     * Roo.DomHelper.markup / overwrite / etc..
-     * (override this)
-     */
-    toObject : function()
-    {
-        return {};
-    },
-      /**
-     * Read a node that has a 'data-block' property - and extract the values from it.
-     * @param {DomElement} node - the node
-     */
-    readElement : function(node)
-    {
-        
-    } 
-    
-    
-};
-
-
-/**
- * @class Roo.htmleditor.BlockFigure
- * Block that has an image and a figcaption
- * @cfg {String} image_src the url for the image
- * @cfg {String} align (left|right) alignment for the block default left
- * @cfg {String} caption the text to appear below  (and in the alt tag)
- * @cfg {String} caption_display (block|none) display or not the caption
- * @cfg {String|number} image_width the width of the image number or %?
- * @cfg {String|number} image_height the height of the image number or %?
- * 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.BlockFigure = function(cfg)
-{
-    if (cfg.node) {
-        this.readElement(cfg.node);
-        this.updateElement(cfg.node);
-    }
-    Roo.apply(this, cfg);
-}
-Roo.extend(Roo.htmleditor.BlockFigure, Roo.htmleditor.Block, {
-    
-    // setable values.
-    image_src: '',
-    align: 'center',
-    caption : '',
-    caption_display : 'block',
-    width : '100%',
-    cls : '',
-    href: '',
-    video_url : '',
-    
-    // margin: '2%', not used
-    
-    text_align: 'left', //   (left|right) alignment for the text caption default left. - not used at present
-
-    
-    // used by context menu
-    friendly_name : 'Image with caption',
-    deleteTitle : "Delete Image and Caption",
-    
-    contextMenu : function(toolbar)
-    {
-        
-        var block = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
-        };
-        
-        
-        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
-        
-        var syncValue = toolbar.editorcore.syncValue;
-        
-        var fields = {};
-        
-        return [
-             {
-                xtype : 'TextItem',
-                text : "Source: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'Button',
-                text: 'Change Image URL',
-                 
-                listeners : {
-                    click: function (btn, state)
-                    {
-                        var b = block();
-                        
-                        Roo.MessageBox.show({
-                            title : "Image Source URL",
-                            msg : "Enter the url for the image",
-                            buttons: Roo.MessageBox.OKCANCEL,
-                            fn: function(btn, val){
-                                if (btn != 'ok') {
-                                    return;
-                                }
-                                b.image_src = val;
-                                b.updateElement();
-                                syncValue();
-                                toolbar.editorcore.onEditorEvent();
-                            },
-                            minWidth:250,
-                            prompt:true,
-                            //multiline: multiline,
-                            modal : true,
-                            value : b.image_src
-                        });
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-         
-            {
-                xtype : 'Button',
-                text: 'Change Link URL',
-                 
-                listeners : {
-                    click: function (btn, state)
-                    {
-                        var b = block();
-                        
-                        Roo.MessageBox.show({
-                            title : "Link URL",
-                            msg : "Enter the url for the link - leave blank to have no link",
-                            buttons: Roo.MessageBox.OKCANCEL,
-                            fn: function(btn, val){
-                                if (btn != 'ok') {
-                                    return;
-                                }
-                                b.href = val;
-                                b.updateElement();
-                                syncValue();
-                                toolbar.editorcore.onEditorEvent();
-                            },
-                            minWidth:250,
-                            prompt:true,
-                            //multiline: multiline,
-                            modal : true,
-                            value : b.href
-                        });
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: 'Show Video URL',
-                 
-                listeners : {
-                    click: function (btn, state)
-                    {
-                        Roo.MessageBox.alert("Video URL",
-                            block().video_url == '' ? 'This image is not linked ot a video' :
-                                'The image is linked to: <a target="_new" href="' + block().video_url + '">' + block().video_url + '</a>');
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            
-            
-            {
-                xtype : 'TextItem',
-                text : "Width: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 70,
-                name : 'width',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = block();
-                        b.width = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.form,
-                store : {
-                    xtype : 'SimpleStore',
-                    data : [
-                        ['auto'],
-                        ['50%'],
-                        ['100%']
-                    ],
-                    fields : [ 'val'],
-                    xns : Roo.data
-                }
-            },
-            {
-                xtype : 'TextItem',
-                text : "Align: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 70,
-                name : 'align',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = block();
-                        b.align = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.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 (btn, state)
-                    {
-                        var b  = block();
-                        b.caption_display = b.caption_display == 'block' ? 'none' : 'block';
-                        this.setText(b.caption_display == 'block' ? "Hide Caption" : "Show Caption");
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            }
-        ];
-        
-    },
-    /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     */
-    toObject : function()
-    {
-        var d = document.createElement('div');
-        d.innerHTML = this.caption;
-        
-        var m = this.width == '50%' && this.align == 'center' ? '0 auto' : 0; 
-        
-        var img =   {
-            tag : 'img',
-            contenteditable : 'false',
-            src : this.image_src,
-            alt : d.innerText.replace(/\n/g, " ").replace(/\s+/g, ' ').trim(), // removeHTML and reduce spaces..
-            style: {
-                width : 'auto',
-                'max-width': '100%',
-                margin : '0px' 
-                
-                
-            }
-        };
-        /*
-        '<div class="{0}" width="420" height="315" src="{1}" frameborder="0" allowfullscreen>' +
-                    '<a href="{2}">' + 
-                        '<img class="{0}-thumbnail" src="{3}/Images/{4}/{5}#image-{4}" />' + 
-                    '</a>' + 
-                '</div>',
-        */
-                
-        if (this.href.length > 0) {
-            img = {
-                tag : 'a',
-                href: this.href,
-                contenteditable : 'true',
-                cn : [
-                    img
-                ]
-            };
-        }
-        
-        
-        if (this.video_url.length > 0) {
-            img = {
-                tag : 'div',
-                cls : this.cls,
-                frameborder : 0,
-                allowfullscreen : true,
-                width : 420,  // these are for video tricks - that we replace the outer
-                height : 315,
-                src : this.video_url,
-                cn : [
-                    img
-                ]
-            };
-        }
-        
-        var captionhtml = this.caption_display == 'hidden' ? this.caption : (this.caption.length ? this.caption : "Caption");
-        
-        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 : [
-                img,
-              
-                {
-                    tag: 'figcaption',
-                    
-                    style : {
-                        'text-align': 'left',
-                        'margin-top' : '16px',
-                        'font-size' : '16px',
-                        'line-height' : '24px',
-                         display : this.caption_display
-                    },
-                    cls : this.cls.length > 0 ? (this.cls  + '-thumbnail' ) : '',
-                    cn : [
-                        {
-                            // we can not rely on yahoo syndication to use CSS elements - so have to use  '<i>' to encase stuff.
-                            tag : 'i',
-                            contenteditable : true,
-                            html : captionhtml
-                        }
-                    ]
-                    
-                }
-            ]
-        };
-         
-    },
-    
-    readElement : function(node)
-    {
-        // this should not really come from the link...
-        this.video_url = this.getVal(node, 'div', 'src');
-        this.cls = this.getVal(node, 'div', 'class');
-        this.href = this.getVal(node, 'a', 'href');
-        
-        this.image_src = this.getVal(node, 'img', 'src');
-         
-        this.align = this.getVal(node, 'figure', 'align');
-        this.caption = this.getVal(node, 'figcaption', 'html');
-        // remove '<i>
-        if (this.caption.trim().match(/^<i[^>]*>/i)) {
-            this.caption = this.caption.trim().replace(/^<i[^>]*>/i, '').replace(/^<\/i>$/i, '');
-        }
-        //this.text_align = this.getVal(node, 'figcaption', 'style','text-align');
-        this.width = this.getVal(node, 'figure', 'style', 'max-width');
-        //this.margin = this.getVal(node, 'figure', 'style', 'margin');
-        
-    },
-    removeNode : function()
-    {
-        return this.node;
-    }
-    
-  
-   
-     
-    
-    
-    
-    
-})
-
-
-/**
- * @class Roo.htmleditor.BlockTable
- * Block that manages a table
- * 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.BlockTable = function(cfg)
-{
-    if (cfg.node) {
-        this.readElement(cfg.node);
-        this.updateElement(cfg.node);
-    }
-    Roo.apply(this, cfg);
-    if (!cfg.node) {
-        this.rows = [];
-        for(var r = 0; r < this.no_row; r++) {
-            this.rows[r] = [];
-            for(var c = 0; c < this.no_col; c++) {
-                this.rows[r][c] = this.emptyCell();
-            }
-        }
-    }
-    
-    
-}
-Roo.extend(Roo.htmleditor.BlockTable, Roo.htmleditor.Block, {
-    rows : false,
-    no_col : 1,
-    no_row : 1,
-    
-    
-    width: '100%',
-    
-    // used by context menu
-    friendly_name : 'Table',
-    deleteTitle : 'Delete Table',
-    // context menu is drawn once..
-    
-    contextMenu : function(toolbar)
-    {
-        
-        var block = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
-        };
-        
-        
-        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
-        
-        var syncValue = toolbar.editorcore.syncValue;
-        
-        var fields = {};
-        
-        return [
-            {
-                xtype : 'TextItem',
-                text : "Width: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 100,
-                name : 'width',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = block();
-                        b.width = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.form,
-                store : {
-                    xtype : 'SimpleStore',
-                    data : [
-                        ['100%'],
-                        ['auto']
-                    ],
-                    fields : [ 'val'],
-                    xns : Roo.data
-                }
-            },
-            // -------- Cols
-            
-            {
-                xtype : 'TextItem',
-                text : "Columns: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-         
-            {
-                xtype : 'Button',
-                text: '-',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        block().removeColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: '+',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        block().addColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            // -------- ROWS
-            {
-                xtype : 'TextItem',
-                text : "Rows: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-         
-            {
-                xtype : 'Button',
-                text: '-',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        block().removeRow();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: '+',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        block().addRow();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            // -------- ROWS
-            {
-                xtype : 'Button',
-                text: 'Reset Column Widths',
-                listeners : {
-                    
-                    click : function (_self, e)
-                    {
-                        block().resetWidths();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            } 
-            
-            
-            
-        ];
-        
-    },
-    
-    
-  /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     * ?? should it be called with option to hide all editing features?
-     */
-    toObject : function()
-    {
-        
-        var ret = {
-            tag : 'table',
-            contenteditable : 'false', // this stops cell selection from picking the table.
-            'data-block' : 'Table',
-            style : {
-                width:  this.width,
-                border : 'solid 1px #000', // ??? hard coded?
-                'border-collapse' : 'collapse' 
-            },
-            cn : [
-                { tag : 'tbody' , cn : [] }
-            ]
-        };
-        
-        // do we have a head = not really 
-        var ncols = 0;
-        Roo.each(this.rows, function( row ) {
-            var tr = {
-                tag: 'tr',
-                style : {
-                    margin: '6px',
-                    border : 'solid 1px #000',
-                    textAlign : 'left' 
-                },
-                cn : [ ]
-            };
-            
-            ret.cn[0].cn.push(tr);
-            // does the row have any properties? ?? height?
-            var nc = 0;
-            Roo.each(row, function( cell ) {
-                
-                var td = {
-                    tag : 'td',
-                    contenteditable :  'true',
-                    'data-block' : 'Td',
-                    html : cell.html,
-                    style : cell.style
-                };
-                if (cell.colspan > 1) {
-                    td.colspan = cell.colspan ;
-                    nc += cell.colspan;
-                } else {
-                    nc++;
-                }
-                if (cell.rowspan > 1) {
-                    td.rowspan = cell.rowspan ;
-                }
-                
-                
-                // widths ?
-                tr.cn.push(td);
-                    
-                
-            }, this);
-            ncols = Math.max(nc, ncols);
-            
-            
-        }, this);
-        // add the header row..
-        
-        ncols++;
-         
-        
-        return ret;
-         
-    },
-    
-    readElement : function(node)
-    {
-        node  = node ? node : this.node ;
-        this.width = this.getVal(node, true, 'style', 'width') || '100%';
-        
-        this.rows = [];
-        this.no_row = 0;
-        var trs = Array.from(node.rows);
-        trs.forEach(function(tr) {
-            var row =  [];
-            this.rows.push(row);
-            
-            this.no_row++;
-            var no_column = 0;
-            Array.from(tr.cells).forEach(function(td) {
-                
-                var add = {
-                    colspan : td.hasAttribute('colspan') ? td.getAttribute('colspan')*1 : 1,
-                    rowspan : td.hasAttribute('rowspan') ? td.getAttribute('rowspan')*1 : 1,
-                    style : td.hasAttribute('style') ? td.getAttribute('style') : '',
-                    html : td.innerHTML
-                };
-                no_column += add.colspan;
-                     
-                
-                row.push(add);
-                
-                
-            },this);
-            this.no_col = Math.max(this.no_col, no_column);
-            
-            
-        },this);
-        
-        
-    },
-    normalizeRows: function()
-    {
-        var ret= [];
-        var rid = -1;
-        this.rows.forEach(function(row) {
-            rid++;
-            ret[rid] = [];
-            row = this.normalizeRow(row);
-            var cid = 0;
-            row.forEach(function(c) {
-                while (typeof(ret[rid][cid]) != 'undefined') {
-                    cid++;
-                }
-                if (typeof(ret[rid]) == 'undefined') {
-                    ret[rid] = [];
-                }
-                ret[rid][cid] = c;
-                c.row = rid;
-                c.col = cid;
-                if (c.rowspan < 2) {
-                    return;
-                }
-                
-                for(var i = 1 ;i < c.rowspan; i++) {
-                    if (typeof(ret[rid+i]) == 'undefined') {
-                        ret[rid+i] = [];
-                    }
-                    ret[rid+i][cid] = c;
-                }
-            });
-        }, this);
-        return ret;
-    
-    },
-    
-    normalizeRow: function(row)
-    {
-        var ret= [];
-        row.forEach(function(c) {
-            if (c.colspan < 2) {
-                ret.push(c);
-                return;
-            }
-            for(var i =0 ;i < c.colspan; i++) {
-                ret.push(c);
-            }
-        });
-        return ret;
-    
-    },
-    
-    deleteColumn : function(sel)
-    {
-        if (!sel || sel.type != 'col') {
-            return;
-        }
-        if (this.no_col < 2) {
-            return;
-        }
-        
-        this.rows.forEach(function(row) {
-            var cols = this.normalizeRow(row);
-            var col = cols[sel.col];
-            if (col.colspan > 1) {
-                col.colspan --;
-            } else {
-                row.remove(col);
-            }
-            
-        }, this);
-        this.no_col--;
-        
-    },
-    removeColumn : function()
-    {
-        this.deleteColumn({
-            type: 'col',
-            col : this.no_col-1
-        });
-        this.updateElement();
-    },
-    
-     
-    addColumn : function()
-    {
-        
-        this.rows.forEach(function(row) {
-            row.push(this.emptyCell());
-           
-        }, this);
-        this.updateElement();
-    },
-    
-    deleteRow : function(sel)
-    {
-        if (!sel || sel.type != 'row') {
-            return;
-        }
-        
-        if (this.no_row < 2) {
-            return;
-        }
-        
-        var rows = this.normalizeRows();
-        
-        
-        rows[sel.row].forEach(function(col) {
-            if (col.rowspan > 1) {
-                col.rowspan--;
-            } else {
-                col.remove = 1; // flage it as removed.
-            }
-            
-        }, this);
-        var newrows = [];
-        this.rows.forEach(function(row) {
-            newrow = [];
-            row.forEach(function(c) {
-                if (typeof(c.remove) == 'undefined') {
-                    newrow.push(c);
-                }
-                
-            });
-            if (newrow.length > 0) {
-                newrows.push(row);
-            }
-        });
-        this.rows =  newrows;
-        
-        
-        
-        this.no_row--;
-        this.updateElement();
-        
-    },
-    removeRow : function()
-    {
-        this.deleteRow({
-            type: 'row',
-            row : this.no_row-1
-        });
-        
-    },
-    
-     
-    addRow : function()
-    {
-        
-        var row = [];
-        for (var i = 0; i < this.no_col; i++ ) {
-            
-            row.push(this.emptyCell());
-           
-        }
-        this.rows.push(row);
-        this.updateElement();
-        
-    },
-     
-    // the default cell object... at present...
-    emptyCell : function() {
-        return (new Roo.htmleditor.BlockTd({})).toObject();
-        
-     
-    },
-    
-    removeNode : function()
-    {
-        return this.node;
-    },
-    
-    
-    
-    resetWidths : function()
-    {
-        Array.from(this.node.getElementsByTagName('td')).forEach(function(n) {
-            var nn = Roo.htmleditor.Block.factory(n);
-            nn.width = '';
-            nn.updateElement(n);
-        });
-    }
-    
-    
-    
-    
-})
-
-/**
- *
- * editing a TD?
- *
- * since selections really work on the table cell, then editing really should work from there
- *
- * The original plan was to support merging etc... - but that may not be needed yet..
- *
- * So this simple version will support:
- *   add/remove cols
- *   adjust the width +/-
- *   reset the width...
- *   
- *
- */
-
-
-
-/**
- * @class Roo.htmleditor.BlockTable
- * Block that manages a table
- * 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.BlockTd = function(cfg)
-{
-    if (cfg.node) {
-        this.readElement(cfg.node);
-        this.updateElement(cfg.node);
-    }
-    Roo.apply(this, cfg);
-     
-    
-    
-}
-Roo.extend(Roo.htmleditor.BlockTd, Roo.htmleditor.Block, {
-    node : false,
-    
-    width: '',
-    textAlign : 'left',
-    valign : 'top',
-    
-    colspan : 1,
-    rowspan : 1,
-    
-    
-    // used by context menu
-    friendly_name : 'Table Cell',
-    deleteTitle : false, // use our customer delete
-    
-    // context menu is drawn once..
-    
-    contextMenu : function(toolbar)
-    {
-        
-        var cell = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
-        };
-        
-        var table = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode.closest('table'));
-        };
-        
-        var lr = false;
-        var saveSel = function()
-        {
-            lr = toolbar.editorcore.getSelection().getRangeAt(0);
-        }
-        var restoreSel = function()
-        {
-            if (lr) {
-                (function() {
-                    toolbar.editorcore.focus();
-                    var cr = toolbar.editorcore.getSelection();
-                    cr.removeAllRanges();
-                    cr.addRange(lr);
-                    toolbar.editorcore.onEditorEvent();
-                }).defer(10, this);
-                
-                
-            }
-        }
-        
-        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
-        
-        var syncValue = toolbar.editorcore.syncValue;
-        
-        var fields = {};
-        
-        return [
-            {
-                xtype : 'Button',
-                text : 'Edit Table',
-                listeners : {
-                    click : function() {
-                        var t = toolbar.tb.selectedNode.closest('table');
-                        toolbar.editorcore.selectNode(t);
-                        toolbar.editorcore.onEditorEvent();                        
-                    }
-                }
-                
-            },
-              
-           
-             
-            {
-                xtype : 'TextItem',
-                text : "Column Width: ",
-                 xns : rooui.Toolbar 
-               
-            },
-            {
-                xtype : 'Button',
-                text: '-',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().shrinkColumn();
-                        syncValue();
-                         toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: '+',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().growColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            
-            {
-                xtype : 'TextItem',
-                text : "Vertical Align: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 100,
-                name : 'valign',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = cell();
-                        b.valign = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.form,
-                store : {
-                    xtype : 'SimpleStore',
-                    data : [
-                        ['top'],
-                        ['middle'],
-                        ['bottom'] // there are afew more... 
-                    ],
-                    fields : [ 'val'],
-                    xns : Roo.data
-                }
-            },
-            
-            {
-                xtype : 'TextItem',
-                text : "Merge Cells: ",
-                 xns : rooui.Toolbar 
-               
-            },
-            
-            
-            {
-                xtype : 'Button',
-                text: 'Right',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().mergeRight();
-                        //block().growColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-             
-            {
-                xtype : 'Button',
-                text: 'Below',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().mergeBelow();
-                        //block().growColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'TextItem',
-                text : "| ",
-                 xns : rooui.Toolbar 
-               
-            },
-            
-            {
-                xtype : 'Button',
-                text: 'Split',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        //toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().split();
-                        syncValue();
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        toolbar.editorcore.onEditorEvent();
-                                             
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Fill',
-                xns : rooui.Toolbar 
-               
-            },
-        
-          
-            {
-                xtype : 'Button',
-                text: 'Delete',
-                 
-                xns : rooui.Toolbar,
-                menu : {
-                    xtype : 'Menu',
-                    xns : rooui.menu,
-                    items : [
-                        {
-                            xtype : 'Item',
-                            html: 'Column',
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var t = table();
-                                    
-                                    cell().deleteColumn();
-                                    syncValue();
-                                    toolbar.editorcore.selectNode(t.node);
-                                    toolbar.editorcore.onEditorEvent();   
-                                }
-                            },
-                            xns : rooui.menu
-                        },
-                        {
-                            xtype : 'Item',
-                            html: 'Row',
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var t = table();
-                                    cell().deleteRow();
-                                    syncValue();
-                                    
-                                    toolbar.editorcore.selectNode(t.node);
-                                    toolbar.editorcore.onEditorEvent();   
-                                                         
-                                }
-                            },
-                            xns : rooui.menu
-                        },
-                       {
-                            xtype : 'Separator',
-                            xns : rooui.menu
-                        },
-                        {
-                            xtype : 'Item',
-                            html: 'Table',
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var t = table();
-                                    var nn = t.node.nextSibling || t.node.previousSibling;
-                                    t.node.parentNode.removeChild(t.node);
-                                    if (nn) { 
-                                        toolbar.editorcore.selectNode(nn, true);
-                                    }
-                                    toolbar.editorcore.onEditorEvent();   
-                                                         
-                                }
-                            },
-                            xns : rooui.menu
-                        }
-                    ]
-                }
-            }
-            
-            // align... << fixme
-            
-        ];
-        
-    },
-    
-    
-  /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     * ?? should it be called with option to hide all editing features?
-     */
- /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     * ?? should it be called with option to hide all editing features?
-     */
-    toObject : function()
-    {
-        
-        var ret = {
-            tag : 'td',
-            contenteditable : 'true', // this stops cell selection from picking the table.
-            'data-block' : 'Td',
-            valign : this.valign,
-            style : {  
-                'text-align' :  this.textAlign,
-                border : 'solid 1px rgb(0, 0, 0)', // ??? hard coded?
-                'border-collapse' : 'collapse',
-                padding : '6px', // 8 for desktop / 4 for mobile
-                'vertical-align': this.valign
-            },
-            html : this.html
-        };
-        if (this.width != '') {
-            ret.width = this.width;
-            ret.style.width = this.width;
-        }
-        
-        
-        if (this.colspan > 1) {
-            ret.colspan = this.colspan ;
-        } 
-        if (this.rowspan > 1) {
-            ret.rowspan = this.rowspan ;
-        }
-        
-           
-        
-        return ret;
-         
-    },
-    
-    readElement : function(node)
-    {
-        node  = node ? node : this.node ;
-        this.width = node.style.width;
-        this.colspan = Math.max(1,1*node.getAttribute('colspan'));
-        this.rowspan = Math.max(1,1*node.getAttribute('rowspan'));
-        this.html = node.innerHTML;
-        
-        
-    },
-     
-    // the default cell object... at present...
-    emptyCell : function() {
-        return {
-            colspan :  1,
-            rowspan :  1,
-            textAlign : 'left',
-            html : "&nbsp;" // is this going to be editable now?
-        };
-     
-    },
-    
-    removeNode : function()
-    {
-        return this.node.closest('table');
-         
-    },
-    
-    cellData : false,
-    
-    colWidths : false,
-    
-    toTableArray  : function()
-    {
-        var ret = [];
-        var tab = this.node.closest('tr').closest('table');
-        Array.from(tab.rows).forEach(function(r, ri){
-            ret[ri] = [];
-        });
-        var rn = 0;
-        this.colWidths = [];
-        var all_auto = true;
-        Array.from(tab.rows).forEach(function(r, ri){
-            
-            var cn = 0;
-            Array.from(r.cells).forEach(function(ce, ci){
-                var c =  {
-                    cell : ce,
-                    row : rn,
-                    col: cn,
-                    colspan : ce.colSpan,
-                    rowspan : ce.rowSpan
-                };
-                if (ce.isEqualNode(this.node)) {
-                    this.cellData = c;
-                }
-                // if we have been filled up by a row?
-                if (typeof(ret[rn][cn]) != 'undefined') {
-                    while(typeof(ret[rn][cn]) != 'undefined') {
-                        cn++;
-                    }
-                    c.col = cn;
-                }
-                
-                if (typeof(this.colWidths[cn]) == 'undefined') {
-                    this.colWidths[cn] =   ce.style.width;
-                    if (this.colWidths[cn] != '') {
-                        all_auto = false;
-                    }
-                }
-                
-                
-                if (c.colspan < 2 && c.rowspan < 2 ) {
-                    ret[rn][cn] = c;
-                    cn++;
-                    return;
-                }
-                for(var j = 0; j < c.rowspan; j++) {
-                    if (typeof(ret[rn+j]) == 'undefined') {
-                        continue; // we have a problem..
-                    }
-                    ret[rn+j][cn] = c;
-                    for(var i = 0; i < c.colspan; i++) {
-                        ret[rn+j][cn+i] = c;
-                    }
-                }
-                
-                cn += c.colspan;
-            }, this);
-            rn++;
-        }, this);
-        
-        // initalize widths.?
-        // either all widths or no widths..
-        if (all_auto) {
-            this.colWidths[0] = false; // no widths flag.
-        }
-        
-        
-        return ret;
-        
-    },
-    
-    
-    
-    
-    mergeRight: function()
-    {
-         
-        // get the contents of the next cell along..
-        var tr = this.node.closest('tr');
-        var i = Array.prototype.indexOf.call(tr.childNodes, this.node);
-        if (i >= tr.childNodes.length - 1) {
-            return; // no cells on right to merge with.
-        }
-        var table = this.toTableArray();
-        
-        if (typeof(table[this.cellData.row][this.cellData.col+this.cellData.colspan]) == 'undefined') {
-            return; // nothing right?
-        }
-        var rc = table[this.cellData.row][this.cellData.col+this.cellData.colspan];
-        // right cell - must be same rowspan and on the same row.
-        if (rc.rowspan != this.cellData.rowspan || rc.row != this.cellData.row) {
-            return; // right hand side is not same rowspan.
-        }
-        
-        
-        
-        this.node.innerHTML += ' ' + rc.cell.innerHTML;
-        tr.removeChild(rc.cell);
-        this.colspan += rc.colspan;
-        this.node.setAttribute('colspan', this.colspan);
-
-    },
-    
-    
-    mergeBelow : function()
-    {
-        var table = this.toTableArray();
-        if (typeof(table[this.cellData.row+this.cellData.rowspan]) == 'undefined') {
-            return; // no row below
-        }
-        if (typeof(table[this.cellData.row+this.cellData.rowspan][this.cellData.col]) == 'undefined') {
-            return; // nothing right?
-        }
-        var rc = table[this.cellData.row+this.cellData.rowspan][this.cellData.col];
-        
-        if (rc.colspan != this.cellData.colspan || rc.col != this.cellData.col) {
-            return; // right hand side is not same rowspan.
-        }
-        this.node.innerHTML =  this.node.innerHTML + rc.cell.innerHTML ;
-        rc.cell.parentNode.removeChild(rc.cell);
-        this.rowspan += rc.rowspan;
-        this.node.setAttribute('rowspan', this.rowspan);
-    },
-    
-    split: function()
-    {
-        if (this.node.rowSpan < 2 && this.node.colSpan < 2) {
-            return;
-        }
-        var table = this.toTableArray();
-        var cd = this.cellData;
-        this.rowspan = 1;
-        this.colspan = 1;
-        
-        for(var r = cd.row; r < cd.row + cd.rowspan; r++) {
-            
-            
-            
-            for(var c = cd.col; c < cd.col + cd.colspan; c++) {
-                if (r == cd.row && c == cd.col) {
-                    this.node.removeAttribute('rowspan');
-                    this.node.removeAttribute('colspan');
-                    continue;
-                }
-                 
-                var ntd = this.node.cloneNode(); // which col/row should be 0..
-                ntd.removeAttribute('id'); //
-                //ntd.style.width  = '';
-                ntd.innerHTML = '';
-                table[r][c] = { cell : ntd, col : c, row: r , colspan : 1 , rowspan : 1   };
-            }
-            
-        }
-        this.redrawAllCells(table);
-        
-         
-        
-    },
-    
-    
-    
-    redrawAllCells: function(table)
-    {
-        
-         
-        var tab = this.node.closest('tr').closest('table');
-        var ctr = tab.rows[0].parentNode;
-        Array.from(tab.rows).forEach(function(r, ri){
-            
-            Array.from(r.cells).forEach(function(ce, ci){
-                ce.parentNode.removeChild(ce);
-            });
-            r.parentNode.removeChild(r);
-        });
-        for(var r = 0 ; r < table.length; r++) {
-            var re = tab.rows[r];
-            
-            var re = tab.ownerDocument.createElement('tr');
-            ctr.appendChild(re);
-            for(var c = 0 ; c < table[r].length; c++) {
-                if (table[r][c].cell === false) {
-                    continue;
-                }
-                
-                re.appendChild(table[r][c].cell);
-                 
-                table[r][c].cell = false;
-            }
-        }
-        
-    },
-    updateWidths : function(table)
-    {
-        for(var r = 0 ; r < table.length; r++) {
-           
-            for(var c = 0 ; c < table[r].length; c++) {
-                if (table[r][c].cell === false) {
-                    continue;
-                }
-                
-                if (this.colWidths[0] != false && table[r][c].colspan < 2) {
-                    var el = Roo.htmleditor.Block.factory(table[r][c].cell);
-                    el.width = Math.floor(this.colWidths[c])  +'%';
-                    el.updateElement(el.node);
-                }
-                table[r][c].cell = false; // done
-            }
-        }
-    },
-    normalizeWidths : function(table)
-    {
-    
-        if (this.colWidths[0] === false) {
-            var nw = 100.0 / this.colWidths.length;
-            this.colWidths.forEach(function(w,i) {
-                this.colWidths[i] = nw;
-            },this);
-            return;
-        }
-    
-        var t = 0, missing = [];
-        
-        this.colWidths.forEach(function(w,i) {
-            //if you mix % and
-            this.colWidths[i] = this.colWidths[i] == '' ? 0 : (this.colWidths[i]+'').replace(/[^0-9]+/g,'')*1;
-            var add =  this.colWidths[i];
-            if (add > 0) {
-                t+=add;
-                return;
-            }
-            missing.push(i);
-            
-            
-        },this);
-        var nc = this.colWidths.length;
-        if (missing.length) {
-            var mult = (nc - missing.length) / (1.0 * nc);
-            var t = mult * t;
-            var ew = (100 -t) / (1.0 * missing.length);
-            this.colWidths.forEach(function(w,i) {
-                if (w > 0) {
-                    this.colWidths[i] = w * mult;
-                    return;
-                }
-                
-                this.colWidths[i] = ew;
-            }, this);
-            // have to make up numbers..
-             
-        }
-        // now we should have all the widths..
-        
-    
-    },
-    
-    shrinkColumn : function()
-    {
-        var table = this.toTableArray();
-        this.normalizeWidths(table);
-        var col = this.cellData.col;
-        var nw = this.colWidths[col] * 0.8;
-        if (nw < 5) {
-            return;
-        }
-        var otherAdd = (this.colWidths[col]  * 0.2) / (this.colWidths.length -1);
-        this.colWidths.forEach(function(w,i) {
-            if (i == col) {
-                 this.colWidths[i] = nw;
-                return;
-            }
-            this.colWidths[i] += otherAdd
-        }, this);
-        this.updateWidths(table);
-         
-    },
-    growColumn : function()
-    {
-        var table = this.toTableArray();
-        this.normalizeWidths(table);
-        var col = this.cellData.col;
-        var nw = this.colWidths[col] * 1.2;
-        if (nw > 90) {
-            return;
-        }
-        var otherSub = (this.colWidths[col]  * 0.2) / (this.colWidths.length -1);
-        this.colWidths.forEach(function(w,i) {
-            if (i == col) {
-                this.colWidths[i] = nw;
-                return;
-            }
-            this.colWidths[i] -= otherSub
-        }, this);
-        this.updateWidths(table);
-         
-    },
-    deleteRow : function()
-    {
-        // delete this rows 'tr'
-        // if any of the cells in this row have a rowspan > 1 && row!= this row..
-        // then reduce the rowspan.
-        var table = this.toTableArray();
-        // this.cellData.row;
-        for (var i =0;i< table[this.cellData.row].length ; i++) {
-            var c = table[this.cellData.row][i];
-            if (c.row != this.cellData.row) {
-                
-                c.rowspan--;
-                c.cell.setAttribute('rowspan', c.rowspan);
-                continue;
-            }
-            if (c.rowspan > 1) {
-                c.rowspan--;
-                c.cell.setAttribute('rowspan', c.rowspan);
-            }
-        }
-        table.splice(this.cellData.row,1);
-        this.redrawAllCells(table);
-        
-    },
-    deleteColumn : function()
-    {
-        var table = this.toTableArray();
-        
-        for (var i =0;i< table.length ; i++) {
-            var c = table[i][this.cellData.col];
-            if (c.col != this.cellData.col) {
-                table[i][this.cellData.col].colspan--;
-            } else if (c.colspan > 1) {
-                c.colspan--;
-                c.cell.setAttribute('colspan', c.colspan);
-            }
-            table[i].splice(this.cellData.col,1);
-        }
-        
-        this.redrawAllCells(table);
-    }
-    
-    
-    
-    
-})
-
-//<script type="text/javascript">
+});//<script type="text/javascript">
 
 /*
  * Based  Ext JS Library 1.1.1
 
 /*
  * Based  Ext JS Library 1.1.1
index ab5d290..e373443 100644 (file)
@@ -20597,4377 +20597,7 @@ Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
     } 
     
     
     } 
     
     
-});Roo.rtf = {}; // namespace
-Roo.rtf.Hex = function(hex)
-{
-    this.hexstr = hex;
-};
-Roo.rtf.Paragraph = function(opts)
-{
-    this.content = []; ///??? is that used?
-};Roo.rtf.Span = function(opts)
-{
-    this.value = opts.value;
-};
-
-Roo.rtf.Group = function(parent)
-{
-    // we dont want to acutally store parent - it will make debug a nightmare..
-    this.content = [];
-    this.cn  = [];
-     
-       
-    
-};
-
-Roo.rtf.Group.prototype = {
-    ignorable : false,
-    content: false,
-    cn: false,
-    addContent : function(node) {
-        // could set styles...
-        this.content.push(node);
-    },
-    addChild : function(cn)
-    {
-        this.cn.push(cn);
-    },
-    // only for images really...
-    toDataURL : function()
-    {
-        var mimetype = false;
-        switch(true) {
-            case this.content.filter(function(a) { return a.value == 'pngblip' } ).length > 0: 
-                mimetype = "image/png";
-                break;
-             case this.content.filter(function(a) { return a.value == 'jpegblip' } ).length > 0:
-                mimetype = "image/jpeg";
-                break;
-            default :
-                return 'about:blank'; // ?? error?
-        }
-        
-        
-        var hexstring = this.content[this.content.length-1].value;
-        
-        return 'data:' + mimetype + ';base64,' + btoa(hexstring.match(/\w{2}/g).map(function(a) {
-            return String.fromCharCode(parseInt(a, 16));
-        }).join(""));
-    }
-    
-};
-// this looks like it's normally the {rtf{ .... }}
-Roo.rtf.Document = function()
-{
-    // we dont want to acutally store parent - it will make debug a nightmare..
-    this.rtlch  = [];
-    this.content = [];
-    this.cn = [];
-    
-};
-Roo.extend(Roo.rtf.Document, Roo.rtf.Group, { 
-    addChild : function(cn)
-    {
-        this.cn.push(cn);
-        switch(cn.type) {
-            case 'rtlch': // most content seems to be inside this??
-            case 'listtext':
-            case 'shpinst':
-                this.rtlch.push(cn);
-                return;
-            default:
-                this[cn.type] = cn;
-        }
-        
-    },
-    
-    getElementsByType : function(type)
-    {
-        var ret =  [];
-        this._getElementsByType(type, ret, this.cn, 'rtf');
-        return ret;
-    },
-    _getElementsByType : function (type, ret, search_array, path)
-    {
-        search_array.forEach(function(n,i) {
-            if (n.type == type) {
-                n.path = path + '/' + n.type + ':' + i;
-                ret.push(n);
-            }
-            if (n.cn.length > 0) {
-                this._getElementsByType(type, ret, n.cn, path + '/' + n.type+':'+i);
-            }
-        },this);
-    }
-    
-});
-Roo.rtf.Ctrl = function(opts)
-{
-    this.value = opts.value;
-    this.param = opts.param;
-};
-/**
- *
- *
- * based on this https://github.com/iarna/rtf-parser
- * it's really only designed to extract pict from pasted RTF 
- *
- * usage:
- *
- *  var images = new Roo.rtf.Parser().parse(a_string).filter(function(g) { return g.type == 'pict'; });
- *  
- *
- */
-
-
-
-
-Roo.rtf.Parser = function(text) {
-    //super({objectMode: true})
-    this.text = '';
-    this.parserState = this.parseText;
-    
-    // these are for interpeter...
-    this.doc = {};
-    ///this.parserState = this.parseTop
-    this.groupStack = [];
-    this.hexStore = [];
-    this.doc = false;
-    
-    this.groups = []; // where we put the return.
-    
-    for (var ii = 0; ii < text.length; ++ii) {
-        ++this.cpos;
-        
-        if (text[ii] === '\n') {
-            ++this.row;
-            this.col = 1;
-        } else {
-            ++this.col;
-        }
-        this.parserState(text[ii]);
-    }
-    
-    
-    
-};
-Roo.rtf.Parser.prototype = {
-    text : '', // string being parsed..
-    controlWord : '',
-    controlWordParam :  '',
-    hexChar : '',
-    doc : false,
-    group: false,
-    groupStack : false,
-    hexStore : false,
-    
-    
-    cpos : 0, 
-    row : 1, // reportin?
-    col : 1, //
-
-     
-    push : function (el)
-    {
-        var m = 'cmd'+ el.type;
-        if (typeof(this[m]) == 'undefined') {
-            Roo.log('invalid cmd:' + el.type);
-            return;
-        }
-        this[m](el);
-        //Roo.log(el);
-    },
-    flushHexStore : function()
-    {
-        if (this.hexStore.length < 1) {
-            return;
-        }
-        var hexstr = this.hexStore.map(
-            function(cmd) {
-                return cmd.value;
-        }).join('');
-        
-        this.group.addContent( new Roo.rtf.Hex( hexstr ));
-              
-            
-        this.hexStore.splice(0)
-        
-    },
-    
-    cmdgroupstart : function()
-    {
-        this.flushHexStore();
-        if (this.group) {
-            this.groupStack.push(this.group);
-        }
-         // parent..
-        if (this.doc === false) {
-            this.group = this.doc = new Roo.rtf.Document();
-            return;
-            
-        }
-        this.group = new Roo.rtf.Group(this.group);
-    },
-    cmdignorable : function()
-    {
-        this.flushHexStore();
-        this.group.ignorable = true;
-    },
-    cmdendparagraph : function()
-    {
-        this.flushHexStore();
-        this.group.addContent(new Roo.rtf.Paragraph());
-    },
-    cmdgroupend : function ()
-    {
-        this.flushHexStore();
-        var endingGroup = this.group;
-        
-        
-        this.group = this.groupStack.pop();
-        if (this.group) {
-            this.group.addChild(endingGroup);
-        }
-        
-        
-        
-        var doc = this.group || this.doc;
-        //if (endingGroup instanceof FontTable) {
-        //  doc.fonts = endingGroup.table
-        //} else if (endingGroup instanceof ColorTable) {
-        //  doc.colors = endingGroup.table
-        //} else if (endingGroup !== this.doc && !endingGroup.get('ignorable')) {
-        if (endingGroup.ignorable === false) {
-            //code
-            this.groups.push(endingGroup);
-           // Roo.log( endingGroup );
-        }
-            //Roo.each(endingGroup.content, function(item)) {
-            //    doc.addContent(item);
-            //}
-            //process.emit('debug', 'GROUP END', endingGroup.type, endingGroup.get('ignorable'))
-        //}
-    },
-    cmdtext : function (cmd)
-    {
-        this.flushHexStore();
-        if (!this.group) { // an RTF fragment, missing the {\rtf1 header
-            //this.group = this.doc
-        }
-        this.group.addContent(new Roo.rtf.Span(cmd));
-    },
-    cmdcontrolword : function (cmd)
-    {
-        this.flushHexStore();
-        if (!this.group.type) {
-            this.group.type = cmd.value;
-            return;
-        }
-        this.group.addContent(new Roo.rtf.Ctrl(cmd));
-        // we actually don't care about ctrl words...
-        return ;
-        /*
-        var method = 'ctrl$' + cmd.value.replace(/-(.)/g, (_, char) => char.toUpperCase())
-        if (this[method]) {
-            this[method](cmd.param)
-        } else {
-            if (!this.group.get('ignorable')) process.emit('debug', method, cmd.param)
-        }
-        */
-    },
-    cmdhexchar : function(cmd) {
-        this.hexStore.push(cmd);
-    },
-    cmderror : function(cmd) {
-        throw new Exception (cmd.value);
-    },
-    
-    /*
-      _flush (done) {
-        if (this.text !== '\u0000') this.emitText()
-        done()
-      }
-      */
-      
-      
-    parseText : function(c)
-    {
-        if (c === '\\') {
-            this.parserState = this.parseEscapes;
-        } else if (c === '{') {
-            this.emitStartGroup();
-        } else if (c === '}') {
-            this.emitEndGroup();
-        } else if (c === '\x0A' || c === '\x0D') {
-            // cr/lf are noise chars
-        } else {
-            this.text += c;
-        }
-    },
-    
-    parseEscapes: function (c)
-    {
-        if (c === '\\' || c === '{' || c === '}') {
-            this.text += c;
-            this.parserState = this.parseText;
-        } else {
-            this.parserState = this.parseControlSymbol;
-            this.parseControlSymbol(c);
-        }
-    },
-    parseControlSymbol: function(c)
-    {
-        if (c === '~') {
-            this.text += '\u00a0'; // nbsp
-            this.parserState = this.parseText
-        } else if (c === '-') {
-             this.text += '\u00ad'; // soft hyphen
-        } else if (c === '_') {
-            this.text += '\u2011'; // non-breaking hyphen
-        } else if (c === '*') {
-            this.emitIgnorable();
-            this.parserState = this.parseText;
-        } else if (c === "'") {
-            this.parserState = this.parseHexChar;
-        } else if (c === '|') { // formula cacter
-            this.emitFormula();
-            this.parserState = this.parseText;
-        } else if (c === ':') { // subentry in an index entry
-            this.emitIndexSubEntry();
-            this.parserState = this.parseText;
-        } else if (c === '\x0a') {
-            this.emitEndParagraph();
-            this.parserState = this.parseText;
-        } else if (c === '\x0d') {
-            this.emitEndParagraph();
-            this.parserState = this.parseText;
-        } else {
-            this.parserState = this.parseControlWord;
-            this.parseControlWord(c);
-        }
-    },
-    parseHexChar: function (c)
-    {
-        if (/^[A-Fa-f0-9]$/.test(c)) {
-            this.hexChar += c;
-            if (this.hexChar.length >= 2) {
-              this.emitHexChar();
-              this.parserState = this.parseText;
-            }
-            return;
-        }
-        this.emitError("Invalid character \"" + c + "\" in hex literal.");
-        this.parserState = this.parseText;
-        
-    },
-    parseControlWord : function(c)
-    {
-        if (c === ' ') {
-            this.emitControlWord();
-            this.parserState = this.parseText;
-        } else if (/^[-\d]$/.test(c)) {
-            this.parserState = this.parseControlWordParam;
-            this.controlWordParam += c;
-        } else if (/^[A-Za-z]$/.test(c)) {
-          this.controlWord += c;
-        } else {
-          this.emitControlWord();
-          this.parserState = this.parseText;
-          this.parseText(c);
-        }
-    },
-    parseControlWordParam : function (c) {
-        if (/^\d$/.test(c)) {
-          this.controlWordParam += c;
-        } else if (c === ' ') {
-          this.emitControlWord();
-          this.parserState = this.parseText;
-        } else {
-          this.emitControlWord();
-          this.parserState = this.parseText;
-          this.parseText(c);
-        }
-    },
-    
-    
-    
-    
-    emitText : function () {
-        if (this.text === '') {
-            return;
-        }
-        this.push({
-            type: 'text',
-            value: this.text,
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-        this.text = ''
-    },
-    emitControlWord : function ()
-    {
-        this.emitText();
-        if (this.controlWord === '') {
-            this.emitError('empty control word');
-        } else {
-            this.push({
-                  type: 'controlword',
-                  value: this.controlWord,
-                  param: this.controlWordParam !== '' && Number(this.controlWordParam),
-                  pos: this.cpos,
-                  row: this.row,
-                  col: this.col
-            });
-        }
-        this.controlWord = '';
-        this.controlWordParam = '';
-    },
-    emitStartGroup : function ()
-    {
-        this.emitText();
-        this.push({
-            type: 'groupstart',
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-    },
-    emitEndGroup : function ()
-    {
-        this.emitText();
-        this.push({
-            type: 'groupend',
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-    },
-    emitIgnorable : function ()
-    {
-        this.emitText();
-        this.push({
-            type: 'ignorable',
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-    },
-    emitHexChar : function ()
-    {
-        this.emitText();
-        this.push({
-            type: 'hexchar',
-            value: this.hexChar,
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-        this.hexChar = ''
-    },
-    emitError : function (message)
-    {
-      this.emitText();
-      this.push({
-            type: 'error',
-            value: message,
-            row: this.row,
-            col: this.col,
-            char: this.cpos //,
-            //stack: new Error().stack
-        });
-    },
-    emitEndParagraph : function () {
-        this.emitText();
-        this.push({
-            type: 'endparagraph',
-            pos: this.cpos,
-            row: this.row,
-            col: this.col
-        });
-    }
-     
-} ;
-Roo.htmleditor = {};
-/**
- * @class Roo.htmleditor.Filter
- * Base Class for filtering htmleditor stuff. - do not use this directly - extend it.
- * @cfg {DomElement} node The node to iterate and filter
- * @cfg {boolean|String|Array} tag Tags to replace 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-
-
-Roo.htmleditor.Filter = function(cfg) {
-    Roo.apply(this.cfg);
-    // this does not actually call walk as it's really just a abstract class
-}
-
-
-Roo.htmleditor.Filter.prototype = {
-    
-    node: false,
-    
-    tag: false,
-
-    // overrride to do replace comments.
-    replaceComment : false,
-    
-    // overrride to do replace or do stuff with tags..
-    replaceTag : false,
-    
-    walk : function(dom)
-    {
-        Roo.each( Array.from(dom.childNodes), function( e ) {
-            switch(true) {
-                
-                case e.nodeType == 8 &&  this.replaceComment  !== false: // comment
-                    this.replaceComment(e);
-                    return;
-                
-                case e.nodeType != 1: //not a node.
-                    return;
-                
-                case this.tag === true: // everything
-                case typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1: // array and it matches.
-                case typeof(this.tag) == 'string' && this.tag == e.tagName: // array and it matches.
-                    if (this.replaceTag && false === this.replaceTag(e)) {
-                        return;
-                    }
-                    if (e.hasChildNodes()) {
-                        this.walk(e);
-                    }
-                    return;
-                
-                default:    // tags .. that do not match.
-                    if (e.hasChildNodes()) {
-                        this.walk(e);
-                    }
-            }
-            
-        }, this);
-        
-    }
-}; 
-
-/**
- * @class Roo.htmleditor.FilterAttributes
- * clean attributes and  styles including http:// etc.. in attribute
- * @constructor
-* Run a new Attribute Filter
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterAttributes = function(cfg)
-{
-    Roo.apply(this, cfg);
-    this.attrib_black = this.attrib_black || [];
-    this.attrib_white = this.attrib_white || [];
-
-    this.attrib_clean = this.attrib_clean || [];
-    this.style_white = this.style_white || [];
-    this.style_black = this.style_black || [];
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterAttributes, Roo.htmleditor.Filter,
-{
-    tag: true, // all tags
-    
-    attrib_black : false, // array
-    attrib_clean : false,
-    attrib_white : false,
-
-    style_white : false,
-    style_black : false,
-     
-     
-    replaceTag : function(node)
-    {
-        if (!node.attributes || !node.attributes.length) {
-            return true;
-        }
-        
-        for (var i = node.attributes.length-1; i > -1 ; i--) {
-            var a = node.attributes[i];
-            //console.log(a);
-            if (this.attrib_white.length && this.attrib_white.indexOf(a.name.toLowerCase()) < 0) {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            
-            
-            
-            if (a.name.toLowerCase().substr(0,2)=='on')  {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            
-            
-            if (this.attrib_black.indexOf(a.name.toLowerCase()) > -1) {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            if (this.attrib_clean.indexOf(a.name.toLowerCase()) > -1) {
-                this.cleanAttr(node,a.name,a.value); // fixme..
-                continue;
-            }
-            if (a.name == 'style') {
-                this.cleanStyle(node,a.name,a.value);
-                continue;
-            }
-            /// clean up MS crap..
-            // tecnically this should be a list of valid class'es..
-            
-            
-            if (a.name == 'class') {
-                if (a.value.match(/^Mso/)) {
-                    node.removeAttribute('class');
-                }
-                
-                if (a.value.match(/^body$/)) {
-                    node.removeAttribute('class');
-                }
-                continue;
-            }
-            
-            
-            // style cleanup!?
-            // class cleanup?
-            
-        }
-        return true; // clean children
-    },
-        
-    cleanAttr: function(node, n,v)
-    {
-        
-        if (v.match(/^\./) || v.match(/^\//)) {
-            return;
-        }
-        if (v.match(/^(http|https):\/\//)
-            || v.match(/^mailto:/) 
-            || v.match(/^ftp:/)
-            || v.match(/^data:/)
-            ) {
-            return;
-        }
-        if (v.match(/^#/)) {
-            return;
-        }
-        if (v.match(/^\{/)) { // allow template editing.
-            return;
-        }
-//            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
-        node.removeAttribute(n);
-        
-    },
-    cleanStyle : function(node,  n,v)
-    {
-        if (v.match(/expression/)) { //XSS?? should we even bother..
-            node.removeAttribute(n);
-            return;
-        }
-        
-        var parts = v.split(/;/);
-        var clean = [];
-        
-        Roo.each(parts, function(p) {
-            p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
-            if (!p.length) {
-                return true;
-            }
-            var l = p.split(':').shift().replace(/\s+/g,'');
-            l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
-            
-            if ( this.style_black.length && (this.style_black.indexOf(l) > -1 || this.style_black.indexOf(l.toLowerCase()) > -1)) {
-                return true;
-            }
-            //Roo.log()
-            // only allow 'c whitelisted system attributes'
-            if ( this.style_white.length &&  style_white.indexOf(l) < 0 && style_white.indexOf(l.toLowerCase()) < 0 ) {
-                return true;
-            }
-            
-            
-            clean.push(p);
-            return true;
-        },this);
-        if (clean.length) { 
-            node.setAttribute(n, clean.join(';'));
-        } else {
-            node.removeAttribute(n);
-        }
-        
-    }
-        
-        
-        
-    
-});/**
- * @class Roo.htmleditor.FilterBlack
- * remove blacklisted elements.
- * @constructor
- * Run a new Blacklisted Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterBlack = function(cfg)
-{
-    Roo.apply(this, cfg);
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterBlack, Roo.htmleditor.Filter,
-{
-    tag : true, // all elements.
-   
-    replaceTag : function(n)
-    {
-        n.parentNode.removeChild(n);
-    }
-});
-/**
- * @class Roo.htmleditor.FilterComment
- * remove comments.
- * @constructor
-* Run a new Comments Filter
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterComment = function(cfg)
-{
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterComment, Roo.htmleditor.Filter,
-{
-  
-    replaceComment : function(n)
-    {
-        n.parentNode.removeChild(n);
-    }
-});/**
- * @class Roo.htmleditor.FilterKeepChildren
- * remove tags but keep children
- * @constructor
- * Run a new Keep Children Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterKeepChildren = function(cfg)
-{
-    Roo.apply(this, cfg);
-    if (this.tag === false) {
-        return; // dont walk.. (you can use this to use this just to do a child removal on a single tag )
-    }
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterKeepChildren, Roo.htmleditor.FilterBlack,
-{
-    
-  
-    replaceTag : function(node)
-    {
-        // walk children...
-        //Roo.log(node);
-        var ar = Array.from(node.childNodes);
-        //remove first..
-        for (var i = 0; i < ar.length; i++) {
-            if (ar[i].nodeType == 1) {
-                if (
-                    (typeof(this.tag) == 'object' && this.tag.indexOf(ar[i].tagName) > -1)
-                    || // array and it matches
-                    (typeof(this.tag) == 'string' && this.tag == ar[i].tagName)
-                ) {
-                    this.replaceTag(ar[i]); // child is blacklisted as well...
-                    continue;
-                }
-            }
-        }  
-        ar = Array.from(node.childNodes);
-        for (var i = 0; i < ar.length; i++) {
-         
-            node.removeChild(ar[i]);
-            // what if we need to walk these???
-            node.parentNode.insertBefore(ar[i], node);
-            if (this.tag !== false) {
-                this.walk(ar[i]);
-                
-            }
-        }
-        node.parentNode.removeChild(node);
-        return false; // don't walk children
-        
-        
-    }
-});/**
- * @class Roo.htmleditor.FilterParagraph
- * paragraphs cause a nightmare for shared content - this filter is designed to be called ? at various points when editing
- * like on 'push' to remove the <p> tags and replace them with line breaks.
- * @constructor
- * Run a new Paragraph Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterParagraph = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterParagraph, Roo.htmleditor.Filter,
-{
-    
-     
-    tag : 'P',
-    
-     
-    replaceTag : function(node)
-    {
-        
-        if (node.childNodes.length == 1 &&
-            node.childNodes[0].nodeType == 3 &&
-            node.childNodes[0].textContent.trim().length < 1
-            ) {
-            // remove and replace with '<BR>';
-            node.parentNode.replaceChild(node.ownerDocument.createElement('BR'),node);
-            return false; // no need to walk..
-        }
-        var ar = Array.from(node.childNodes);
-        for (var i = 0; i < ar.length; i++) {
-            node.removeChild(ar[i]);
-            // what if we need to walk these???
-            node.parentNode.insertBefore(ar[i], node);
-        }
-        // now what about this?
-        // <p> &nbsp; </p>
-        
-        // double BR.
-        node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
-        node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
-        node.parentNode.removeChild(node);
-        
-        return false;
-
-    }
-    
-});/**
- * @class Roo.htmleditor.FilterSpan
- * filter span's with no attributes out..
- * @constructor
- * Run a new Span Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterSpan = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterSpan, Roo.htmleditor.FilterKeepChildren,
-{
-     
-    tag : 'SPAN',
-     
-    replaceTag : function(node)
-    {
-        if (node.attributes && node.attributes.length > 0) {
-            return true; // walk if there are any.
-        }
-        Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this, node);
-        return false;
-     
-    }
-    
-});/**
- * @class Roo.htmleditor.FilterTableWidth
-  try and remove table width data - as that frequently messes up other stuff.
- * 
- *      was cleanTableWidths.
- *
- * Quite often pasting from word etc.. results in tables with column and widths.
- * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
- *
- * @constructor
- * Run a new Table Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterTableWidth = function(cfg)
-{
-    // no need to apply config.
-    this.tag = ['TABLE', 'TD', 'TR', 'TH', 'THEAD', 'TBODY' ];
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterTableWidth, Roo.htmleditor.Filter,
-{
-     
-     
-    
-    replaceTag: function(node) {
-        
-        
-      
-        if (node.hasAttribute('width')) {
-            node.removeAttribute('width');
-        }
-        
-         
-        if (node.hasAttribute("style")) {
-            // pretty basic...
-            
-            var styles = node.getAttribute("style").split(";");
-            var nstyle = [];
-            Roo.each(styles, function(s) {
-                if (!s.match(/:/)) {
-                    return;
-                }
-                var kv = s.split(":");
-                if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
-                    return;
-                }
-                // what ever is left... we allow.
-                nstyle.push(s);
-            });
-            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
-            if (!nstyle.length) {
-                node.removeAttribute('style');
-            }
-        }
-        
-        return true; // continue doing children..
-    }
-});/**
- * @class Roo.htmleditor.FilterWord
- * try and clean up all the mess that Word generates.
- * 
- * This is the 'nice version' - see 'Heavy' that white lists a very short list of elements, and multi-filters 
- * @constructor
- * Run a new Span Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterWord = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterWord, Roo.htmleditor.Filter,
-{
-    tag: true,
-     
-    
-    /**
-     * Clean up MS wordisms...
-     */
-    replaceTag : function(node)
-    {
-         
-        // no idea what this does - span with text, replaceds with just text.
-        if(
-                node.nodeName == 'SPAN' &&
-                !node.hasAttributes() &&
-                node.childNodes.length == 1 &&
-                node.firstChild.nodeName == "#text"  
-        ) {
-            var textNode = node.firstChild;
-            node.removeChild(textNode);
-            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
-                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
-            }
-            node.parentNode.insertBefore(textNode, node);
-            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
-                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
-            }
-            
-            node.parentNode.removeChild(node);
-            return false; // dont do chidren - we have remove our node - so no need to do chdhilren?
-        }
-        
-   
-        
-        if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
-            node.parentNode.removeChild(node);
-            return false; // dont do chidlren
-        }
-        //Roo.log(node.tagName);
-        // remove - but keep children..
-        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
-            //Roo.log('-- removed');
-            while (node.childNodes.length) {
-                var cn = node.childNodes[0];
-                node.removeChild(cn);
-                node.parentNode.insertBefore(cn, node);
-                // move node to parent - and clean it..
-                this.replaceTag(cn);
-            }
-            node.parentNode.removeChild(node);
-            /// no need to iterate chidlren = it's got none..
-            //this.iterateChildren(node, this.cleanWord);
-            return false; // no need to iterate children.
-        }
-        // clean styles
-        if (node.className.length) {
-            
-            var cn = node.className.split(/\W+/);
-            var cna = [];
-            Roo.each(cn, function(cls) {
-                if (cls.match(/Mso[a-zA-Z]+/)) {
-                    return;
-                }
-                cna.push(cls);
-            });
-            node.className = cna.length ? cna.join(' ') : '';
-            if (!cna.length) {
-                node.removeAttribute("class");
-            }
-        }
-        
-        if (node.hasAttribute("lang")) {
-            node.removeAttribute("lang");
-        }
-        
-        if (node.hasAttribute("style")) {
-            
-            var styles = node.getAttribute("style").split(";");
-            var nstyle = [];
-            Roo.each(styles, function(s) {
-                if (!s.match(/:/)) {
-                    return;
-                }
-                var kv = s.split(":");
-                if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
-                    return;
-                }
-                // what ever is left... we allow.
-                nstyle.push(s);
-            });
-            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
-            if (!nstyle.length) {
-                node.removeAttribute('style');
-            }
-        }
-        return true; // do children
-        
-        
-        
-    }
-});
-/**
- * @class Roo.htmleditor.FilterStyleToTag
- * part of the word stuff... - certain 'styles' should be converted to tags.
- * eg.
- *   font-weight: bold -> bold
- *   ?? super / subscrit etc..
- * 
- * @constructor
-* Run a new style to tag filter.
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterStyleToTag = function(cfg)
-{
-    
-    this.tags = {
-        B  : [ 'fontWeight' , 'bold'],
-        I :  [ 'fontStyle' , 'italic'],
-        //pre :  [ 'font-style' , 'italic'],
-        // h1.. h6 ?? font-size?
-        SUP : [ 'verticalAlign' , 'super' ],
-        SUB : [ 'verticalAlign' , 'sub' ]
-        
-        
-    };
-    
-    Roo.apply(this, cfg);
-     
-    
-    this.walk(cfg.node);
-    
-    
-    
-}
-
-
-Roo.extend(Roo.htmleditor.FilterStyleToTag, Roo.htmleditor.Filter,
-{
-    tag: true, // all tags
-    
-    tags : false,
-    
-    
-    replaceTag : function(node)
-    {
-        
-        
-        if (node.getAttribute("style") === null) {
-            return true;
-        }
-        var inject = [];
-        for (var k in this.tags) {
-            if (node.style[this.tags[k][0]] == this.tags[k][1]) {
-                inject.push(k);
-                node.style.removeProperty(this.tags[k][0]);
-            }
-        }
-        if (!inject.length) {
-            return true; 
-        }
-        var cn = Array.from(node.childNodes);
-        var nn = node;
-        Roo.each(inject, function(t) {
-            var nc = node.ownerDocument.createElement(t);
-            nn.appendChild(nc);
-            nn = nc;
-        });
-        for(var i = 0;i < cn.length;cn++) {
-            node.removeChild(cn[i]);
-            nn.appendChild(cn[i]);
-        }
-        return true /// iterate thru
-    }
-    
-})/**
- * @class Roo.htmleditor.FilterLongBr
- * BR/BR/BR - keep a maximum of 2...
- * @constructor
- * Run a new Long BR Filter
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.FilterLongBr = function(cfg)
-{
-    // no need to apply config.
-    this.walk(cfg.node);
-}
-
-Roo.extend(Roo.htmleditor.FilterLongBr, Roo.htmleditor.Filter,
-{
-    
-     
-    tag : 'BR',
-    
-     
-    replaceTag : function(node)
-    {
-        
-        var ps = node.nextSibling;
-        while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
-            ps = ps.nextSibling;
-        }
-        
-        if (!ps &&  [ 'TD', 'TH', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(node.parentNode.tagName) > -1) { 
-            node.parentNode.removeChild(node); // remove last BR inside one fo these tags
-            return false;
-        }
-        
-        if (!ps || ps.nodeType != 1) {
-            return false;
-        }
-        
-        if (!ps || ps.tagName != 'BR') {
-           
-            return false;
-        }
-        
-        
-        
-        
-        
-        if (!node.previousSibling) {
-            return false;
-        }
-        var ps = node.previousSibling;
-        
-        while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
-            ps = ps.previousSibling;
-        }
-        if (!ps || ps.nodeType != 1) {
-            return false;
-        }
-        // if header or BR before.. then it's a candidate for removal.. - as we only want '2' of these..
-        if (!ps || [ 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(ps.tagName) < 0) {
-            return false;
-        }
-        
-        node.parentNode.removeChild(node); // remove me...
-        
-        return false; // no need to do children
-
-    }
-    
-}); 
-
-/**
- * @class Roo.htmleditor.FilterBlock
- * removes id / data-block and contenteditable that are associated with blocks
- * usage should be done on a cloned copy of the dom
- * @constructor
-* Run a new Attribute Filter { node : xxxx }}
-* @param {Object} config Configuration options
- */
-Roo.htmleditor.FilterBlock = function(cfg)
-{
-    Roo.apply(this, cfg);
-    var qa = cfg.node.querySelectorAll;
-    this.removeAttributes('data-block');
-    this.removeAttributes('contenteditable');
-    this.removeAttributes('id');
-    
-}
-
-Roo.apply(Roo.htmleditor.FilterBlock.prototype,
-{
-    node: true, // all tags
-     
-     
-    removeAttributes : function(attr)
-    {
-        var ar = this.node.querySelectorAll('*[' + attr + ']');
-        for (var i =0;i<ar.length;i++) {
-            ar[i].removeAttribute(attr);
-        }
-    }
-        
-        
-        
-    
-});
-/***
- * This is based loosely on tinymce 
- * @class Roo.htmleditor.TidySerializer
- * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
- * @constructor
- * @method Serializer
- * @param {Object} settings Name/value settings object.
- */
-
-
-Roo.htmleditor.TidySerializer = function(settings)
-{
-    Roo.apply(this, settings);
-    
-    this.writer = new Roo.htmleditor.TidyWriter(settings);
-    
-    
-
-};
-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
-        
-        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)
-{
-    
-    // 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 = {
-
-    state : false,
-    
-    indent :  '  ',
-    
-    // part of state...
-    indentstr : '',
-    in_pre: false,
-    in_inline : false,
-    last_inline : false,
-    encode : false,
-     
-    
-            /**
-    * 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', 'A'
-];
-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..
- * @cfg {Roo.HtmlEditorCore} core the editor.
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-
-
-
-
-Roo.htmleditor.KeyEnter = function(cfg) {
-    Roo.apply(this, cfg);
-    // this does not actually call walk as it's really just a abstract class
-    Roo.get(this.core.doc.body).on('keypress', this.keypress, this);
-}
-
-//Roo.htmleditor.KeyEnter.i = 0;
-
-
-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();
-        // https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
-        var doc = this.core.doc;
-          //add a new line
-       
-    
-        var sel = this.core.getSelection();
-        var range = sel.getRangeAt(0);
-        var n = range.commonAncestorContainer;
-        var pc = range.closest([ 'ol', 'ul']);
-        var pli = range.closest('li');
-        if (!pc || e.ctrlKey) {
-            sel.insertNode('br', 'after'); 
-         
-            this.core.undoManager.addEvent();
-            this.core.fireEditorEvent(e);
-            return false;
-        }
-        
-        // deal with <li> insetion
-        if (pli.innerText.trim() == '' &&
-            pli.previousSibling &&
-            pli.previousSibling.nodeName == 'LI' &&
-            pli.previousSibling.innerText.trim() ==  '') {
-            pli.parentNode.removeChild(pli.previousSibling);
-            sel.cursorAfter(pc);
-            this.core.undoManager.addEvent();
-            this.core.fireEditorEvent(e);
-            return false;
-        }
-    
-        var li = doc.createElement('LI');
-        li.innerHTML = '&nbsp;';
-        if (!pli || !pli.firstSibling) {
-            pc.appendChild(li);
-        } else {
-            pli.parentNode.insertBefore(li, pli.firstSibling);
-        }
-        sel.cursorText (li.firstChild);
-      
-        this.core.undoManager.addEvent();
-        this.core.fireEditorEvent(e);
-
-        return false;
-        
-    
-        
-        
-         
-    }
-};
-     
-/**
- * @class Roo.htmleditor.Block
- * Base class for html editor blocks - do not use it directly .. extend it..
- * @cfg {DomElement} node The node to apply stuff to.
- * @cfg {String} friendly_name the name that appears in the context bar about this block
- * @cfg {Object} Context menu - see Roo.form.HtmlEditor.ToolbarContext
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.Block  = function(cfg)
-{
-    // do nothing .. should not be called really.
-}
-/**
- * factory method to get the block from an element (using cache if necessary)
- * @static
- * @param {HtmlElement} the dom element
- */
-Roo.htmleditor.Block.factory = function(node)
-{
-    var cc = Roo.htmleditor.Block.cache;
-    var id = Roo.get(node).id;
-    if (typeof(cc[id]) != 'undefined' && (!cc[id].node || cc[id].node.closest('body'))) {
-        Roo.htmleditor.Block.cache[id].readElement(node);
-        return Roo.htmleditor.Block.cache[id];
-    }
-    var db  = node.getAttribute('data-block');
-    if (!db) {
-        db = node.nodeName.toLowerCase().toUpperCaseFirst();
-    }
-    var cls = Roo.htmleditor['Block' + db];
-    if (typeof(cls) == 'undefined') {
-        //Roo.log(node.getAttribute('data-block'));
-        Roo.log("OOps missing block : " + 'Block' + db);
-        return false;
-    }
-    Roo.htmleditor.Block.cache[id] = new cls({ node: node });
-    return Roo.htmleditor.Block.cache[id];  /// should trigger update element
-};
-
-/**
- * initalize all Elements from content that are 'blockable'
- * @static
- * @param the body element
- */
-Roo.htmleditor.Block.initAll = function(body, type)
-{
-    if (typeof(type) == 'undefined') {
-        var ia = Roo.htmleditor.Block.initAll;
-        ia(body,'table');
-        ia(body,'td');
-        ia(body,'figure');
-        return;
-    }
-    Roo.each(Roo.get(body).query(type), function(e) {
-        Roo.htmleditor.Block.factory(e);    
-    },this);
-};
-// question goes here... do we need to clear out this cache sometimes?
-// or show we make it relivant to the htmleditor.
-Roo.htmleditor.Block.cache = {};
-
-Roo.htmleditor.Block.prototype = {
-    
-    node : false,
-    
-     // used by context menu
-    friendly_name : 'Based Block',
-    
-    // text for button to delete this element
-    deleteTitle : false,
-    
-    context : false,
-    /**
-     * Update a node with values from this object
-     * @param {DomElement} node
-     */
-    updateElement : function(node)
-    {
-        Roo.DomHelper.update(node === undefined ? this.node : node, this.toObject());
-    },
-     /**
-     * convert to plain HTML for calling insertAtCursor..
-     */
-    toHTML : function()
-    {
-        return Roo.DomHelper.markup(this.toObject());
-    },
-    /**
-     * used by readEleemnt to extract data from a node
-     * may need improving as it's pretty basic
-     
-     * @param {DomElement} node
-     * @param {String} tag - tag to find, eg. IMG ?? might be better to use DomQuery ?
-     * @param {String} attribute (use html - for contents, or style for using next param as style)
-     * @param {String} style the style property - eg. text-align
-     */
-    getVal : function(node, tag, attr, style)
-    {
-        var n = node;
-        if (tag !== true && n.tagName != tag.toUpperCase()) {
-            // in theory we could do figure[3] << 3rd figure? or some more complex search..?
-            // but kiss for now.
-            n = node.getElementsByTagName(tag).item(0);
-        }
-        if (!n) {
-            return '';
-        }
-        if (attr == 'html') {
-            return n.innerHTML;
-        }
-        if (attr == 'style') {
-            return n.style[style]; 
-        }
-        
-        return n.hasAttribute(attr) ? n.getAttribute(attr) : '';
-            
-    },
-    /**
-     * create a DomHelper friendly object - for use with 
-     * Roo.DomHelper.markup / overwrite / etc..
-     * (override this)
-     */
-    toObject : function()
-    {
-        return {};
-    },
-      /**
-     * Read a node that has a 'data-block' property - and extract the values from it.
-     * @param {DomElement} node - the node
-     */
-    readElement : function(node)
-    {
-        
-    } 
-    
-    
-};
-
-
-/**
- * @class Roo.htmleditor.BlockFigure
- * Block that has an image and a figcaption
- * @cfg {String} image_src the url for the image
- * @cfg {String} align (left|right) alignment for the block default left
- * @cfg {String} caption the text to appear below  (and in the alt tag)
- * @cfg {String} caption_display (block|none) display or not the caption
- * @cfg {String|number} image_width the width of the image number or %?
- * @cfg {String|number} image_height the height of the image number or %?
- * 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.BlockFigure = function(cfg)
-{
-    if (cfg.node) {
-        this.readElement(cfg.node);
-        this.updateElement(cfg.node);
-    }
-    Roo.apply(this, cfg);
-}
-Roo.extend(Roo.htmleditor.BlockFigure, Roo.htmleditor.Block, {
-    
-    // setable values.
-    image_src: '',
-    align: 'center',
-    caption : '',
-    caption_display : 'block',
-    width : '100%',
-    cls : '',
-    href: '',
-    video_url : '',
-    
-    // margin: '2%', not used
-    
-    text_align: 'left', //   (left|right) alignment for the text caption default left. - not used at present
-
-    
-    // used by context menu
-    friendly_name : 'Image with caption',
-    deleteTitle : "Delete Image and Caption",
-    
-    contextMenu : function(toolbar)
-    {
-        
-        var block = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
-        };
-        
-        
-        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
-        
-        var syncValue = toolbar.editorcore.syncValue;
-        
-        var fields = {};
-        
-        return [
-             {
-                xtype : 'TextItem',
-                text : "Source: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'Button',
-                text: 'Change Image URL',
-                 
-                listeners : {
-                    click: function (btn, state)
-                    {
-                        var b = block();
-                        
-                        Roo.MessageBox.show({
-                            title : "Image Source URL",
-                            msg : "Enter the url for the image",
-                            buttons: Roo.MessageBox.OKCANCEL,
-                            fn: function(btn, val){
-                                if (btn != 'ok') {
-                                    return;
-                                }
-                                b.image_src = val;
-                                b.updateElement();
-                                syncValue();
-                                toolbar.editorcore.onEditorEvent();
-                            },
-                            minWidth:250,
-                            prompt:true,
-                            //multiline: multiline,
-                            modal : true,
-                            value : b.image_src
-                        });
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-         
-            {
-                xtype : 'Button',
-                text: 'Change Link URL',
-                 
-                listeners : {
-                    click: function (btn, state)
-                    {
-                        var b = block();
-                        
-                        Roo.MessageBox.show({
-                            title : "Link URL",
-                            msg : "Enter the url for the link - leave blank to have no link",
-                            buttons: Roo.MessageBox.OKCANCEL,
-                            fn: function(btn, val){
-                                if (btn != 'ok') {
-                                    return;
-                                }
-                                b.href = val;
-                                b.updateElement();
-                                syncValue();
-                                toolbar.editorcore.onEditorEvent();
-                            },
-                            minWidth:250,
-                            prompt:true,
-                            //multiline: multiline,
-                            modal : true,
-                            value : b.href
-                        });
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: 'Show Video URL',
-                 
-                listeners : {
-                    click: function (btn, state)
-                    {
-                        Roo.MessageBox.alert("Video URL",
-                            block().video_url == '' ? 'This image is not linked ot a video' :
-                                'The image is linked to: <a target="_new" href="' + block().video_url + '">' + block().video_url + '</a>');
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            
-            
-            {
-                xtype : 'TextItem',
-                text : "Width: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 70,
-                name : 'width',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = block();
-                        b.width = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.form,
-                store : {
-                    xtype : 'SimpleStore',
-                    data : [
-                        ['auto'],
-                        ['50%'],
-                        ['100%']
-                    ],
-                    fields : [ 'val'],
-                    xns : Roo.data
-                }
-            },
-            {
-                xtype : 'TextItem',
-                text : "Align: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 70,
-                name : 'align',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = block();
-                        b.align = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.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 (btn, state)
-                    {
-                        var b  = block();
-                        b.caption_display = b.caption_display == 'block' ? 'none' : 'block';
-                        this.setText(b.caption_display == 'block' ? "Hide Caption" : "Show Caption");
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            }
-        ];
-        
-    },
-    /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     */
-    toObject : function()
-    {
-        var d = document.createElement('div');
-        d.innerHTML = this.caption;
-        
-        var m = this.width == '50%' && this.align == 'center' ? '0 auto' : 0; 
-        
-        var img =   {
-            tag : 'img',
-            contenteditable : 'false',
-            src : this.image_src,
-            alt : d.innerText.replace(/\n/g, " ").replace(/\s+/g, ' ').trim(), // removeHTML and reduce spaces..
-            style: {
-                width : 'auto',
-                'max-width': '100%',
-                margin : '0px' 
-                
-                
-            }
-        };
-        /*
-        '<div class="{0}" width="420" height="315" src="{1}" frameborder="0" allowfullscreen>' +
-                    '<a href="{2}">' + 
-                        '<img class="{0}-thumbnail" src="{3}/Images/{4}/{5}#image-{4}" />' + 
-                    '</a>' + 
-                '</div>',
-        */
-                
-        if (this.href.length > 0) {
-            img = {
-                tag : 'a',
-                href: this.href,
-                contenteditable : 'true',
-                cn : [
-                    img
-                ]
-            };
-        }
-        
-        
-        if (this.video_url.length > 0) {
-            img = {
-                tag : 'div',
-                cls : this.cls,
-                frameborder : 0,
-                allowfullscreen : true,
-                width : 420,  // these are for video tricks - that we replace the outer
-                height : 315,
-                src : this.video_url,
-                cn : [
-                    img
-                ]
-            };
-        }
-        
-        var captionhtml = this.caption_display == 'hidden' ? this.caption : (this.caption.length ? this.caption : "Caption");
-        
-        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 : [
-                img,
-              
-                {
-                    tag: 'figcaption',
-                    
-                    style : {
-                        'text-align': 'left',
-                        'margin-top' : '16px',
-                        'font-size' : '16px',
-                        'line-height' : '24px',
-                         display : this.caption_display
-                    },
-                    cls : this.cls.length > 0 ? (this.cls  + '-thumbnail' ) : '',
-                    cn : [
-                        {
-                            // we can not rely on yahoo syndication to use CSS elements - so have to use  '<i>' to encase stuff.
-                            tag : 'i',
-                            contenteditable : true,
-                            html : captionhtml
-                        }
-                    ]
-                    
-                }
-            ]
-        };
-         
-    },
-    
-    readElement : function(node)
-    {
-        // this should not really come from the link...
-        this.video_url = this.getVal(node, 'div', 'src');
-        this.cls = this.getVal(node, 'div', 'class');
-        this.href = this.getVal(node, 'a', 'href');
-        
-        this.image_src = this.getVal(node, 'img', 'src');
-         
-        this.align = this.getVal(node, 'figure', 'align');
-        this.caption = this.getVal(node, 'figcaption', 'html');
-        // remove '<i>
-        if (this.caption.trim().match(/^<i[^>]*>/i)) {
-            this.caption = this.caption.trim().replace(/^<i[^>]*>/i, '').replace(/^<\/i>$/i, '');
-        }
-        //this.text_align = this.getVal(node, 'figcaption', 'style','text-align');
-        this.width = this.getVal(node, 'figure', 'style', 'max-width');
-        //this.margin = this.getVal(node, 'figure', 'style', 'margin');
-        
-    },
-    removeNode : function()
-    {
-        return this.node;
-    }
-    
-  
-   
-     
-    
-    
-    
-    
-})
-
-
-/**
- * @class Roo.htmleditor.BlockTable
- * Block that manages a table
- * 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.BlockTable = function(cfg)
-{
-    if (cfg.node) {
-        this.readElement(cfg.node);
-        this.updateElement(cfg.node);
-    }
-    Roo.apply(this, cfg);
-    if (!cfg.node) {
-        this.rows = [];
-        for(var r = 0; r < this.no_row; r++) {
-            this.rows[r] = [];
-            for(var c = 0; c < this.no_col; c++) {
-                this.rows[r][c] = this.emptyCell();
-            }
-        }
-    }
-    
-    
-}
-Roo.extend(Roo.htmleditor.BlockTable, Roo.htmleditor.Block, {
-    rows : false,
-    no_col : 1,
-    no_row : 1,
-    
-    
-    width: '100%',
-    
-    // used by context menu
-    friendly_name : 'Table',
-    deleteTitle : 'Delete Table',
-    // context menu is drawn once..
-    
-    contextMenu : function(toolbar)
-    {
-        
-        var block = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
-        };
-        
-        
-        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
-        
-        var syncValue = toolbar.editorcore.syncValue;
-        
-        var fields = {};
-        
-        return [
-            {
-                xtype : 'TextItem',
-                text : "Width: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 100,
-                name : 'width',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = block();
-                        b.width = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.form,
-                store : {
-                    xtype : 'SimpleStore',
-                    data : [
-                        ['100%'],
-                        ['auto']
-                    ],
-                    fields : [ 'val'],
-                    xns : Roo.data
-                }
-            },
-            // -------- Cols
-            
-            {
-                xtype : 'TextItem',
-                text : "Columns: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-         
-            {
-                xtype : 'Button',
-                text: '-',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        block().removeColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: '+',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        block().addColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            // -------- ROWS
-            {
-                xtype : 'TextItem',
-                text : "Rows: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-         
-            {
-                xtype : 'Button',
-                text: '-',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        block().removeRow();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: '+',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        block().addRow();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            // -------- ROWS
-            {
-                xtype : 'Button',
-                text: 'Reset Column Widths',
-                listeners : {
-                    
-                    click : function (_self, e)
-                    {
-                        block().resetWidths();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            } 
-            
-            
-            
-        ];
-        
-    },
-    
-    
-  /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     * ?? should it be called with option to hide all editing features?
-     */
-    toObject : function()
-    {
-        
-        var ret = {
-            tag : 'table',
-            contenteditable : 'false', // this stops cell selection from picking the table.
-            'data-block' : 'Table',
-            style : {
-                width:  this.width,
-                border : 'solid 1px #000', // ??? hard coded?
-                'border-collapse' : 'collapse' 
-            },
-            cn : [
-                { tag : 'tbody' , cn : [] }
-            ]
-        };
-        
-        // do we have a head = not really 
-        var ncols = 0;
-        Roo.each(this.rows, function( row ) {
-            var tr = {
-                tag: 'tr',
-                style : {
-                    margin: '6px',
-                    border : 'solid 1px #000',
-                    textAlign : 'left' 
-                },
-                cn : [ ]
-            };
-            
-            ret.cn[0].cn.push(tr);
-            // does the row have any properties? ?? height?
-            var nc = 0;
-            Roo.each(row, function( cell ) {
-                
-                var td = {
-                    tag : 'td',
-                    contenteditable :  'true',
-                    'data-block' : 'Td',
-                    html : cell.html,
-                    style : cell.style
-                };
-                if (cell.colspan > 1) {
-                    td.colspan = cell.colspan ;
-                    nc += cell.colspan;
-                } else {
-                    nc++;
-                }
-                if (cell.rowspan > 1) {
-                    td.rowspan = cell.rowspan ;
-                }
-                
-                
-                // widths ?
-                tr.cn.push(td);
-                    
-                
-            }, this);
-            ncols = Math.max(nc, ncols);
-            
-            
-        }, this);
-        // add the header row..
-        
-        ncols++;
-         
-        
-        return ret;
-         
-    },
-    
-    readElement : function(node)
-    {
-        node  = node ? node : this.node ;
-        this.width = this.getVal(node, true, 'style', 'width') || '100%';
-        
-        this.rows = [];
-        this.no_row = 0;
-        var trs = Array.from(node.rows);
-        trs.forEach(function(tr) {
-            var row =  [];
-            this.rows.push(row);
-            
-            this.no_row++;
-            var no_column = 0;
-            Array.from(tr.cells).forEach(function(td) {
-                
-                var add = {
-                    colspan : td.hasAttribute('colspan') ? td.getAttribute('colspan')*1 : 1,
-                    rowspan : td.hasAttribute('rowspan') ? td.getAttribute('rowspan')*1 : 1,
-                    style : td.hasAttribute('style') ? td.getAttribute('style') : '',
-                    html : td.innerHTML
-                };
-                no_column += add.colspan;
-                     
-                
-                row.push(add);
-                
-                
-            },this);
-            this.no_col = Math.max(this.no_col, no_column);
-            
-            
-        },this);
-        
-        
-    },
-    normalizeRows: function()
-    {
-        var ret= [];
-        var rid = -1;
-        this.rows.forEach(function(row) {
-            rid++;
-            ret[rid] = [];
-            row = this.normalizeRow(row);
-            var cid = 0;
-            row.forEach(function(c) {
-                while (typeof(ret[rid][cid]) != 'undefined') {
-                    cid++;
-                }
-                if (typeof(ret[rid]) == 'undefined') {
-                    ret[rid] = [];
-                }
-                ret[rid][cid] = c;
-                c.row = rid;
-                c.col = cid;
-                if (c.rowspan < 2) {
-                    return;
-                }
-                
-                for(var i = 1 ;i < c.rowspan; i++) {
-                    if (typeof(ret[rid+i]) == 'undefined') {
-                        ret[rid+i] = [];
-                    }
-                    ret[rid+i][cid] = c;
-                }
-            });
-        }, this);
-        return ret;
-    
-    },
-    
-    normalizeRow: function(row)
-    {
-        var ret= [];
-        row.forEach(function(c) {
-            if (c.colspan < 2) {
-                ret.push(c);
-                return;
-            }
-            for(var i =0 ;i < c.colspan; i++) {
-                ret.push(c);
-            }
-        });
-        return ret;
-    
-    },
-    
-    deleteColumn : function(sel)
-    {
-        if (!sel || sel.type != 'col') {
-            return;
-        }
-        if (this.no_col < 2) {
-            return;
-        }
-        
-        this.rows.forEach(function(row) {
-            var cols = this.normalizeRow(row);
-            var col = cols[sel.col];
-            if (col.colspan > 1) {
-                col.colspan --;
-            } else {
-                row.remove(col);
-            }
-            
-        }, this);
-        this.no_col--;
-        
-    },
-    removeColumn : function()
-    {
-        this.deleteColumn({
-            type: 'col',
-            col : this.no_col-1
-        });
-        this.updateElement();
-    },
-    
-     
-    addColumn : function()
-    {
-        
-        this.rows.forEach(function(row) {
-            row.push(this.emptyCell());
-           
-        }, this);
-        this.updateElement();
-    },
-    
-    deleteRow : function(sel)
-    {
-        if (!sel || sel.type != 'row') {
-            return;
-        }
-        
-        if (this.no_row < 2) {
-            return;
-        }
-        
-        var rows = this.normalizeRows();
-        
-        
-        rows[sel.row].forEach(function(col) {
-            if (col.rowspan > 1) {
-                col.rowspan--;
-            } else {
-                col.remove = 1; // flage it as removed.
-            }
-            
-        }, this);
-        var newrows = [];
-        this.rows.forEach(function(row) {
-            newrow = [];
-            row.forEach(function(c) {
-                if (typeof(c.remove) == 'undefined') {
-                    newrow.push(c);
-                }
-                
-            });
-            if (newrow.length > 0) {
-                newrows.push(row);
-            }
-        });
-        this.rows =  newrows;
-        
-        
-        
-        this.no_row--;
-        this.updateElement();
-        
-    },
-    removeRow : function()
-    {
-        this.deleteRow({
-            type: 'row',
-            row : this.no_row-1
-        });
-        
-    },
-    
-     
-    addRow : function()
-    {
-        
-        var row = [];
-        for (var i = 0; i < this.no_col; i++ ) {
-            
-            row.push(this.emptyCell());
-           
-        }
-        this.rows.push(row);
-        this.updateElement();
-        
-    },
-     
-    // the default cell object... at present...
-    emptyCell : function() {
-        return (new Roo.htmleditor.BlockTd({})).toObject();
-        
-     
-    },
-    
-    removeNode : function()
-    {
-        return this.node;
-    },
-    
-    
-    
-    resetWidths : function()
-    {
-        Array.from(this.node.getElementsByTagName('td')).forEach(function(n) {
-            var nn = Roo.htmleditor.Block.factory(n);
-            nn.width = '';
-            nn.updateElement(n);
-        });
-    }
-    
-    
-    
-    
-})
-
-/**
- *
- * editing a TD?
- *
- * since selections really work on the table cell, then editing really should work from there
- *
- * The original plan was to support merging etc... - but that may not be needed yet..
- *
- * So this simple version will support:
- *   add/remove cols
- *   adjust the width +/-
- *   reset the width...
- *   
- *
- */
-
-
-
-/**
- * @class Roo.htmleditor.BlockTable
- * Block that manages a table
- * 
- * @constructor
- * Create a new Filter.
- * @param {Object} config Configuration options
- */
-
-Roo.htmleditor.BlockTd = function(cfg)
-{
-    if (cfg.node) {
-        this.readElement(cfg.node);
-        this.updateElement(cfg.node);
-    }
-    Roo.apply(this, cfg);
-     
-    
-    
-}
-Roo.extend(Roo.htmleditor.BlockTd, Roo.htmleditor.Block, {
-    node : false,
-    
-    width: '',
-    textAlign : 'left',
-    valign : 'top',
-    
-    colspan : 1,
-    rowspan : 1,
-    
-    
-    // used by context menu
-    friendly_name : 'Table Cell',
-    deleteTitle : false, // use our customer delete
-    
-    // context menu is drawn once..
-    
-    contextMenu : function(toolbar)
-    {
-        
-        var cell = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
-        };
-        
-        var table = function() {
-            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode.closest('table'));
-        };
-        
-        var lr = false;
-        var saveSel = function()
-        {
-            lr = toolbar.editorcore.getSelection().getRangeAt(0);
-        }
-        var restoreSel = function()
-        {
-            if (lr) {
-                (function() {
-                    toolbar.editorcore.focus();
-                    var cr = toolbar.editorcore.getSelection();
-                    cr.removeAllRanges();
-                    cr.addRange(lr);
-                    toolbar.editorcore.onEditorEvent();
-                }).defer(10, this);
-                
-                
-            }
-        }
-        
-        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
-        
-        var syncValue = toolbar.editorcore.syncValue;
-        
-        var fields = {};
-        
-        return [
-            {
-                xtype : 'Button',
-                text : 'Edit Table',
-                listeners : {
-                    click : function() {
-                        var t = toolbar.tb.selectedNode.closest('table');
-                        toolbar.editorcore.selectNode(t);
-                        toolbar.editorcore.onEditorEvent();                        
-                    }
-                }
-                
-            },
-              
-           
-             
-            {
-                xtype : 'TextItem',
-                text : "Column Width: ",
-                 xns : rooui.Toolbar 
-               
-            },
-            {
-                xtype : 'Button',
-                text: '-',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().shrinkColumn();
-                        syncValue();
-                         toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Button',
-                text: '+',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().growColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            
-            {
-                xtype : 'TextItem',
-                text : "Vertical Align: ",
-                xns : rooui.Toolbar  //Boostrap?
-            },
-            {
-                xtype : 'ComboBox',
-                allowBlank : false,
-                displayField : 'val',
-                editable : true,
-                listWidth : 100,
-                triggerAction : 'all',
-                typeAhead : true,
-                valueField : 'val',
-                width : 100,
-                name : 'valign',
-                listeners : {
-                    select : function (combo, r, index)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        var b = cell();
-                        b.valign = r.get('val');
-                        b.updateElement();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.form,
-                store : {
-                    xtype : 'SimpleStore',
-                    data : [
-                        ['top'],
-                        ['middle'],
-                        ['bottom'] // there are afew more... 
-                    ],
-                    fields : [ 'val'],
-                    xns : Roo.data
-                }
-            },
-            
-            {
-                xtype : 'TextItem',
-                text : "Merge Cells: ",
-                 xns : rooui.Toolbar 
-               
-            },
-            
-            
-            {
-                xtype : 'Button',
-                text: 'Right',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().mergeRight();
-                        //block().growColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-             
-            {
-                xtype : 'Button',
-                text: 'Below',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().mergeBelow();
-                        //block().growColumn();
-                        syncValue();
-                        toolbar.editorcore.onEditorEvent();
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'TextItem',
-                text : "| ",
-                 xns : rooui.Toolbar 
-               
-            },
-            
-            {
-                xtype : 'Button',
-                text: 'Split',
-                listeners : {
-                    click : function (_self, e)
-                    {
-                        //toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        cell().split();
-                        syncValue();
-                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
-                        toolbar.editorcore.onEditorEvent();
-                                             
-                    }
-                },
-                xns : rooui.Toolbar
-            },
-            {
-                xtype : 'Fill',
-                xns : rooui.Toolbar 
-               
-            },
-        
-          
-            {
-                xtype : 'Button',
-                text: 'Delete',
-                 
-                xns : rooui.Toolbar,
-                menu : {
-                    xtype : 'Menu',
-                    xns : rooui.menu,
-                    items : [
-                        {
-                            xtype : 'Item',
-                            html: 'Column',
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var t = table();
-                                    
-                                    cell().deleteColumn();
-                                    syncValue();
-                                    toolbar.editorcore.selectNode(t.node);
-                                    toolbar.editorcore.onEditorEvent();   
-                                }
-                            },
-                            xns : rooui.menu
-                        },
-                        {
-                            xtype : 'Item',
-                            html: 'Row',
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var t = table();
-                                    cell().deleteRow();
-                                    syncValue();
-                                    
-                                    toolbar.editorcore.selectNode(t.node);
-                                    toolbar.editorcore.onEditorEvent();   
-                                                         
-                                }
-                            },
-                            xns : rooui.menu
-                        },
-                       {
-                            xtype : 'Separator',
-                            xns : rooui.menu
-                        },
-                        {
-                            xtype : 'Item',
-                            html: 'Table',
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var t = table();
-                                    var nn = t.node.nextSibling || t.node.previousSibling;
-                                    t.node.parentNode.removeChild(t.node);
-                                    if (nn) { 
-                                        toolbar.editorcore.selectNode(nn, true);
-                                    }
-                                    toolbar.editorcore.onEditorEvent();   
-                                                         
-                                }
-                            },
-                            xns : rooui.menu
-                        }
-                    ]
-                }
-            }
-            
-            // align... << fixme
-            
-        ];
-        
-    },
-    
-    
-  /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     * ?? should it be called with option to hide all editing features?
-     */
- /**
-     * create a DomHelper friendly object - for use with
-     * Roo.DomHelper.markup / overwrite / etc..
-     * ?? should it be called with option to hide all editing features?
-     */
-    toObject : function()
-    {
-        
-        var ret = {
-            tag : 'td',
-            contenteditable : 'true', // this stops cell selection from picking the table.
-            'data-block' : 'Td',
-            valign : this.valign,
-            style : {  
-                'text-align' :  this.textAlign,
-                border : 'solid 1px rgb(0, 0, 0)', // ??? hard coded?
-                'border-collapse' : 'collapse',
-                padding : '6px', // 8 for desktop / 4 for mobile
-                'vertical-align': this.valign
-            },
-            html : this.html
-        };
-        if (this.width != '') {
-            ret.width = this.width;
-            ret.style.width = this.width;
-        }
-        
-        
-        if (this.colspan > 1) {
-            ret.colspan = this.colspan ;
-        } 
-        if (this.rowspan > 1) {
-            ret.rowspan = this.rowspan ;
-        }
-        
-           
-        
-        return ret;
-         
-    },
-    
-    readElement : function(node)
-    {
-        node  = node ? node : this.node ;
-        this.width = node.style.width;
-        this.colspan = Math.max(1,1*node.getAttribute('colspan'));
-        this.rowspan = Math.max(1,1*node.getAttribute('rowspan'));
-        this.html = node.innerHTML;
-        
-        
-    },
-     
-    // the default cell object... at present...
-    emptyCell : function() {
-        return {
-            colspan :  1,
-            rowspan :  1,
-            textAlign : 'left',
-            html : "&nbsp;" // is this going to be editable now?
-        };
-     
-    },
-    
-    removeNode : function()
-    {
-        return this.node.closest('table');
-         
-    },
-    
-    cellData : false,
-    
-    colWidths : false,
-    
-    toTableArray  : function()
-    {
-        var ret = [];
-        var tab = this.node.closest('tr').closest('table');
-        Array.from(tab.rows).forEach(function(r, ri){
-            ret[ri] = [];
-        });
-        var rn = 0;
-        this.colWidths = [];
-        var all_auto = true;
-        Array.from(tab.rows).forEach(function(r, ri){
-            
-            var cn = 0;
-            Array.from(r.cells).forEach(function(ce, ci){
-                var c =  {
-                    cell : ce,
-                    row : rn,
-                    col: cn,
-                    colspan : ce.colSpan,
-                    rowspan : ce.rowSpan
-                };
-                if (ce.isEqualNode(this.node)) {
-                    this.cellData = c;
-                }
-                // if we have been filled up by a row?
-                if (typeof(ret[rn][cn]) != 'undefined') {
-                    while(typeof(ret[rn][cn]) != 'undefined') {
-                        cn++;
-                    }
-                    c.col = cn;
-                }
-                
-                if (typeof(this.colWidths[cn]) == 'undefined') {
-                    this.colWidths[cn] =   ce.style.width;
-                    if (this.colWidths[cn] != '') {
-                        all_auto = false;
-                    }
-                }
-                
-                
-                if (c.colspan < 2 && c.rowspan < 2 ) {
-                    ret[rn][cn] = c;
-                    cn++;
-                    return;
-                }
-                for(var j = 0; j < c.rowspan; j++) {
-                    if (typeof(ret[rn+j]) == 'undefined') {
-                        continue; // we have a problem..
-                    }
-                    ret[rn+j][cn] = c;
-                    for(var i = 0; i < c.colspan; i++) {
-                        ret[rn+j][cn+i] = c;
-                    }
-                }
-                
-                cn += c.colspan;
-            }, this);
-            rn++;
-        }, this);
-        
-        // initalize widths.?
-        // either all widths or no widths..
-        if (all_auto) {
-            this.colWidths[0] = false; // no widths flag.
-        }
-        
-        
-        return ret;
-        
-    },
-    
-    
-    
-    
-    mergeRight: function()
-    {
-         
-        // get the contents of the next cell along..
-        var tr = this.node.closest('tr');
-        var i = Array.prototype.indexOf.call(tr.childNodes, this.node);
-        if (i >= tr.childNodes.length - 1) {
-            return; // no cells on right to merge with.
-        }
-        var table = this.toTableArray();
-        
-        if (typeof(table[this.cellData.row][this.cellData.col+this.cellData.colspan]) == 'undefined') {
-            return; // nothing right?
-        }
-        var rc = table[this.cellData.row][this.cellData.col+this.cellData.colspan];
-        // right cell - must be same rowspan and on the same row.
-        if (rc.rowspan != this.cellData.rowspan || rc.row != this.cellData.row) {
-            return; // right hand side is not same rowspan.
-        }
-        
-        
-        
-        this.node.innerHTML += ' ' + rc.cell.innerHTML;
-        tr.removeChild(rc.cell);
-        this.colspan += rc.colspan;
-        this.node.setAttribute('colspan', this.colspan);
-
-    },
-    
-    
-    mergeBelow : function()
-    {
-        var table = this.toTableArray();
-        if (typeof(table[this.cellData.row+this.cellData.rowspan]) == 'undefined') {
-            return; // no row below
-        }
-        if (typeof(table[this.cellData.row+this.cellData.rowspan][this.cellData.col]) == 'undefined') {
-            return; // nothing right?
-        }
-        var rc = table[this.cellData.row+this.cellData.rowspan][this.cellData.col];
-        
-        if (rc.colspan != this.cellData.colspan || rc.col != this.cellData.col) {
-            return; // right hand side is not same rowspan.
-        }
-        this.node.innerHTML =  this.node.innerHTML + rc.cell.innerHTML ;
-        rc.cell.parentNode.removeChild(rc.cell);
-        this.rowspan += rc.rowspan;
-        this.node.setAttribute('rowspan', this.rowspan);
-    },
-    
-    split: function()
-    {
-        if (this.node.rowSpan < 2 && this.node.colSpan < 2) {
-            return;
-        }
-        var table = this.toTableArray();
-        var cd = this.cellData;
-        this.rowspan = 1;
-        this.colspan = 1;
-        
-        for(var r = cd.row; r < cd.row + cd.rowspan; r++) {
-            
-            
-            
-            for(var c = cd.col; c < cd.col + cd.colspan; c++) {
-                if (r == cd.row && c == cd.col) {
-                    this.node.removeAttribute('rowspan');
-                    this.node.removeAttribute('colspan');
-                    continue;
-                }
-                 
-                var ntd = this.node.cloneNode(); // which col/row should be 0..
-                ntd.removeAttribute('id'); //
-                //ntd.style.width  = '';
-                ntd.innerHTML = '';
-                table[r][c] = { cell : ntd, col : c, row: r , colspan : 1 , rowspan : 1   };
-            }
-            
-        }
-        this.redrawAllCells(table);
-        
-         
-        
-    },
-    
-    
-    
-    redrawAllCells: function(table)
-    {
-        
-         
-        var tab = this.node.closest('tr').closest('table');
-        var ctr = tab.rows[0].parentNode;
-        Array.from(tab.rows).forEach(function(r, ri){
-            
-            Array.from(r.cells).forEach(function(ce, ci){
-                ce.parentNode.removeChild(ce);
-            });
-            r.parentNode.removeChild(r);
-        });
-        for(var r = 0 ; r < table.length; r++) {
-            var re = tab.rows[r];
-            
-            var re = tab.ownerDocument.createElement('tr');
-            ctr.appendChild(re);
-            for(var c = 0 ; c < table[r].length; c++) {
-                if (table[r][c].cell === false) {
-                    continue;
-                }
-                
-                re.appendChild(table[r][c].cell);
-                 
-                table[r][c].cell = false;
-            }
-        }
-        
-    },
-    updateWidths : function(table)
-    {
-        for(var r = 0 ; r < table.length; r++) {
-           
-            for(var c = 0 ; c < table[r].length; c++) {
-                if (table[r][c].cell === false) {
-                    continue;
-                }
-                
-                if (this.colWidths[0] != false && table[r][c].colspan < 2) {
-                    var el = Roo.htmleditor.Block.factory(table[r][c].cell);
-                    el.width = Math.floor(this.colWidths[c])  +'%';
-                    el.updateElement(el.node);
-                }
-                table[r][c].cell = false; // done
-            }
-        }
-    },
-    normalizeWidths : function(table)
-    {
-    
-        if (this.colWidths[0] === false) {
-            var nw = 100.0 / this.colWidths.length;
-            this.colWidths.forEach(function(w,i) {
-                this.colWidths[i] = nw;
-            },this);
-            return;
-        }
-    
-        var t = 0, missing = [];
-        
-        this.colWidths.forEach(function(w,i) {
-            //if you mix % and
-            this.colWidths[i] = this.colWidths[i] == '' ? 0 : (this.colWidths[i]+'').replace(/[^0-9]+/g,'')*1;
-            var add =  this.colWidths[i];
-            if (add > 0) {
-                t+=add;
-                return;
-            }
-            missing.push(i);
-            
-            
-        },this);
-        var nc = this.colWidths.length;
-        if (missing.length) {
-            var mult = (nc - missing.length) / (1.0 * nc);
-            var t = mult * t;
-            var ew = (100 -t) / (1.0 * missing.length);
-            this.colWidths.forEach(function(w,i) {
-                if (w > 0) {
-                    this.colWidths[i] = w * mult;
-                    return;
-                }
-                
-                this.colWidths[i] = ew;
-            }, this);
-            // have to make up numbers..
-             
-        }
-        // now we should have all the widths..
-        
-    
-    },
-    
-    shrinkColumn : function()
-    {
-        var table = this.toTableArray();
-        this.normalizeWidths(table);
-        var col = this.cellData.col;
-        var nw = this.colWidths[col] * 0.8;
-        if (nw < 5) {
-            return;
-        }
-        var otherAdd = (this.colWidths[col]  * 0.2) / (this.colWidths.length -1);
-        this.colWidths.forEach(function(w,i) {
-            if (i == col) {
-                 this.colWidths[i] = nw;
-                return;
-            }
-            this.colWidths[i] += otherAdd
-        }, this);
-        this.updateWidths(table);
-         
-    },
-    growColumn : function()
-    {
-        var table = this.toTableArray();
-        this.normalizeWidths(table);
-        var col = this.cellData.col;
-        var nw = this.colWidths[col] * 1.2;
-        if (nw > 90) {
-            return;
-        }
-        var otherSub = (this.colWidths[col]  * 0.2) / (this.colWidths.length -1);
-        this.colWidths.forEach(function(w,i) {
-            if (i == col) {
-                this.colWidths[i] = nw;
-                return;
-            }
-            this.colWidths[i] -= otherSub
-        }, this);
-        this.updateWidths(table);
-         
-    },
-    deleteRow : function()
-    {
-        // delete this rows 'tr'
-        // if any of the cells in this row have a rowspan > 1 && row!= this row..
-        // then reduce the rowspan.
-        var table = this.toTableArray();
-        // this.cellData.row;
-        for (var i =0;i< table[this.cellData.row].length ; i++) {
-            var c = table[this.cellData.row][i];
-            if (c.row != this.cellData.row) {
-                
-                c.rowspan--;
-                c.cell.setAttribute('rowspan', c.rowspan);
-                continue;
-            }
-            if (c.rowspan > 1) {
-                c.rowspan--;
-                c.cell.setAttribute('rowspan', c.rowspan);
-            }
-        }
-        table.splice(this.cellData.row,1);
-        this.redrawAllCells(table);
-        
-    },
-    deleteColumn : function()
-    {
-        var table = this.toTableArray();
-        
-        for (var i =0;i< table.length ; i++) {
-            var c = table[i][this.cellData.col];
-            if (c.col != this.cellData.col) {
-                table[i][this.cellData.col].colspan--;
-            } else if (c.colspan > 1) {
-                c.colspan--;
-                c.cell.setAttribute('colspan', c.colspan);
-            }
-            table[i].splice(this.cellData.col,1);
-        }
-        
-        this.redrawAllCells(table);
-    }
-    
-    
-    
-    
-})
-
-//<script type="text/javascript">
+});//<script type="text/javascript">
 
 /*
  * Based  Ext JS Library 1.1.1
 
 /*
  * Based  Ext JS Library 1.1.1
index fc04b21..b378cc8 100644 (file)
@@ -905,205 +905,6 @@ this.el.on('DOMAttrModified',this.setFromHidden,this);this.el.on('propertychange
 Roo.form.Radio=function(){Roo.form.Radio.superclass.constructor.apply(this,arguments);};Roo.extend(Roo.form.Radio,Roo.form.Checkbox,{inputType:'radio',getGroupValue:function(){return this.el.up('form').child('input[name='+this.el.dom.name+']:checked',true).value;
 },onRender:function(ct,A){Roo.form.Checkbox.superclass.onRender.call(this,ct,A);if(this.inputValue!==undefined){this.el.dom.value=this.inputValue;}this.wrap=this.el.wrap({cls:"x-form-check-wrap"});if(this.boxLabel){this.wrap.createChild({tag:'label',htmlFor:this.el.id,cls:'x-form-cb-label',html:this.boxLabel}
 );}if(this.checked){this.el.dom.checked='checked';}}});
 Roo.form.Radio=function(){Roo.form.Radio.superclass.constructor.apply(this,arguments);};Roo.extend(Roo.form.Radio,Roo.form.Checkbox,{inputType:'radio',getGroupValue:function(){return this.el.up('form').child('input[name='+this.el.dom.name+']:checked',true).value;
 },onRender:function(ct,A){Roo.form.Checkbox.superclass.onRender.call(this,ct,A);if(this.inputValue!==undefined){this.el.dom.value=this.inputValue;}this.wrap=this.el.wrap({cls:"x-form-check-wrap"});if(this.boxLabel){this.wrap.createChild({tag:'label',htmlFor:this.el.id,cls:'x-form-cb-label',html:this.boxLabel}
 );}if(this.checked){this.el.dom.checked='checked';}}});
-// Roo/rtf/namespace.js
-Roo.rtf={};
-// Roo/rtf/Hex.js
-Roo.rtf.Hex=function(A){this.hexstr=A;};
-// Roo/rtf/Paragraph.js
-Roo.rtf.Paragraph=function(A){this.content=[];};
-// Roo/rtf/Span.js
-Roo.rtf.Span=function(A){this.value=A.value;};
-// Roo/rtf/Group.js
-Roo.rtf.Group=function(A){this.content=[];this.cn=[];};Roo.rtf.Group.prototype={ignorable:false,content:false,cn:false,addContent:function(A){this.content.push(A);},addChild:function(cn){this.cn.push(cn);},toDataURL:function(){var A=false;switch(true){case this.content.filter(function(a){return a.value=='pngblip'}
-).length>0:A="image/png";break;case this.content.filter(function(a){return a.value=='jpegblip'}).length>0:A="image/jpeg";break;default:return 'about:blank';}var B=this.content[this.content.length-1].value;return 'data:'+A+';base64,'+btoa(B.match(/\w{2}/g).map(function(a){return String.fromCharCode(parseInt(a,16));
-}).join(""));}};
-// Roo/rtf/Document.js
-Roo.rtf.Document=function(){this.rtlch=[];this.content=[];this.cn=[];};Roo.extend(Roo.rtf.Document,Roo.rtf.Group,{addChild:function(cn){this.cn.push(cn);switch(cn.type){case 'rtlch':case 'listtext':case 'shpinst':this.rtlch.push(cn);return;default:this[cn.type]=cn;
-}},getElementsByType:function(A){var B=[];this._getElementsByType(A,B,this.cn,'rtf');return B;},_getElementsByType:function(A,B,C,D){C.forEach(function(n,i){if(n.type==A){n.path=D+'/'+n.type+':'+i;B.push(n);}if(n.cn.length>0){this._getElementsByType(A,B,n.cn,D+'/'+n.type+':'+i);
-}},this);}});
-// Roo/rtf/Ctrl.js
-Roo.rtf.Ctrl=function(A){this.value=A.value;this.param=A.param;};
-// Roo/rtf/Parser.js
-Roo.rtf.Parser=function(A){this.text='';this.parserState=this.parseText;this.doc={};this.groupStack=[];this.hexStore=[];this.doc=false;this.groups=[];for(var ii=0;ii<A.length;++ii){++this.cpos;if(A[ii]==='\n'){++this.row;this.col=1;}else{++this.col;}this.parserState(A[ii]);
-}};Roo.rtf.Parser.prototype={text:'',controlWord:'',controlWordParam:'',hexChar:'',doc:false,group:false,groupStack:false,hexStore:false,cpos:0,row:1,col:1,push:function(el){var m='cmd'+el.type;if(typeof(this[m])=='undefined'){Roo.log('invalid cmd:'+el.type);
-return;}this[m](el);},flushHexStore:function(){if(this.hexStore.length<1){return;}var A=this.hexStore.map(function(B){return B.value;}).join('');this.group.addContent(new Roo.rtf.Hex(A));this.hexStore.splice(0)},cmdgroupstart:function(){this.flushHexStore();
-if(this.group){this.groupStack.push(this.group);}if(this.doc===false){this.group=this.doc=new Roo.rtf.Document();return;}this.group=new Roo.rtf.Group(this.group);},cmdignorable:function(){this.flushHexStore();this.group.ignorable=true;},cmdendparagraph:function(){this.flushHexStore();
-this.group.addContent(new Roo.rtf.Paragraph());},cmdgroupend:function(){this.flushHexStore();var A=this.group;this.group=this.groupStack.pop();if(this.group){this.group.addChild(A);}var B=this.group||this.doc;if(A.ignorable===false){this.groups.push(A);}}
-,cmdtext:function(A){this.flushHexStore();if(!this.group){}this.group.addContent(new Roo.rtf.Span(A));},cmdcontrolword:function(A){this.flushHexStore();if(!this.group.type){this.group.type=A.value;return;}this.group.addContent(new Roo.rtf.Ctrl(A));return;
-},cmdhexchar:function(A){this.hexStore.push(A);},cmderror:function(A){throw new Exception(A.value);},parseText:function(c){if(c==='\\'){this.parserState=this.parseEscapes;}else if(c==='{'){this.emitStartGroup();}else if(c==='}'){this.emitEndGroup();}else if(c==='\x0A'||c==='\x0D'){}
-else{this.text+=c;}},parseEscapes:function(c){if(c==='\\'||c==='{'||c==='}'){this.text+=c;this.parserState=this.parseText;}else{this.parserState=this.parseControlSymbol;this.parseControlSymbol(c);}},parseControlSymbol:function(c){if(c==='~'){this.text+='\u00a0';
-this.parserState=this.parseText}else if(c==='-'){this.text+='\u00ad';}else if(c==='_'){this.text+='\u2011';}else if(c==='*'){this.emitIgnorable();this.parserState=this.parseText;}else if(c==="'"){this.parserState=this.parseHexChar;}else if(c==='|'){this.emitFormula();
-this.parserState=this.parseText;}else if(c===':'){this.emitIndexSubEntry();this.parserState=this.parseText;}else if(c==='\x0a'){this.emitEndParagraph();this.parserState=this.parseText;}else if(c==='\x0d'){this.emitEndParagraph();this.parserState=this.parseText;
-}else{this.parserState=this.parseControlWord;this.parseControlWord(c);}},parseHexChar:function(c){if(/^[A-Fa-f0-9]$/.test(c)){this.hexChar+=c;if(this.hexChar.length>=2){this.emitHexChar();this.parserState=this.parseText;}return;}this.emitError("Invalid character \""+c+"\" in hex literal.");
-this.parserState=this.parseText;},parseControlWord:function(c){if(c===' '){this.emitControlWord();this.parserState=this.parseText;}else if(/^[-\d]$/.test(c)){this.parserState=this.parseControlWordParam;this.controlWordParam+=c;}else if(/^[A-Za-z]$/.test(c)){this.controlWord+=c;
-}else{this.emitControlWord();this.parserState=this.parseText;this.parseText(c);}},parseControlWordParam:function(c){if(/^\d$/.test(c)){this.controlWordParam+=c;}else if(c===' '){this.emitControlWord();this.parserState=this.parseText;}else{this.emitControlWord();
-this.parserState=this.parseText;this.parseText(c);}},emitText:function(){if(this.text===''){return;}this.push({type:'text',value:this.text,pos:this.cpos,row:this.row,col:this.col});this.text=''},emitControlWord:function(){this.emitText();if(this.controlWord===''){this.emitError('empty control word');
-}else{this.push({type:'controlword',value:this.controlWord,param:this.controlWordParam!==''&&Number(this.controlWordParam),pos:this.cpos,row:this.row,col:this.col});}this.controlWord='';this.controlWordParam='';},emitStartGroup:function(){this.emitText();
-this.push({type:'groupstart',pos:this.cpos,row:this.row,col:this.col});},emitEndGroup:function(){this.emitText();this.push({type:'groupend',pos:this.cpos,row:this.row,col:this.col});},emitIgnorable:function(){this.emitText();this.push({type:'ignorable',pos:this.cpos,row:this.row,col:this.col}
-);},emitHexChar:function(){this.emitText();this.push({type:'hexchar',value:this.hexChar,pos:this.cpos,row:this.row,col:this.col});this.hexChar=''},emitError:function(A){this.emitText();this.push({type:'error',value:A,row:this.row,col:this.col,char:this.cpos}
-);},emitEndParagraph:function(){this.emitText();this.push({type:'endparagraph',pos:this.cpos,row:this.row,col:this.col});}};
-// Roo/htmleditor/namespace.js
-Roo.htmleditor={};
-// Roo/htmleditor/Filter.js
-Roo.htmleditor.Filter=function(A){Roo.apply(this.cfg);};Roo.htmleditor.Filter.prototype={node:false,tag:false,replaceComment:false,replaceTag:false,walk:function(A){Roo.each(Array.from(A.childNodes),function(e){switch(true){case e.nodeType==8&&this.replaceComment!==false:this.replaceComment(e);
-return;case e.nodeType!=1:return;case this.tag===true:case typeof(this.tag)=='object'&&this.tag.indexOf(e.tagName)>-1:case typeof(this.tag)=='string'&&this.tag==e.tagName:if(this.replaceTag&&false===this.replaceTag(e)){return;}if(e.hasChildNodes()){this.walk(e);
-}return;default:if(e.hasChildNodes()){this.walk(e);}}},this);}};
-// Roo/htmleditor/FilterAttributes.js
-Roo.htmleditor.FilterAttributes=function(A){Roo.apply(this,A);this.attrib_black=this.attrib_black||[];this.attrib_white=this.attrib_white||[];this.attrib_clean=this.attrib_clean||[];this.style_white=this.style_white||[];this.style_black=this.style_black||[];
-this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterAttributes,Roo.htmleditor.Filter,{tag:true,attrib_black:false,attrib_clean:false,attrib_white:false,style_white:false,style_black:false,replaceTag:function(A){if(!A.attributes||!A.attributes.length){return true;
-}for(var i=A.attributes.length-1;i>-1;i--){var a=A.attributes[i];if(this.attrib_white.length&&this.attrib_white.indexOf(a.name.toLowerCase())<0){A.removeAttribute(a.name);continue;}if(a.name.toLowerCase().substr(0,2)=='on'){A.removeAttribute(a.name);continue;
-}if(this.attrib_black.indexOf(a.name.toLowerCase())>-1){A.removeAttribute(a.name);continue;}if(this.attrib_clean.indexOf(a.name.toLowerCase())>-1){this.cleanAttr(A,a.name,a.value);continue;}if(a.name=='style'){this.cleanStyle(A,a.name,a.value);continue;}if(a.name=='class'){if(a.value.match(/^Mso/)){A.removeAttribute('class');
-}if(a.value.match(/^body$/)){A.removeAttribute('class');}continue;}}return true;},cleanAttr:function(A,n,v){if(v.match(/^\./)||v.match(/^\//)){return;}if(v.match(/^(http|https):\/\//)||v.match(/^mailto:/)||v.match(/^ftp:/)||v.match(/^data:/)){return;}if(v.match(/^#/)){return;
-}if(v.match(/^\{/)){return;}A.removeAttribute(n);},cleanStyle:function(A,n,v){if(v.match(/expression/)){A.removeAttribute(n);return;}var B=v.split(/;/);var C=[];Roo.each(B,function(p){p=p.replace(/^\s+/g,'').replace(/\s+$/g,'');if(!p.length){return true;}
-var l=p.split(':').shift().replace(/\s+/g,'');l=l.replace(/^\s+/g,'').replace(/\s+$/g,'');if(this.style_black.length&&(this.style_black.indexOf(l)>-1||this.style_black.indexOf(l.toLowerCase())>-1)){return true;}if(this.style_white.length&&style_white.indexOf(l)<0&&style_white.indexOf(l.toLowerCase())<0){return true;
-}C.push(p);return true;},this);if(C.length){A.setAttribute(n,C.join(';'));}else{A.removeAttribute(n);}}});
-// Roo/htmleditor/FilterBlack.js
-Roo.htmleditor.FilterBlack=function(A){Roo.apply(this,A);this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterBlack,Roo.htmleditor.Filter,{tag:true,replaceTag:function(n){n.parentNode.removeChild(n);}});
-// Roo/htmleditor/FilterComment.js
-Roo.htmleditor.FilterComment=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterComment,Roo.htmleditor.Filter,{replaceComment:function(n){n.parentNode.removeChild(n);}});
-// Roo/htmleditor/FilterKeepChildren.js
-Roo.htmleditor.FilterKeepChildren=function(A){Roo.apply(this,A);if(this.tag===false){return;}this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterKeepChildren,Roo.htmleditor.FilterBlack,{replaceTag:function(A){var ar=Array.from(A.childNodes);for(var i=0;i<ar.length;
-i++){if(ar[i].nodeType==1){if((typeof(this.tag)=='object'&&this.tag.indexOf(ar[i].tagName)>-1)||(typeof(this.tag)=='string'&&this.tag==ar[i].tagName)){this.replaceTag(ar[i]);continue;}}}ar=Array.from(A.childNodes);for(var i=0;i<ar.length;i++){A.removeChild(ar[i]);
-A.parentNode.insertBefore(ar[i],A);if(this.tag!==false){this.walk(ar[i]);}}A.parentNode.removeChild(A);return false;}});
-// Roo/htmleditor/FilterParagraph.js
-Roo.htmleditor.FilterParagraph=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterParagraph,Roo.htmleditor.Filter,{tag:'P',replaceTag:function(A){if(A.childNodes.length==1&&A.childNodes[0].nodeType==3&&A.childNodes[0].textContent.trim().length<1){A.parentNode.replaceChild(A.ownerDocument.createElement('BR'),A);
-return false;}var ar=Array.from(A.childNodes);for(var i=0;i<ar.length;i++){A.removeChild(ar[i]);A.parentNode.insertBefore(ar[i],A);}A.parentNode.insertBefore(A.ownerDocument.createElement('BR'),A);A.parentNode.insertBefore(A.ownerDocument.createElement('BR'),A);
-A.parentNode.removeChild(A);return false;}});
-// Roo/htmleditor/FilterSpan.js
-Roo.htmleditor.FilterSpan=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterSpan,Roo.htmleditor.FilterKeepChildren,{tag:'SPAN',replaceTag:function(A){if(A.attributes&&A.attributes.length>0){return true;}Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this,A);
-return false;}});
-// Roo/htmleditor/FilterTableWidth.js
-Roo.htmleditor.FilterTableWidth=function(A){this.tag=['TABLE','TD','TR','TH','THEAD','TBODY'];this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterTableWidth,Roo.htmleditor.Filter,{replaceTag:function(A){if(A.hasAttribute('width')){A.removeAttribute('width');
-}if(A.hasAttribute("style")){var B=A.getAttribute("style").split(";");var C=[];Roo.each(B,function(s){if(!s.match(/:/)){return;}var kv=s.split(":");if(kv[0].match(/^\s*(width|min-width)\s*$/)){return;}C.push(s);});A.setAttribute("style",C.length?C.join(';'):'');
-if(!C.length){A.removeAttribute('style');}}return true;}});
-// Roo/htmleditor/FilterWord.js
-Roo.htmleditor.FilterWord=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterWord,Roo.htmleditor.Filter,{tag:true,replaceTag:function(A){if(A.nodeName=='SPAN'&&!A.hasAttributes()&&A.childNodes.length==1&&A.firstChild.nodeName=="#text"){var B=A.firstChild;
-A.removeChild(B);if(A.getAttribute('lang')!='zh-CN'){A.parentNode.insertBefore(A.ownerDocument.createTextNode(" "),A);}A.parentNode.insertBefore(B,A);if(A.getAttribute('lang')!='zh-CN'){A.parentNode.insertBefore(A.ownerDocument.createTextNode(" "),A);}A.parentNode.removeChild(A);
-return false;}if(A.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)){A.parentNode.removeChild(A);return false;}if(A.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)){while(A.childNodes.length){var cn=A.childNodes[0];
-A.removeChild(cn);A.parentNode.insertBefore(cn,A);this.replaceTag(cn);}A.parentNode.removeChild(A);return false;}if(A.className.length){var cn=A.className.split(/\W+/);var C=[];Roo.each(cn,function(F){if(F.match(/Mso[a-zA-Z]+/)){return;}C.push(F);});A.className=C.length?C.join(' '):'';
-if(!C.length){A.removeAttribute("class");}}if(A.hasAttribute("lang")){A.removeAttribute("lang");}if(A.hasAttribute("style")){var D=A.getAttribute("style").split(";");var E=[];Roo.each(D,function(s){if(!s.match(/:/)){return;}var kv=s.split(":");if(kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)){return;
-}E.push(s);});A.setAttribute("style",E.length?E.join(';'):'');if(!E.length){A.removeAttribute('style');}}return true;}});
-// Roo/htmleditor/FilterStyleToTag.js
-Roo.htmleditor.FilterStyleToTag=function(A){this.tags={B:['fontWeight','bold'],I:['fontStyle','italic'],SUP:['verticalAlign','super'],SUB:['verticalAlign','sub']};Roo.apply(this,A);this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterStyleToTag,Roo.htmleditor.Filter,{tag:true,tags:false,replaceTag:function(A){if(A.getAttribute("style")===null){return true;
-}var B=[];for(var k in this.tags){if(A.style[this.tags[k][0]]==this.tags[k][1]){B.push(k);A.style.removeProperty(this.tags[k][0]);}}if(!B.length){return true;}var cn=Array.from(A.childNodes);var nn=A;Roo.each(B,function(t){var nc=A.ownerDocument.createElement(t);
-nn.appendChild(nc);nn=nc;});for(var i=0;i<cn.length;cn++){A.removeChild(cn[i]);nn.appendChild(cn[i]);}return true}})
-// Roo/htmleditor/FilterLongBr.js
-Roo.htmleditor.FilterLongBr=function(A){this.walk(A.node);};Roo.extend(Roo.htmleditor.FilterLongBr,Roo.htmleditor.Filter,{tag:'BR',replaceTag:function(A){var ps=A.nextSibling;while(ps&&ps.nodeType==3&&ps.nodeValue.trim().length<1){ps=ps.nextSibling;}if(!ps&&['TD','TH','LI','H1','H2','H3','H4','H5','H6'].indexOf(A.parentNode.tagName)>-1){A.parentNode.removeChild(A);
-return false;}if(!ps||ps.nodeType!=1){return false;}if(!ps||ps.tagName!='BR'){return false;}if(!A.previousSibling){return false;}var ps=A.previousSibling;while(ps&&ps.nodeType==3&&ps.nodeValue.trim().length<1){ps=ps.previousSibling;}if(!ps||ps.nodeType!=1){return false;
-}if(!ps||['BR','H1','H2','H3','H4','H5','H6'].indexOf(ps.tagName)<0){return false;}A.parentNode.removeChild(A);return false;}});
-// 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/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','A'];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();
-this.core.fireEditorEvent(e);return false;}if(D.innerText.trim()==''&&D.previousSibling&&D.previousSibling.nodeName=='LI'&&D.previousSibling.innerText.trim()==''){D.parentNode.removeChild(D.previousSibling);B.cursorAfter(pc);this.core.undoManager.addEvent();
-this.core.fireEditorEvent(e);return false;}var li=A.createElement('LI');li.innerHTML='&nbsp;';if(!D||!D.firstSibling){pc.appendChild(li);}else{D.parentNode.insertBefore(li,D.firstSibling);}B.cursorText(li.firstChild);this.core.undoManager.addEvent();this.core.fireEditorEvent(e);
-return false;}};
-// Roo/htmleditor/Block.js
-Roo.htmleditor.Block=function(A){};Roo.htmleditor.Block.factory=function(A){var cc=Roo.htmleditor.Block.cache;var id=Roo.get(A).id;if(typeof(cc[id])!='undefined'&&(!cc[id].node||cc[id].node.closest('body'))){Roo.htmleditor.Block.cache[id].readElement(A);return Roo.htmleditor.Block.cache[id];
-}var db=A.getAttribute('data-block');if(!db){db=A.nodeName.toLowerCase().toUpperCaseFirst();}var B=Roo.htmleditor['Block'+db];if(typeof(B)=='undefined'){Roo.log("OOps missing block : "+'Block'+db);return false;}Roo.htmleditor.Block.cache[id]=new B({node:A}
-);return Roo.htmleditor.Block.cache[id];};Roo.htmleditor.Block.initAll=function(A,B){if(typeof(B)=='undefined'){var ia=Roo.htmleditor.Block.initAll;ia(A,'table');ia(A,'td');ia(A,'figure');return;}Roo.each(Roo.get(A).query(B),function(e){Roo.htmleditor.Block.factory(e);
-},this);};Roo.htmleditor.Block.cache={};Roo.htmleditor.Block.prototype={node:false,friendly_name:'Based Block',deleteTitle:false,context:false,updateElement:function(A){Roo.DomHelper.update(A===undefined?this.node:A,this.toObject());},toHTML:function(){return Roo.DomHelper.markup(this.toObject());
-},getVal:function(A,B,C,D){var n=A;if(B!==true&&n.tagName!=B.toUpperCase()){n=A.getElementsByTagName(B).item(0);}if(!n){return '';}if(C=='html'){return n.innerHTML;}if(C=='style'){return n.style[D];}return n.hasAttribute(C)?n.getAttribute(C):'';},toObject:function(){return {}
-;},readElement:function(A){}};
-// Roo/htmleditor/BlockFigure.js
-Roo.htmleditor.BlockFigure=function(A){if(A.node){this.readElement(A.node);this.updateElement(A.node);}Roo.apply(this,A);};Roo.extend(Roo.htmleditor.BlockFigure,Roo.htmleditor.Block,{image_src:'',align:'center',caption:'',caption_display:'block',width:'100%',cls:'',href:'',video_url:'',text_align:'left',friendly_name:'Image with caption',deleteTitle:"Delete Image and Caption",contextMenu:function(A){var B=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode);
-};var C=typeof(Roo.bootstrap)=='undefined'?Roo:Roo.bootstrap;var D=A.editorcore.syncValue;var E={};return [{xtype:'TextItem',text:"Source: ",xns:C.Toolbar},{xtype:'Button',text:'Change Image URL',listeners:{click:function(F,G){var b=B();Roo.MessageBox.show({title:"Image Source URL",msg:"Enter the url for the image",buttons:Roo.MessageBox.OKCANCEL,fn:function(H,I){if(H!='ok'){return;
-}b.image_src=I;b.updateElement();D();A.editorcore.onEditorEvent();},minWidth:250,prompt:true,modal:true,value:b.image_src});}},xns:C.Toolbar},{xtype:'Button',text:'Change Link URL',listeners:{click:function(F,G){var b=B();Roo.MessageBox.show({title:"Link URL",msg:"Enter the url for the link - leave blank to have no link",buttons:Roo.MessageBox.OKCANCEL,fn:function(H,I){if(H!='ok'){return;
-}b.href=I;b.updateElement();D();A.editorcore.onEditorEvent();},minWidth:250,prompt:true,modal:true,value:b.href});}},xns:C.Toolbar},{xtype:'Button',text:'Show Video URL',listeners:{click:function(F,G){Roo.MessageBox.alert("Video URL",B().video_url==''?'This image is not linked ot a video':'The image is linked to: <a target="_new" href="'+B().video_url+'">'+B().video_url+'</a>');
-}},xns:C.Toolbar},{xtype:'TextItem',text:"Width: ",xns:C.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:70,name:'width',listeners:{select:function(F,r,G){A.editorcore.selectNode(A.tb.selectedNode);
-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," ").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]};}var B=this.caption_display=='hidden'?this.caption:(this.caption.length?this.caption:"Caption");
-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',style:{'text-align':'left','margin-top':'16px','font-size':'16px','line-height':'24px',display:this.caption_display}
-,cls:this.cls.length>0?(this.cls+'-thumbnail'):'',cn:[{tag:'i',contenteditable:true,html:B}]}]};},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.caption.trim().match(/^<i[^>]*>/i)){this.caption=this.caption.trim().replace(/^<i[^>]*>/i,'').replace(/^<\/i>$/i,'');}this.width=this.getVal(A,'figure','style','max-width');
-},removeNode:function(){return this.node;}})
-// Roo/htmleditor/BlockTable.js
-Roo.htmleditor.BlockTable=function(A){if(A.node){this.readElement(A.node);this.updateElement(A.node);}Roo.apply(this,A);if(!A.node){this.rows=[];for(var r=0;r<this.no_row;r++){this.rows[r]=[];for(var c=0;c<this.no_col;c++){this.rows[r][c]=this.emptyCell();
-}}}};Roo.extend(Roo.htmleditor.BlockTable,Roo.htmleditor.Block,{rows:false,no_col:1,no_row:1,width:'100%',friendly_name:'Table',deleteTitle:'Delete Table',contextMenu:function(A){var B=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode);};var C=typeof(Roo.bootstrap)=='undefined'?Roo:Roo.bootstrap;
-var D=A.editorcore.syncValue;var E={};return [{xtype:'TextItem',text:"Width: ",xns:C.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:100,name:'width',listeners:{select:function(F,r,G){A.editorcore.selectNode(A.tb.selectedNode);
-var b=B();b.width=r.get('val');b.updateElement();D();A.editorcore.onEditorEvent();}},xns:C.form,store:{xtype:'SimpleStore',data:[['100%'],['auto']],fields:['val'],xns:Roo.data}},{xtype:'TextItem',text:"Columns: ",xns:C.Toolbar},{xtype:'Button',text:'-',listeners:{click:function(F,e){A.editorcore.selectNode(A.tb.selectedNode);
-B().removeColumn();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar},{xtype:'Button',text:'+',listeners:{click:function(F,e){A.editorcore.selectNode(A.tb.selectedNode);B().addColumn();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar},{xtype:'TextItem',text:"Rows: ",xns:C.Toolbar}
-,{xtype:'Button',text:'-',listeners:{click:function(F,e){A.editorcore.selectNode(A.tb.selectedNode);B().removeRow();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar},{xtype:'Button',text:'+',listeners:{click:function(F,e){B().addRow();D();A.editorcore.onEditorEvent();
-}},xns:C.Toolbar},{xtype:'Button',text:'Reset Column Widths',listeners:{click:function(F,e){B().resetWidths();D();A.editorcore.onEditorEvent();}},xns:C.Toolbar}];},toObject:function(){var A={tag:'table',contenteditable:'false','data-block':'Table',style:{width:this.width,border:'solid 1px #000','border-collapse':'collapse'}
-,cn:[{tag:'tbody',cn:[]}]};var B=0;Roo.each(this.rows,function(C){var tr={tag:'tr',style:{margin:'6px',border:'solid 1px #000',textAlign:'left'},cn:[]};A.cn[0].cn.push(tr);var nc=0;Roo.each(C,function(D){var td={tag:'td',contenteditable:'true','data-block':'Td',html:D.html,style:D.style}
-;if(D.colspan>1){td.colspan=D.colspan;nc+=D.colspan;}else{nc++;}if(D.rowspan>1){td.rowspan=D.rowspan;}tr.cn.push(td);},this);B=Math.max(nc,B);},this);B++;return A;},readElement:function(A){A=A?A:this.node;this.width=this.getVal(A,true,'style','width')||'100%';
-this.rows=[];this.no_row=0;var B=Array.from(A.rows);B.forEach(function(tr){var C=[];this.rows.push(C);this.no_row++;var D=0;Array.from(tr.cells).forEach(function(td){var E={colspan:td.hasAttribute('colspan')?td.getAttribute('colspan')*1:1,rowspan:td.hasAttribute('rowspan')?td.getAttribute('rowspan')*1:1,style:td.hasAttribute('style')?td.getAttribute('style'):'',html:td.innerHTML}
-;D+=E.colspan;C.push(E);},this);this.no_col=Math.max(this.no_col,D);},this);},normalizeRows:function(){var A=[];var B=-1;this.rows.forEach(function(C){B++;A[B]=[];C=this.normalizeRow(C);var D=0;C.forEach(function(c){while(typeof(A[B][D])!='undefined'){D++;
-}if(typeof(A[B])=='undefined'){A[B]=[];}A[B][D]=c;c.row=B;c.col=D;if(c.rowspan<2){return;}for(var i=1;i<c.rowspan;i++){if(typeof(A[B+i])=='undefined'){A[B+i]=[];}A[B+i][D]=c;}});},this);return A;},normalizeRow:function(A){var B=[];A.forEach(function(c){if(c.colspan<2){B.push(c);
-return;}for(var i=0;i<c.colspan;i++){B.push(c);}});return B;},deleteColumn:function(A){if(!A||A.type!='col'){return;}if(this.no_col<2){return;}this.rows.forEach(function(B){var C=this.normalizeRow(B);var D=C[A.col];if(D.colspan>1){D.colspan--;}else{B.remove(D);
-}},this);this.no_col--;},removeColumn:function(){this.deleteColumn({type:'col',col:this.no_col-1});this.updateElement();},addColumn:function(){this.rows.forEach(function(A){A.push(this.emptyCell());},this);this.updateElement();},deleteRow:function(A){if(!A||A.type!='row'){return;
-}if(this.no_row<2){return;}var B=this.normalizeRows();B[A.row].forEach(function(D){if(D.rowspan>1){D.rowspan--;}else{D.remove=1;}},this);var C=[];this.rows.forEach(function(D){newrow=[];D.forEach(function(c){if(typeof(c.remove)=='undefined'){newrow.push(c);
-}});if(newrow.length>0){C.push(D);}});this.rows=C;this.no_row--;this.updateElement();},removeRow:function(){this.deleteRow({type:'row',row:this.no_row-1});},addRow:function(){var A=[];for(var i=0;i<this.no_col;i++){A.push(this.emptyCell());}this.rows.push(A);
-this.updateElement();},emptyCell:function(){return (new Roo.htmleditor.BlockTd({})).toObject();},removeNode:function(){return this.node;},resetWidths:function(){Array.from(this.node.getElementsByTagName('td')).forEach(function(n){var nn=Roo.htmleditor.Block.factory(n);
-nn.width='';nn.updateElement(n);});}})
-// Roo/htmleditor/BlockTd.js
-Roo.htmleditor.BlockTd=function(A){if(A.node){this.readElement(A.node);this.updateElement(A.node);}Roo.apply(this,A);};Roo.extend(Roo.htmleditor.BlockTd,Roo.htmleditor.Block,{node:false,width:'',textAlign:'left',valign:'top',colspan:1,rowspan:1,friendly_name:'Table Cell',deleteTitle:false,contextMenu:function(A){var B=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode);
-};var C=function(){return Roo.htmleditor.Block.factory(A.tb.selectedNode.closest('table'));};var lr=false;var D=function(){lr=A.editorcore.getSelection().getRangeAt(0);};var restoreSel=function(){if(lr){(function(){A.editorcore.focus();var cr=A.editorcore.getSelection();
-cr.removeAllRanges();cr.addRange(lr);A.editorcore.onEditorEvent();}).defer(10,this);}};var rooui=typeof(Roo.bootstrap)=='undefined'?Roo:Roo.bootstrap;var E=A.editorcore.syncValue;var F={};return [{xtype:'Button',text:'Edit Table',listeners:{click:function(){var t=A.tb.selectedNode.closest('table');
-A.editorcore.selectNode(t);A.editorcore.onEditorEvent();}}},{xtype:'TextItem',text:"Column Width: ",xns:rooui.Toolbar},{xtype:'Button',text:'-',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);B().shrinkColumn();E();A.editorcore.onEditorEvent();
-}},xns:rooui.Toolbar},{xtype:'Button',text:'+',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);B().growColumn();E();A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'TextItem',text:"Vertical Align: ",xns:rooui.Toolbar},{xtype:'ComboBox',allowBlank:false,displayField:'val',editable:true,listWidth:100,triggerAction:'all',typeAhead:true,valueField:'val',width:100,name:'valign',listeners:{select:function(G,r,H){A.editorcore.selectNode(A.tb.selectedNode);
-var b=B();b.valign=r.get('val');b.updateElement();E();A.editorcore.onEditorEvent();}},xns:rooui.form,store:{xtype:'SimpleStore',data:[['top'],['middle'],['bottom']],fields:['val'],xns:Roo.data}},{xtype:'TextItem',text:"Merge Cells: ",xns:rooui.Toolbar},{xtype:'Button',text:'Right',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);
-B().mergeRight();E();A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'Button',text:'Below',listeners:{click:function(G,e){A.editorcore.selectNode(A.tb.selectedNode);B().mergeBelow();E();A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'TextItem',text:"| ",xns:rooui.Toolbar}
-,{xtype:'Button',text:'Split',listeners:{click:function(G,e){B().split();E();A.editorcore.selectNode(A.tb.selectedNode);A.editorcore.onEditorEvent();}},xns:rooui.Toolbar},{xtype:'Fill',xns:rooui.Toolbar},{xtype:'Button',text:'Delete',xns:rooui.Toolbar,menu:{xtype:'Menu',xns:rooui.menu,items:[{xtype:'Item',html:'Column',listeners:{click:function(G,e){var t=C();
-B().deleteColumn();E();A.editorcore.selectNode(t.node);A.editorcore.onEditorEvent();}},xns:rooui.menu},{xtype:'Item',html:'Row',listeners:{click:function(G,e){var t=C();B().deleteRow();E();A.editorcore.selectNode(t.node);A.editorcore.onEditorEvent();}},xns:rooui.menu}
-,{xtype:'Separator',xns:rooui.menu},{xtype:'Item',html:'Table',listeners:{click:function(G,e){var t=C();var nn=t.node.nextSibling||t.node.previousSibling;t.node.parentNode.removeChild(t.node);if(nn){A.editorcore.selectNode(nn,true);}A.editorcore.onEditorEvent();
-}},xns:rooui.menu}]}}];},toObject:function(){var A={tag:'td',contenteditable:'true','data-block':'Td',valign:this.valign,style:{'text-align':this.textAlign,border:'solid 1px rgb(0, 0, 0)','border-collapse':'collapse',padding:'6px','vertical-align':this.valign}
-,html:this.html};if(this.width!=''){A.width=this.width;A.style.width=this.width;}if(this.colspan>1){A.colspan=this.colspan;}if(this.rowspan>1){A.rowspan=this.rowspan;}return A;},readElement:function(A){A=A?A:this.node;this.width=A.style.width;this.colspan=Math.max(1,1*A.getAttribute('colspan'));
-this.rowspan=Math.max(1,1*A.getAttribute('rowspan'));this.html=A.innerHTML;},emptyCell:function(){return {colspan:1,rowspan:1,textAlign:'left',html:"&nbsp;"};},removeNode:function(){return this.node.closest('table');},cellData:false,colWidths:false,toTableArray:function(){var A=[];
-var B=this.node.closest('tr').closest('table');Array.from(B.rows).forEach(function(r,ri){A[ri]=[];});var rn=0;this.colWidths=[];var C=true;Array.from(B.rows).forEach(function(r,ri){var cn=0;Array.from(r.cells).forEach(function(ce,ci){var c={cell:ce,row:rn,col:cn,colspan:ce.colSpan,rowspan:ce.rowSpan}
-;if(ce.isEqualNode(this.node)){this.cellData=c;}if(typeof(A[rn][cn])!='undefined'){while(typeof(A[rn][cn])!='undefined'){cn++;}c.col=cn;}if(typeof(this.colWidths[cn])=='undefined'){this.colWidths[cn]=ce.style.width;if(this.colWidths[cn]!=''){C=false;}}if(c.colspan<2&&c.rowspan<2){A[rn][cn]=c;
-cn++;return;}for(var j=0;j<c.rowspan;j++){if(typeof(A[rn+j])=='undefined'){continue;}A[rn+j][cn]=c;for(var i=0;i<c.colspan;i++){A[rn+j][cn+i]=c;}}cn+=c.colspan;},this);rn++;},this);if(C){this.colWidths[0]=false;}return A;},mergeRight:function(){var tr=this.node.closest('tr');
-var i=Array.prototype.indexOf.call(tr.childNodes,this.node);if(i>=tr.childNodes.length-1){return;}var A=this.toTableArray();if(typeof(A[this.cellData.row][this.cellData.col+this.cellData.colspan])=='undefined'){return;}var rc=A[this.cellData.row][this.cellData.col+this.cellData.colspan];
-if(rc.rowspan!=this.cellData.rowspan||rc.row!=this.cellData.row){return;}this.node.innerHTML+=' '+rc.cell.innerHTML;tr.removeChild(rc.cell);this.colspan+=rc.colspan;this.node.setAttribute('colspan',this.colspan);},mergeBelow:function(){var A=this.toTableArray();
-if(typeof(A[this.cellData.row+this.cellData.rowspan])=='undefined'){return;}if(typeof(A[this.cellData.row+this.cellData.rowspan][this.cellData.col])=='undefined'){return;}var rc=A[this.cellData.row+this.cellData.rowspan][this.cellData.col];if(rc.colspan!=this.cellData.colspan||rc.col!=this.cellData.col){return;
-}this.node.innerHTML=this.node.innerHTML+rc.cell.innerHTML;rc.cell.parentNode.removeChild(rc.cell);this.rowspan+=rc.rowspan;this.node.setAttribute('rowspan',this.rowspan);},split:function(){if(this.node.rowSpan<2&&this.node.colSpan<2){return;}var A=this.toTableArray();
-var cd=this.cellData;this.rowspan=1;this.colspan=1;for(var r=cd.row;r<cd.row+cd.rowspan;r++){for(var c=cd.col;c<cd.col+cd.colspan;c++){if(r==cd.row&&c==cd.col){this.node.removeAttribute('rowspan');this.node.removeAttribute('colspan');continue;}var B=this.node.cloneNode();
-B.removeAttribute('id');B.innerHTML='';A[r][c]={cell:B,col:c,row:r,colspan:1,rowspan:1};}}this.redrawAllCells(A);},redrawAllCells:function(A){var B=this.node.closest('tr').closest('table');var C=B.rows[0].parentNode;Array.from(B.rows).forEach(function(r,ri){Array.from(r.cells).forEach(function(ce,ci){ce.parentNode.removeChild(ce);
-});r.parentNode.removeChild(r);});for(var r=0;r<A.length;r++){var re=B.rows[r];var re=B.ownerDocument.createElement('tr');C.appendChild(re);for(var c=0;c<A[r].length;c++){if(A[r][c].cell===false){continue;}re.appendChild(A[r][c].cell);A[r][c].cell=false;}
-}},updateWidths:function(A){for(var r=0;r<A.length;r++){for(var c=0;c<A[r].length;c++){if(A[r][c].cell===false){continue;}if(this.colWidths[0]!=false&&A[r][c].colspan<2){var el=Roo.htmleditor.Block.factory(A[r][c].cell);el.width=Math.floor(this.colWidths[c])+'%';
-el.updateElement(el.node);}A[r][c].cell=false;}}},normalizeWidths:function(A){if(this.colWidths[0]===false){var nw=100.0/this.colWidths.length;this.colWidths.forEach(function(w,i){this.colWidths[i]=nw;},this);return;}var t=0,B=[];this.colWidths.forEach(function(w,i){this.colWidths[i]=this.colWidths[i]==''?0:(this.colWidths[i]+'').replace(/[^0-9]+/g,'')*1;
-var D=this.colWidths[i];if(D>0){t+=D;return;}B.push(i);},this);var nc=this.colWidths.length;if(B.length){var C=(nc-B.length)/(1.0*nc);var t=C*t;var ew=(100-t)/(1.0*B.length);this.colWidths.forEach(function(w,i){if(w>0){this.colWidths[i]=w*C;return;}this.colWidths[i]=ew;
-},this);}},shrinkColumn:function(){var A=this.toTableArray();this.normalizeWidths(A);var B=this.cellData.col;var nw=this.colWidths[B]*0.8;if(nw<5){return;}var C=(this.colWidths[B]*0.2)/(this.colWidths.length-1);this.colWidths.forEach(function(w,i){if(i==B){this.colWidths[i]=nw;
-return;}this.colWidths[i]+=C},this);this.updateWidths(A);},growColumn:function(){var A=this.toTableArray();this.normalizeWidths(A);var B=this.cellData.col;var nw=this.colWidths[B]*1.2;if(nw>90){return;}var C=(this.colWidths[B]*0.2)/(this.colWidths.length-1);
-this.colWidths.forEach(function(w,i){if(i==B){this.colWidths[i]=nw;return;}this.colWidths[i]-=C},this);this.updateWidths(A);},deleteRow:function(){var A=this.toTableArray();for(var i=0;i<A[this.cellData.row].length;i++){var c=A[this.cellData.row][i];if(c.row!=this.cellData.row){c.rowspan--;
-c.cell.setAttribute('rowspan',c.rowspan);continue;}if(c.rowspan>1){c.rowspan--;c.cell.setAttribute('rowspan',c.rowspan);}}A.splice(this.cellData.row,1);this.redrawAllCells(A);},deleteColumn:function(){var A=this.toTableArray();for(var i=0;i<A.length;i++){var c=A[i][this.cellData.col];
-if(c.col!=this.cellData.col){A[i][this.cellData.col].colspan--;}else if(c.colspan>1){c.colspan--;c.cell.setAttribute('colspan',c.colspan);}A[i].splice(this.cellData.col,1);}this.redrawAllCells(A);}})
 // Roo/HtmlEditorCore.js
 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);
 // Roo/HtmlEditorCore.js
 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);