1 //<script type="text/javascript">
4 * Based Ext JS Library 1.1.1
5 * Copyright(c) 2006-2007, Ext JS, LLC.
11 * @class Roo.HtmlEditorCore
12 * @extends Roo.Component
13 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
18 Roo.HtmlEditorCore = function(config){
21 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
25 * Fires when the editor is fully initialized (including the iframe)
26 * @param {Roo.HtmlEditorCore} this
31 * Fires when the editor is first receives the focus. Any insertion must wait
32 * until after this event.
33 * @param {Roo.HtmlEditorCore} this
38 * Fires before the textarea is updated with content from the editor iframe. Return false
40 * @param {Roo.HtmlEditorCore} this
41 * @param {String} html
46 * Fires before the iframe editor is updated with content from the textarea. Return false
48 * @param {Roo.HtmlEditorCore} this
49 * @param {String} html
54 * Fires when the textarea is updated with content from the editor iframe.
55 * @param {Roo.HtmlEditorCore} this
56 * @param {String} html
61 * Fires when the iframe editor is updated with content from the textarea.
62 * @param {Roo.HtmlEditorCore} this
63 * @param {String} html
69 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
70 * @param {Roo.HtmlEditorCore} this
78 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
82 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
88 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
93 * @cfg {Number} height (in pixels)
97 * @cfg {Number} width (in pixels)
102 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
110 // private properties
111 validationEvent : false,
115 sourceEditMode : false,
116 onFocus : Roo.emptyFn,
124 * Protected method that will not generally be called directly. It
125 * is called when the editor initializes the iframe with HTML contents. Override this method if you
126 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
128 getDocMarkup : function(){
131 Roo.log(this.stylesheets);
133 // inherit styels from page...??
134 if (this.stylesheets === false) {
136 Roo.get(document.head).select('style').each(function(node) {
137 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
140 Roo.get(document.head).select('link').each(function(node) {
141 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
144 } else if (!this.stylesheets.length) {
146 st = '<style type="text/css">' +
147 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
150 Roo.each(this.stylesheets, function(s) {
151 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
156 st += '<style type="text/css">' +
157 'IMG { cursor: pointer } ' +
161 return '<html><head>' + st +
162 //<style type="text/css">' +
163 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
165 ' </head><body class="roo-htmleditor-body"></body></html>';
169 onRender : function(ct, position)
172 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
173 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
176 this.el.dom.style.border = '0 none';
177 this.el.dom.setAttribute('tabIndex', -1);
178 this.el.addClass('x-hidden hide');
182 if(Roo.isIE){ // fix IE 1px bogus margin
183 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
187 this.frameId = Roo.id();
191 var iframe = this.owner.wrap.createChild({
193 cls: 'form-control', // bootstrap..
197 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
202 this.iframe = iframe.dom;
206 this.doc.designMode = 'on';
209 this.doc.write(this.getDocMarkup());
213 var task = { // must defer to wait for browser to be ready
215 //console.log("run task?" + this.doc.readyState);
217 if(this.doc.body || this.doc.readyState == 'complete'){
219 this.doc.designMode="on";
223 Roo.TaskMgr.stop(task);
224 this.initEditor.defer(10, this);
231 Roo.TaskMgr.start(task);
238 onResize : function(w, h)
240 Roo.log('resize: ' +w + ',' + h );
241 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
245 if(typeof w == 'number'){
247 this.iframe.style.width = w + 'px';
249 if(typeof h == 'number'){
251 this.iframe.style.height = h + 'px';
253 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
260 * Toggles the editor between standard and source edit mode.
261 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
263 toggleSourceEdit : function(sourceEditMode){
265 this.sourceEditMode = sourceEditMode === true;
267 if(this.sourceEditMode){
269 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
272 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
273 //this.iframe.className = '';
276 //this.setSize(this.owner.wrap.getSize());
277 //this.fireEvent('editmodechange', this, this.sourceEditMode);
284 * Protected method that will not generally be called directly. If you need/want
285 * custom HTML cleanup, this is the method you should override.
286 * @param {String} html The HTML to be cleaned
287 * return {String} The cleaned HTML
289 cleanHtml : function(html){
292 if(Roo.isSafari){ // strip safari nonsense
293 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
296 if(html == ' '){
303 * HTML Editor -> Textarea
304 * Protected method that will not generally be called directly. Syncs the contents
305 * of the editor iframe with the textarea.
307 syncValue : function(){
308 if(this.initialized){
309 var bd = (this.doc.body || this.doc.documentElement);
310 //this.cleanUpPaste(); -- this is done else where and causes havoc..
311 var html = bd.innerHTML;
313 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
314 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
316 html = '<div style="'+m[0]+'">' + html + '</div>';
319 html = this.cleanHtml(html);
320 // fix up the special chars.. normaly like back quotes in word...
321 // however we do not want to do this with chinese..
322 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
323 var cc = b.charCodeAt();
325 (cc >= 0x4E00 && cc < 0xA000 ) ||
326 (cc >= 0x3400 && cc < 0x4E00 ) ||
327 (cc >= 0xf900 && cc < 0xfb00 )
333 if(this.owner.fireEvent('beforesync', this, html) !== false){
334 this.el.dom.value = html;
335 this.owner.fireEvent('sync', this, html);
341 * Protected method that will not generally be called directly. Pushes the value of the textarea
342 * into the iframe editor.
344 pushValue : function(){
345 if(this.initialized){
346 var v = this.el.dom.value;
352 if(this.owner.fireEvent('beforepush', this, v) !== false){
353 var d = (this.doc.body || this.doc.documentElement);
356 this.el.dom.value = d.innerHTML;
357 this.owner.fireEvent('push', this, v);
363 deferFocus : function(){
364 this.focus.defer(10, this);
369 if(this.win && !this.sourceEditMode){
376 assignDocWin: function()
378 var iframe = this.iframe;
381 this.doc = iframe.contentWindow.document;
382 this.win = iframe.contentWindow;
384 if (!Roo.get(this.frameId)) {
387 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
388 this.win = Roo.get(this.frameId).dom.contentWindow;
393 initEditor : function(){
394 //console.log("INIT EDITOR");
399 this.doc.designMode="on";
401 this.doc.write(this.getDocMarkup());
404 var dbody = (this.doc.body || this.doc.documentElement);
405 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
406 // this copies styles from the containing element into thsi one..
407 // not sure why we need all of this..
408 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
409 ss['background-attachment'] = 'fixed'; // w3c
410 dbody.bgProperties = 'fixed'; // ie
411 Roo.DomHelper.applyStyles(dbody, ss);
412 Roo.EventManager.on(this.doc, {
413 //'mousedown': this.onEditorEvent,
414 'mouseup': this.onEditorEvent,
415 'dblclick': this.onEditorEvent,
416 'click': this.onEditorEvent,
417 'keyup': this.onEditorEvent,
422 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
424 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
425 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
427 this.initialized = true;
429 this.owner.fireEvent('initialize', this);
434 onDestroy : function(){
440 //for (var i =0; i < this.toolbars.length;i++) {
441 // // fixme - ask toolbars for heights?
442 // this.toolbars[i].onDestroy();
445 //this.wrap.dom.innerHTML = '';
446 //this.wrap.remove();
451 onFirstFocus : function(){
456 this.activated = true;
459 if(Roo.isGecko){ // prevent silly gecko errors
461 var s = this.win.getSelection();
462 if(!s.focusNode || s.focusNode.nodeType != 3){
463 var r = s.getRangeAt(0);
464 r.selectNodeContents((this.doc.body || this.doc.documentElement));
469 this.execCmd('useCSS', true);
470 this.execCmd('styleWithCSS', false);
473 this.owner.fireEvent('activate', this);
477 adjustFont: function(btn){
478 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
479 //if(Roo.isSafari){ // safari
482 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
483 if(Roo.isSafari){ // safari
484 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
485 v = (v < 10) ? 10 : v;
486 v = (v > 48) ? 48 : v;
487 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
492 v = Math.max(1, v+adjust);
494 this.execCmd('FontSize', v );
497 onEditorEvent : function(e){
498 this.owner.fireEvent('editorevent', this, e);
499 // this.updateToolbar();
500 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
503 insertTag : function(tg)
505 // could be a bit smarter... -> wrap the current selected tRoo..
506 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
508 range = this.createRange(this.getSelection());
509 var wrappingNode = this.doc.createElement(tg.toLowerCase());
510 wrappingNode.appendChild(range.extractContents());
511 range.insertNode(wrappingNode);
518 this.execCmd("formatblock", tg);
522 insertText : function(txt)
526 var range = this.createRange();
527 range.deleteContents();
528 //alert(Sender.getAttribute('label'));
530 range.insertNode(this.doc.createTextNode(txt));
536 * Executes a Midas editor command on the editor document and performs necessary focus and
537 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
538 * @param {String} cmd The Midas command
539 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
541 relayCmd : function(cmd, value){
543 this.execCmd(cmd, value);
544 this.owner.fireEvent('editorevent', this);
545 //this.updateToolbar();
546 this.owner.deferFocus();
550 * Executes a Midas editor command directly on the editor document.
551 * For visual commands, you should use {@link #relayCmd} instead.
552 * <b>This should only be called after the editor is initialized.</b>
553 * @param {String} cmd The Midas command
554 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
556 execCmd : function(cmd, value){
557 this.doc.execCommand(cmd, false, value === undefined ? null : value);
564 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
566 * @param {String} text | dom node..
568 insertAtCursor : function(text)
579 var r = this.doc.selection.createRange();
590 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
594 // from jquery ui (MIT licenced)
598 if (win.getSelection && win.getSelection().getRangeAt) {
599 range = win.getSelection().getRangeAt(0);
600 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
601 range.insertNode(node);
602 } else if (win.document.selection && win.document.selection.createRange) {
603 // no firefox support
604 var txt = typeof(text) == 'string' ? text : text.outerHTML;
605 win.document.selection.createRange().pasteHTML(txt);
607 // no firefox support
608 var txt = typeof(text) == 'string' ? text : text.outerHTML;
609 this.execCmd('InsertHTML', txt);
618 mozKeyPress : function(e){
620 var c = e.getCharCode(), cmd;
623 c = String.fromCharCode(c).toLowerCase();
637 this.cleanUpPaste.defer(100, this);
653 fixKeys : function(){ // load time branching for fastest keydown performance
656 var k = e.getKey(), r;
659 r = this.doc.selection.createRange();
662 r.pasteHTML('    ');
669 r = this.doc.selection.createRange();
671 var target = r.parentElement();
672 if(!target || target.tagName.toLowerCase() != 'li'){
674 r.pasteHTML('<br />');
680 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
681 this.cleanUpPaste.defer(100, this);
687 }else if(Roo.isOpera){
693 this.execCmd('InsertHTML','    ');
696 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
697 this.cleanUpPaste.defer(100, this);
702 }else if(Roo.isSafari){
708 this.execCmd('InsertText','\t');
712 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
713 this.cleanUpPaste.defer(100, this);
721 getAllAncestors: function()
723 var p = this.getSelectedNode();
726 a.push(p); // push blank onto stack..
727 p = this.getParentElement();
731 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
735 a.push(this.doc.body);
742 getSelection : function()
745 return Roo.isIE ? this.doc.selection : this.win.getSelection();
748 getSelectedNode: function()
750 // this may only work on Gecko!!!
752 // should we cache this!!!!
757 var range = this.createRange(this.getSelection()).cloneRange();
760 var parent = range.parentElement();
762 var testRange = range.duplicate();
763 testRange.moveToElementText(parent);
764 if (testRange.inRange(range)) {
767 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
770 parent = parent.parentElement;
775 // is ancestor a text element.
776 var ac = range.commonAncestorContainer;
777 if (ac.nodeType == 3) {
781 var ar = ac.childNodes;
784 var other_nodes = [];
785 var has_other_nodes = false;
786 for (var i=0;i<ar.length;i++) {
787 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
790 // fullly contained node.
792 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
797 // probably selected..
798 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
799 other_nodes.push(ar[i]);
803 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
808 has_other_nodes = true;
810 if (!nodes.length && other_nodes.length) {
813 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
819 createRange: function(sel)
821 // this has strange effects when using with
822 // top toolbar - not sure if it's a great idea.
823 //this.editor.contentWindow.focus();
824 if (typeof sel != "undefined") {
826 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
828 return this.doc.createRange();
831 return this.doc.createRange();
834 getParentElement: function()
838 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
840 var range = this.createRange(sel);
843 var p = range.commonAncestorContainer;
844 while (p.nodeType == 3) { // text node
855 * Range intersection.. the hard stuff...
859 * [ -- selected range --- ]
863 * if end is before start or hits it. fail.
864 * if start is after end or hits it fail.
866 * if either hits (but other is outside. - then it's not
872 // @see http://www.thismuchiknow.co.uk/?p=64.
873 rangeIntersectsNode : function(range, node)
875 var nodeRange = node.ownerDocument.createRange();
877 nodeRange.selectNode(node);
879 nodeRange.selectNodeContents(node);
882 var rangeStartRange = range.cloneRange();
883 rangeStartRange.collapse(true);
885 var rangeEndRange = range.cloneRange();
886 rangeEndRange.collapse(false);
888 var nodeStartRange = nodeRange.cloneRange();
889 nodeStartRange.collapse(true);
891 var nodeEndRange = nodeRange.cloneRange();
892 nodeEndRange.collapse(false);
894 return rangeStartRange.compareBoundaryPoints(
895 Range.START_TO_START, nodeEndRange) == -1 &&
896 rangeEndRange.compareBoundaryPoints(
897 Range.START_TO_START, nodeStartRange) == 1;
901 rangeCompareNode : function(range, node)
903 var nodeRange = node.ownerDocument.createRange();
905 nodeRange.selectNode(node);
907 nodeRange.selectNodeContents(node);
911 range.collapse(true);
913 nodeRange.collapse(true);
915 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
916 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
918 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
920 var nodeIsBefore = ss == 1;
921 var nodeIsAfter = ee == -1;
923 if (nodeIsBefore && nodeIsAfter)
925 if (!nodeIsBefore && nodeIsAfter)
926 return 1; //right trailed.
928 if (nodeIsBefore && !nodeIsAfter)
929 return 2; // left trailed.
934 // private? - in a new class?
935 cleanUpPaste : function()
937 // cleans up the whole document..
938 Roo.log('cleanuppaste');
939 this.cleanUpChildren(this.doc.body);
940 var clean = this.cleanWordChars(this.doc.body.innerHTML);
941 if (clean != this.doc.body.innerHTML) {
942 this.doc.body.innerHTML = clean;
947 cleanWordChars : function(input) {// change the chars to hex code
948 var he = Roo.HtmlEditorCore;
951 Roo.each(he.swapCodes, function(sw) {
952 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
954 output = output.replace(swapper, sw[1]);
961 cleanUpChildren : function (n)
963 if (!n.childNodes.length) {
966 for (var i = n.childNodes.length-1; i > -1 ; i--) {
967 this.cleanUpChild(n.childNodes[i]);
974 cleanUpChild : function (node)
978 if (node.nodeName == "#text") {
979 // clean up silly Windows -- stuff?
982 if (node.nodeName == "#comment") {
983 node.parentNode.removeChild(node);
984 // clean up silly Windows -- stuff?
988 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1) {
990 node.parentNode.removeChild(node);
995 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
997 // remove <a name=....> as rendering on yahoo mailer is borked with this.
998 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
1000 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
1001 // remove_keep_children = true;
1004 if (remove_keep_children) {
1005 this.cleanUpChildren(node);
1006 // inserts everything just before this node...
1007 while (node.childNodes.length) {
1008 var cn = node.childNodes[0];
1009 node.removeChild(cn);
1010 node.parentNode.insertBefore(cn, node);
1012 node.parentNode.removeChild(node);
1016 if (!node.attributes || !node.attributes.length) {
1017 this.cleanUpChildren(node);
1021 function cleanAttr(n,v)
1024 if (v.match(/^\./) || v.match(/^\//)) {
1027 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
1030 if (v.match(/^#/)) {
1033 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
1034 node.removeAttribute(n);
1038 function cleanStyle(n,v)
1040 if (v.match(/expression/)) { //XSS?? should we even bother..
1041 node.removeAttribute(n);
1044 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
1045 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
1048 var parts = v.split(/;/);
1051 Roo.each(parts, function(p) {
1052 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
1056 var l = p.split(':').shift().replace(/\s+/g,'');
1057 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
1060 if ( cblack.indexOf(l) > -1) {
1061 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
1062 //node.removeAttribute(n);
1066 // only allow 'c whitelisted system attributes'
1067 if ( cwhite.length && cwhite.indexOf(l) < 0) {
1068 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
1069 //node.removeAttribute(n);
1080 node.setAttribute(n, clean.join(';'));
1082 node.removeAttribute(n);
1088 for (var i = node.attributes.length-1; i > -1 ; i--) {
1089 var a = node.attributes[i];
1092 if (a.name.toLowerCase().substr(0,2)=='on') {
1093 node.removeAttribute(a.name);
1096 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
1097 node.removeAttribute(a.name);
1100 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
1101 cleanAttr(a.name,a.value); // fixme..
1104 if (a.name == 'style') {
1105 cleanStyle(a.name,a.value);
1108 /// clean up MS crap..
1109 // tecnically this should be a list of valid class'es..
1112 if (a.name == 'class') {
1113 if (a.value.match(/^Mso/)) {
1114 node.className = '';
1117 if (a.value.match(/body/)) {
1118 node.className = '';
1129 this.cleanUpChildren(node);
1135 // hide stuff that is not compatible
1153 * @cfg {String} fieldClass @hide
1156 * @cfg {String} focusClass @hide
1159 * @cfg {String} autoCreate @hide
1162 * @cfg {String} inputType @hide
1165 * @cfg {String} invalidClass @hide
1168 * @cfg {String} invalidText @hide
1171 * @cfg {String} msgFx @hide
1174 * @cfg {String} validateOnBlur @hide
1178 Roo.HtmlEditorCore.white = [
1179 'area', 'br', 'img', 'input', 'hr', 'wbr',
1181 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
1182 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
1183 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
1184 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
1185 'table', 'ul', 'xmp',
1187 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
1190 'dir', 'menu', 'ol', 'ul', 'dl',
1196 Roo.HtmlEditorCore.black = [
1197 // 'embed', 'object', // enable - backend responsiblity to clean thiese
1199 'base', 'basefont', 'bgsound', 'blink', 'body',
1200 'frame', 'frameset', 'head', 'html', 'ilayer',
1201 'iframe', 'layer', 'link', 'meta', 'object',
1202 'script', 'style' ,'title', 'xml' // clean later..
1204 Roo.HtmlEditorCore.clean = [
1205 'script', 'style', 'title', 'xml'
1207 Roo.HtmlEditorCore.remove = [
1212 Roo.HtmlEditorCore.ablack = [
1216 Roo.HtmlEditorCore.aclean = [
1217 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
1221 Roo.HtmlEditorCore.pwhite= [
1222 'http', 'https', 'mailto'
1225 // white listed style attributes.
1226 Roo.HtmlEditorCore.cwhite= [
1227 // 'text-align', /// default is to allow most things..
1233 // black listed style attributes.
1234 Roo.HtmlEditorCore.cblack= [
1235 // 'font-size' -- this can be set by the project
1239 Roo.HtmlEditorCore.swapCodes =[