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);
27 * Fires when the editor is fully initialized (including the iframe)
28 * @param {Roo.HtmlEditorCore} this
33 * Fires when the editor is first receives the focus. Any insertion must wait
34 * until after this event.
35 * @param {Roo.HtmlEditorCore} this
40 * Fires before the textarea is updated with content from the editor iframe. Return false
42 * @param {Roo.HtmlEditorCore} this
43 * @param {String} html
48 * Fires before the iframe editor is updated with content from the textarea. Return false
50 * @param {Roo.HtmlEditorCore} this
51 * @param {String} html
56 * Fires when the textarea is updated with content from the editor iframe.
57 * @param {Roo.HtmlEditorCore} this
58 * @param {String} html
63 * Fires when the iframe editor is updated with content from the textarea.
64 * @param {Roo.HtmlEditorCore} this
65 * @param {String} html
71 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
72 * @param {Roo.HtmlEditorCore} this
78 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
80 // defaults : white / black...
81 this.applyBlacklists();
88 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
92 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
98 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
103 * @cfg {Number} height (in pixels)
107 * @cfg {Number} width (in pixels)
112 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
118 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
120 allowComments: false,
124 // private properties
125 validationEvent : false,
129 sourceEditMode : false,
130 onFocus : Roo.emptyFn,
136 // blacklist + whitelisted elements..
143 * Protected method that will not generally be called directly. It
144 * is called when the editor initializes the iframe with HTML contents. Override this method if you
145 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
147 getDocMarkup : function(){
151 // inherit styels from page...??
152 if (this.stylesheets === false) {
154 Roo.get(document.head).select('style').each(function(node) {
155 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
158 Roo.get(document.head).select('link').each(function(node) {
159 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
162 } else if (!this.stylesheets.length) {
164 st = '<style type="text/css">' +
165 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
168 for (var i in this.stylesheets) {
169 if (typeof(this.stylesheets[i]) != 'string') {
172 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
177 st += '<style type="text/css">' +
178 'IMG { cursor: pointer } ' +
181 var cls = 'roo-htmleditor-body';
183 if(this.bodyCls.length){
184 cls += ' ' + this.bodyCls;
187 return '<html><head>' + st +
188 //<style type="text/css">' +
189 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
191 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
195 onRender : function(ct, position)
198 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
199 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
202 this.el.dom.style.border = '0 none';
203 this.el.dom.setAttribute('tabIndex', -1);
204 this.el.addClass('x-hidden hide');
208 if(Roo.isIE){ // fix IE 1px bogus margin
209 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
213 this.frameId = Roo.id();
217 var iframe = this.owner.wrap.createChild({
219 cls: 'form-control', // bootstrap..
223 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
228 this.iframe = iframe.dom;
232 this.doc.designMode = 'on';
235 this.doc.write(this.getDocMarkup());
239 var task = { // must defer to wait for browser to be ready
241 //console.log("run task?" + this.doc.readyState);
243 if(this.doc.body || this.doc.readyState == 'complete'){
245 this.doc.designMode="on";
249 Roo.TaskMgr.stop(task);
250 this.initEditor.defer(10, this);
257 Roo.TaskMgr.start(task);
262 onResize : function(w, h)
264 Roo.log('resize: ' +w + ',' + h );
265 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
269 if(typeof w == 'number'){
271 this.iframe.style.width = w + 'px';
273 if(typeof h == 'number'){
275 this.iframe.style.height = h + 'px';
277 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
284 * Toggles the editor between standard and source edit mode.
285 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
287 toggleSourceEdit : function(sourceEditMode){
289 this.sourceEditMode = sourceEditMode === true;
291 if(this.sourceEditMode){
293 Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']); //FIXME - what's the BS styles for these
296 Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']);
297 //this.iframe.className = '';
300 //this.setSize(this.owner.wrap.getSize());
301 //this.fireEvent('editmodechange', this, this.sourceEditMode);
308 * Protected method that will not generally be called directly. If you need/want
309 * custom HTML cleanup, this is the method you should override.
310 * @param {String} html The HTML to be cleaned
311 * return {String} The cleaned HTML
313 cleanHtml : function(html){
316 if(Roo.isSafari){ // strip safari nonsense
317 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
320 if(html == ' '){
327 * HTML Editor -> Textarea
328 * Protected method that will not generally be called directly. Syncs the contents
329 * of the editor iframe with the textarea.
331 syncValue : function(){
332 if(this.initialized){
333 var bd = (this.doc.body || this.doc.documentElement);
334 //this.cleanUpPaste(); -- this is done else where and causes havoc..
335 var html = bd.innerHTML;
337 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
338 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
340 html = '<div style="'+m[0]+'">' + html + '</div>';
343 html = this.cleanHtml(html);
344 // fix up the special chars.. normaly like back quotes in word...
345 // however we do not want to do this with chinese..
346 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
348 var cc = match.charCodeAt();
350 // Get the character value, handling surrogate pairs
351 if (match.length == 2) {
352 // It's a surrogate pair, calculate the Unicode code point
353 var high = match.charCodeAt(0) - 0xD800;
354 var low = match.charCodeAt(1) - 0xDC00;
355 cc = (high * 0x400) + low + 0x10000;
357 (cc >= 0x4E00 && cc < 0xA000 ) ||
358 (cc >= 0x3400 && cc < 0x4E00 ) ||
359 (cc >= 0xf900 && cc < 0xfb00 )
364 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
365 return "&#" + cc + ";";
372 if(this.owner.fireEvent('beforesync', this, html) !== false){
373 this.el.dom.value = html;
374 this.owner.fireEvent('sync', this, html);
380 * TEXTAREA -> EDITABLE
381 * Protected method that will not generally be called directly. Pushes the value of the textarea
382 * into the iframe editor.
384 pushValue : function()
386 if(this.initialized){
387 var v = this.el.dom.value.trim();
390 if(this.owner.fireEvent('beforepush', this, v) !== false){
391 var d = (this.doc.body || this.doc.documentElement);
393 //this.cleanUpPaste();
394 this.el.dom.value = d.innerHTML;
395 this.owner.fireEvent('push', this, v);
398 Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) {
399 var cls = Roo.htmleditor['Block' + Roo.get(e).attr('data-block')];
400 if (typeof(cls) == 'undefined') {
401 Roo.log("OOps missing block : " + 'Block' + Roo.get(e).attr('data-block'));
404 new cls(e); /// should trigger update element
412 deferFocus : function(){
413 this.focus.defer(10, this);
418 if(this.win && !this.sourceEditMode){
425 assignDocWin: function()
427 var iframe = this.iframe;
430 this.doc = iframe.contentWindow.document;
431 this.win = iframe.contentWindow;
433 // if (!Roo.get(this.frameId)) {
436 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
437 // this.win = Roo.get(this.frameId).dom.contentWindow;
439 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
443 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
444 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
449 initEditor : function(){
450 //console.log("INIT EDITOR");
455 this.doc.designMode="on";
457 this.doc.write(this.getDocMarkup());
460 var dbody = (this.doc.body || this.doc.documentElement);
461 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
462 // this copies styles from the containing element into thsi one..
463 // not sure why we need all of this..
464 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
466 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
467 //ss['background-attachment'] = 'fixed'; // w3c
468 dbody.bgProperties = 'fixed'; // ie
469 //Roo.DomHelper.applyStyles(dbody, ss);
470 Roo.EventManager.on(this.doc, {
471 //'mousedown': this.onEditorEvent,
472 'mouseup': this.onEditorEvent,
473 'dblclick': this.onEditorEvent,
474 'click': this.onEditorEvent,
475 'keyup': this.onEditorEvent,
476 'paste': this.onPasteEvent,
481 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
483 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
484 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
486 this.initialized = true;
489 // initialize special key events - enter
490 new Roo.htmleditor.KeyEnter({core : this});
494 this.owner.fireEvent('initialize', this);
498 onPasteEvent : function(e,v) {
499 // default behaveiour should be our local cleanup paste? (optional?)
500 // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable..
501 this.owner.fireEvent('paste', e, v);
504 onDestroy : function(){
510 //for (var i =0; i < this.toolbars.length;i++) {
511 // // fixme - ask toolbars for heights?
512 // this.toolbars[i].onDestroy();
515 //this.wrap.dom.innerHTML = '';
516 //this.wrap.remove();
521 onFirstFocus : function(){
526 this.activated = true;
529 if(Roo.isGecko){ // prevent silly gecko errors
531 var s = this.win.getSelection();
532 if(!s.focusNode || s.focusNode.nodeType != 3){
533 var r = s.getRangeAt(0);
534 r.selectNodeContents((this.doc.body || this.doc.documentElement));
539 this.execCmd('useCSS', true);
540 this.execCmd('styleWithCSS', false);
543 this.owner.fireEvent('activate', this);
547 adjustFont: function(btn){
548 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
549 //if(Roo.isSafari){ // safari
552 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
553 if(Roo.isSafari){ // safari
554 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
555 v = (v < 10) ? 10 : v;
556 v = (v > 48) ? 48 : v;
557 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
562 v = Math.max(1, v+adjust);
564 this.execCmd('FontSize', v );
567 onEditorEvent : function(e)
569 this.owner.fireEvent('editorevent', this, e);
570 // this.updateToolbar();
571 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
574 insertTag : function(tg)
576 // could be a bit smarter... -> wrap the current selected tRoo..
577 if (tg.toLowerCase() == 'span' ||
578 tg.toLowerCase() == 'code' ||
579 tg.toLowerCase() == 'sup' ||
580 tg.toLowerCase() == 'sub'
583 range = this.createRange(this.getSelection());
584 var wrappingNode = this.doc.createElement(tg.toLowerCase());
585 wrappingNode.appendChild(range.extractContents());
586 range.insertNode(wrappingNode);
593 this.execCmd("formatblock", tg);
597 insertText : function(txt)
601 var range = this.createRange();
602 range.deleteContents();
603 //alert(Sender.getAttribute('label'));
605 range.insertNode(this.doc.createTextNode(txt));
611 * Executes a Midas editor command on the editor document and performs necessary focus and
612 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
613 * @param {String} cmd The Midas command
614 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
616 relayCmd : function(cmd, value){
618 this.execCmd(cmd, value);
619 this.owner.fireEvent('editorevent', this);
620 //this.updateToolbar();
621 this.owner.deferFocus();
625 * Executes a Midas editor command directly on the editor document.
626 * For visual commands, you should use {@link #relayCmd} instead.
627 * <b>This should only be called after the editor is initialized.</b>
628 * @param {String} cmd The Midas command
629 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
631 execCmd : function(cmd, value){
632 this.doc.execCommand(cmd, false, value === undefined ? null : value);
639 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
641 * @param {String} text | dom node..
643 insertAtCursor : function(text)
652 var r = this.doc.selection.createRange();
663 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
667 // from jquery ui (MIT licenced)
671 if (win.getSelection && win.getSelection().getRangeAt) {
672 range = win.getSelection().getRangeAt(0);
673 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
674 range.insertNode(node);
675 } else if (win.document.selection && win.document.selection.createRange) {
676 // no firefox support
677 var txt = typeof(text) == 'string' ? text : text.outerHTML;
678 win.document.selection.createRange().pasteHTML(txt);
680 // no firefox support
681 var txt = typeof(text) == 'string' ? text : text.outerHTML;
682 this.execCmd('InsertHTML', txt);
691 mozKeyPress : function(e){
693 var c = e.getCharCode(), cmd;
696 c = String.fromCharCode(c).toLowerCase();
710 // this.cleanUpPaste.defer(100, this);
726 fixKeys : function(){ // load time branching for fastest keydown performance
729 var k = e.getKey(), r;
732 r = this.doc.selection.createRange();
735 r.pasteHTML('    ');
742 r = this.doc.selection.createRange();
744 var target = r.parentElement();
745 if(!target || target.tagName.toLowerCase() != 'li'){
747 r.pasteHTML('<br/>');
753 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
754 // this.cleanUpPaste.defer(100, this);
760 }else if(Roo.isOpera){
766 this.execCmd('InsertHTML','    ');
769 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
770 // this.cleanUpPaste.defer(100, this);
775 }else if(Roo.isSafari){
781 this.execCmd('InsertText','\t');
785 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
786 // this.cleanUpPaste.defer(100, this);
794 getAllAncestors: function()
796 var p = this.getSelectedNode();
799 a.push(p); // push blank onto stack..
800 p = this.getParentElement();
804 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
808 a.push(this.doc.body);
815 getSelection : function()
818 return Roo.isIE ? this.doc.selection : this.win.getSelection();
821 getSelectedNode: function()
823 // this may only work on Gecko!!!
825 // should we cache this!!!!
830 var range = this.createRange(this.getSelection()).cloneRange();
833 var parent = range.parentElement();
835 var testRange = range.duplicate();
836 testRange.moveToElementText(parent);
837 if (testRange.inRange(range)) {
840 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
843 parent = parent.parentElement;
848 // is ancestor a text element.
849 var ac = range.commonAncestorContainer;
850 if (ac.nodeType == 3) {
854 var ar = ac.childNodes;
857 var other_nodes = [];
858 var has_other_nodes = false;
859 for (var i=0;i<ar.length;i++) {
860 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
863 // fullly contained node.
865 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
870 // probably selected..
871 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
872 other_nodes.push(ar[i]);
876 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
881 has_other_nodes = true;
883 if (!nodes.length && other_nodes.length) {
886 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
892 createRange: function(sel)
894 // this has strange effects when using with
895 // top toolbar - not sure if it's a great idea.
896 //this.editor.contentWindow.focus();
897 if (typeof sel != "undefined") {
899 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
901 return this.doc.createRange();
904 return this.doc.createRange();
907 getParentElement: function()
911 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
913 var range = this.createRange(sel);
916 var p = range.commonAncestorContainer;
917 while (p.nodeType == 3) { // text node
928 * Range intersection.. the hard stuff...
932 * [ -- selected range --- ]
936 * if end is before start or hits it. fail.
937 * if start is after end or hits it fail.
939 * if either hits (but other is outside. - then it's not
945 // @see http://www.thismuchiknow.co.uk/?p=64.
946 rangeIntersectsNode : function(range, node)
948 var nodeRange = node.ownerDocument.createRange();
950 nodeRange.selectNode(node);
952 nodeRange.selectNodeContents(node);
955 var rangeStartRange = range.cloneRange();
956 rangeStartRange.collapse(true);
958 var rangeEndRange = range.cloneRange();
959 rangeEndRange.collapse(false);
961 var nodeStartRange = nodeRange.cloneRange();
962 nodeStartRange.collapse(true);
964 var nodeEndRange = nodeRange.cloneRange();
965 nodeEndRange.collapse(false);
967 return rangeStartRange.compareBoundaryPoints(
968 Range.START_TO_START, nodeEndRange) == -1 &&
969 rangeEndRange.compareBoundaryPoints(
970 Range.START_TO_START, nodeStartRange) == 1;
974 rangeCompareNode : function(range, node)
976 var nodeRange = node.ownerDocument.createRange();
978 nodeRange.selectNode(node);
980 nodeRange.selectNodeContents(node);
984 range.collapse(true);
986 nodeRange.collapse(true);
988 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
989 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
991 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
993 var nodeIsBefore = ss == 1;
994 var nodeIsAfter = ee == -1;
996 if (nodeIsBefore && nodeIsAfter) {
999 if (!nodeIsBefore && nodeIsAfter) {
1000 return 1; //right trailed.
1003 if (nodeIsBefore && !nodeIsAfter) {
1004 return 2; // left trailed.
1010 // private? - in a new class?
1011 cleanUpPaste : function()
1013 // cleans up the whole document..
1014 Roo.log('cleanuppaste');
1016 this.cleanUpChild(this.doc.body);
1017 var clean = this.cleanWordChars(this.doc.body.innerHTML);
1018 if (clean != this.doc.body.innerHTML) {
1019 this.doc.body.innerHTML = clean;
1024 cleanWordChars : function(input) {// change the chars to hex code
1025 var he = Roo.HtmlEditorCore;
1028 Roo.each(he.swapCodes, function(sw) {
1029 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
1031 output = output.replace(swapper, sw[1]);
1041 cleanUpChild : function (node)
1044 new Roo.htmleditor.FilterComment({node : node});
1045 new Roo.htmleditor.FilterAttributes({
1047 attrib_black : this.ablack,
1048 attrib_clean : this.aclean,
1049 style_white : this.cwhite,
1050 style_black : this.cblack
1052 new Roo.htmleditor.FilterBlack({ node : node, tag : this.black});
1053 new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} );
1059 * Clean up MS wordisms...
1060 * @deprecated - use filter directly
1062 cleanWord : function(node)
1064 new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
1071 * @deprecated - use filters
1073 cleanTableWidths : function(node)
1075 new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
1082 applyBlacklists : function()
1084 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
1085 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
1087 this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean : Roo.HtmlEditorCore.aclean;
1088 this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack : Roo.HtmlEditorCore.ablack;
1089 this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove : Roo.HtmlEditorCore.tag_remove;
1093 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
1094 if (b.indexOf(tag) > -1) {
1097 this.white.push(tag);
1101 Roo.each(w, function(tag) {
1102 if (b.indexOf(tag) > -1) {
1105 if (this.white.indexOf(tag) > -1) {
1108 this.white.push(tag);
1113 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
1114 if (w.indexOf(tag) > -1) {
1117 this.black.push(tag);
1121 Roo.each(b, function(tag) {
1122 if (w.indexOf(tag) > -1) {
1125 if (this.black.indexOf(tag) > -1) {
1128 this.black.push(tag);
1133 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
1134 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
1138 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
1139 if (b.indexOf(tag) > -1) {
1142 this.cwhite.push(tag);
1146 Roo.each(w, function(tag) {
1147 if (b.indexOf(tag) > -1) {
1150 if (this.cwhite.indexOf(tag) > -1) {
1153 this.cwhite.push(tag);
1158 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
1159 if (w.indexOf(tag) > -1) {
1162 this.cblack.push(tag);
1166 Roo.each(b, function(tag) {
1167 if (w.indexOf(tag) > -1) {
1170 if (this.cblack.indexOf(tag) > -1) {
1173 this.cblack.push(tag);
1178 setStylesheets : function(stylesheets)
1180 if(typeof(stylesheets) == 'string'){
1181 Roo.get(this.iframe.contentDocument.head).createChild({
1192 Roo.each(stylesheets, function(s) {
1197 Roo.get(_this.iframe.contentDocument.head).createChild({
1208 removeStylesheets : function()
1212 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
1217 setStyle : function(style)
1219 Roo.get(this.iframe.contentDocument.head).createChild({
1228 // hide stuff that is not compatible
1246 * @cfg {String} fieldClass @hide
1249 * @cfg {String} focusClass @hide
1252 * @cfg {String} autoCreate @hide
1255 * @cfg {String} inputType @hide
1258 * @cfg {String} invalidClass @hide
1261 * @cfg {String} invalidText @hide
1264 * @cfg {String} msgFx @hide
1267 * @cfg {String} validateOnBlur @hide
1271 Roo.HtmlEditorCore.white = [
1272 'area', 'br', 'img', 'input', 'hr', 'wbr',
1274 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
1275 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
1276 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
1277 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
1278 'table', 'ul', 'xmp',
1280 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
1283 'dir', 'menu', 'ol', 'ul', 'dl',
1289 Roo.HtmlEditorCore.black = [
1290 // 'embed', 'object', // enable - backend responsiblity to clean thiese
1292 'base', 'basefont', 'bgsound', 'blink', 'body',
1293 'frame', 'frameset', 'head', 'html', 'ilayer',
1294 'iframe', 'layer', 'link', 'meta', 'object',
1295 'script', 'style' ,'title', 'xml' // clean later..
1297 Roo.HtmlEditorCore.clean = [
1298 'script', 'style', 'title', 'xml'
1300 Roo.HtmlEditorCore.tag_remove = [
1305 Roo.HtmlEditorCore.ablack = [
1309 Roo.HtmlEditorCore.aclean = [
1310 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
1314 Roo.HtmlEditorCore.pwhite= [
1315 'http', 'https', 'mailto'
1318 // white listed style attributes.
1319 Roo.HtmlEditorCore.cwhite= [
1320 // 'text-align', /// default is to allow most things..
1326 // black listed style attributes.
1327 Roo.HtmlEditorCore.cblack= [
1328 // 'font-size' -- this can be set by the project
1332 Roo.HtmlEditorCore.swapCodes =[
1333 [ 8211, "–" ],
1334 [ 8212, "—" ],