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=' ';}}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',' ');
-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!=' '){n.insertAdjacentHTML('afterend',' ');}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.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:{'"':'"','\'':''','<':'<','>':'>','&':'&','`':'`'},reverseEntities:{'<':'<','>':'>','&':'&','"':'"',''':'\''},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=' ';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:" "};},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.bootstrap = {};/**
+/**
* set the version of bootstrap based on the stylesheet...
*
*/
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> </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 = ' ';
- 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 : " " // 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);
});
-Roo.bootstrap.dash = {};/*
+/*
* - LGPL
*
* numberBox
-// 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
}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=' ';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:" "};},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);
,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);
}
};
})();
-/**
- * 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 = ' ';
- }
- }
-
- 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', ' ');
- 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 != ' ') {
- n.insertAdjacentHTML('afterend', ' ');
- }
- this.cursorText (n.nextSibling);
- }
-
-
-});/*
+/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
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=' ';}}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',' ');
-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!=' '){n.insertAdjacentHTML('afterend',' ');}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;
}
};
})();
-/**
- * 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 = ' ';
- }
- }
-
- 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', ' ');
- 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 != ' ') {
- n.insertAdjacentHTML('afterend', ' ');
- }
- this.cursorText (n.nextSibling);
- }
-
-
-});/*
+/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
}
-});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> </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 : {
- '"': '"',
- // Needs to be escaped since the YUI compressor would otherwise break the code
- '\'': ''',
- '<': '<',
- '>': '>',
- '&': '&',
- '`': '`'
- },
- // Reverse lookup table for raw entities
- reverseEntities : {
- '<': '<',
- '>': '>',
- '&': '&',
- '"': '"',
- ''': '\''
- },
-
- 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 = ' ';
- 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 : " " // 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
}
-});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> </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 : {
- '"': '"',
- // Needs to be escaped since the YUI compressor would otherwise break the code
- '\'': ''',
- '<': '<',
- '>': '>',
- '&': '&',
- '`': '`'
- },
- // Reverse lookup table for raw entities
- reverseEntities : {
- '<': '<',
- '>': '>',
- '&': '&',
- '"': '"',
- ''': '\''
- },
-
- 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 = ' ';
- 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 : " " // 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
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:{'"':'"','\'':''','<':'<','>':'>','&':'&','`':'`'},reverseEntities:{'<':'<','>':'>','&':'&','"':'"',''':'\''},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=' ';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:" "};},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);