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()
333 Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)");
334 if(this.initialized){
335 var bd = (this.doc.body || this.doc.documentElement);
336 //this.cleanUpPaste(); -- this is done else where and causes havoc..
338 // not sure if this is really the place for this
339 // the blocks are synced occasionaly - since we currently dont add listeners on the blocks
340 // this has to update attributes that get duped.. like alt and caption..
342 Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) {
343 Roo.htmleditor.Block.factory(e);
347 var div = document.createElement('div');
348 div.innerHTML = bd.innerHTML;
349 // remove content editable. (blocks)
353 new Roo.htmleditor.FilterAttributes({node : div, attrib_black: [ 'contenteditable' ] });
355 var html = div.innerHTML;
357 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
358 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
360 html = '<div style="'+m[0]+'">' + html + '</div>';
363 html = this.cleanHtml(html);
364 // fix up the special chars.. normaly like back quotes in word...
365 // however we do not want to do this with chinese..
366 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
368 var cc = match.charCodeAt();
370 // Get the character value, handling surrogate pairs
371 if (match.length == 2) {
372 // It's a surrogate pair, calculate the Unicode code point
373 var high = match.charCodeAt(0) - 0xD800;
374 var low = match.charCodeAt(1) - 0xDC00;
375 cc = (high * 0x400) + low + 0x10000;
377 (cc >= 0x4E00 && cc < 0xA000 ) ||
378 (cc >= 0x3400 && cc < 0x4E00 ) ||
379 (cc >= 0xf900 && cc < 0xfb00 )
384 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
385 return "&#" + cc + ";";
392 if(this.owner.fireEvent('beforesync', this, html) !== false){
393 this.el.dom.value = html;
394 this.owner.fireEvent('sync', this, html);
400 * TEXTAREA -> EDITABLE
401 * Protected method that will not generally be called directly. Pushes the value of the textarea
402 * into the iframe editor.
404 pushValue : function()
406 Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)");
407 if(this.initialized){
408 var v = this.el.dom.value.trim();
411 if(this.owner.fireEvent('beforepush', this, v) !== false){
412 var d = (this.doc.body || this.doc.documentElement);
415 this.el.dom.value = d.innerHTML;
416 this.owner.fireEvent('push', this, v);
419 Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) {
421 Roo.htmleditor.Block.factory(e);
424 var lc = this.doc.body.lastChild;
425 if (lc && lc.nodeType == 1 && lc.getAttribute("contenteditable") == "false") {
426 // add an extra line at the end.
427 this.doc.body.appendChild(this.doc.createElement('br'));
435 deferFocus : function(){
436 this.focus.defer(10, this);
441 if(this.win && !this.sourceEditMode){
448 assignDocWin: function()
450 var iframe = this.iframe;
453 this.doc = iframe.contentWindow.document;
454 this.win = iframe.contentWindow;
456 // if (!Roo.get(this.frameId)) {
459 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
460 // this.win = Roo.get(this.frameId).dom.contentWindow;
462 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
466 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
467 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
472 initEditor : function(){
473 //console.log("INIT EDITOR");
478 this.doc.designMode="on";
480 this.doc.write(this.getDocMarkup());
483 var dbody = (this.doc.body || this.doc.documentElement);
484 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
485 // this copies styles from the containing element into thsi one..
486 // not sure why we need all of this..
487 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
489 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
490 //ss['background-attachment'] = 'fixed'; // w3c
491 dbody.bgProperties = 'fixed'; // ie
492 //Roo.DomHelper.applyStyles(dbody, ss);
493 Roo.EventManager.on(this.doc, {
494 //'mousedown': this.onEditorEvent,
495 'mouseup': this.onEditorEvent,
496 'dblclick': this.onEditorEvent,
497 'click': this.onEditorEvent,
498 'keyup': this.onEditorEvent,
503 Roo.EventManager.on(this.doc, {
504 'paste': this.onPasteEvent,
508 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
510 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
511 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
513 this.initialized = true;
516 // initialize special key events - enter
517 new Roo.htmleditor.KeyEnter({core : this});
521 this.owner.fireEvent('initialize', this);
525 onPasteEvent : function(e,v)
527 // I think we better assume paste is going to be a dirty load of rubish from word..
529 // even pasting into a 'email version' of this widget will have to clean up that mess.
530 var cd = (e.browserEvent.clipboardData || window.clipboardData);
532 var html = cd.getData('text/html'); // clipboard event
533 var images = (new Roo.rtf.Parser())
534 .parse(cd.getData('text/rtf'))
535 .filter(function(g) { return g.type == 'pict'; })
536 .map(function(g) { return g.toDataURL(); });
539 html = this.cleanWordChars(html);
541 var d = (new DOMParser().parseFromString(html, 'text/html')).body;
544 Roo.each(d.getElementsByTagName('img'), function(img, i) {
545 img.setAttribute('src', images[i]);
548 Roo.log(cd.getData('text/rtf'));
549 Roo.log(cd.getData('text/richtext'));
551 Roo.each(cd.items, function(item) {
554 new Roo.htmleditor.FilterStyleToTag({ node : d });
555 new Roo.htmleditor.FilterAttributes({
557 attrib_white : ['href', 'src', 'name'],
558 attrib_clean : ['href', 'src', 'name']
560 new Roo.htmleditor.FilterBlack({ node : d, tag : this.black});
562 new Roo.htmleditor.FilterKeepChildren({node : d, tag : [ 'FONT' ]} );
563 new Roo.htmleditor.FilterParagraph({ node : d });
564 new Roo.htmleditor.FilterSpan({ node : d });
565 new Roo.htmleditor.FilterLongBr({ node : d });
569 this.insertAtCursor(d.innerHTML);
573 // default behaveiour should be our local cleanup paste? (optional?)
574 // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable..
575 //this.owner.fireEvent('paste', e, v);
578 onDestroy : function(){
584 //for (var i =0; i < this.toolbars.length;i++) {
585 // // fixme - ask toolbars for heights?
586 // this.toolbars[i].onDestroy();
589 //this.wrap.dom.innerHTML = '';
590 //this.wrap.remove();
595 onFirstFocus : function(){
600 this.activated = true;
603 if(Roo.isGecko){ // prevent silly gecko errors
605 var s = this.win.getSelection();
606 if(!s.focusNode || s.focusNode.nodeType != 3){
607 var r = s.getRangeAt(0);
608 r.selectNodeContents((this.doc.body || this.doc.documentElement));
613 this.execCmd('useCSS', true);
614 this.execCmd('styleWithCSS', false);
617 this.owner.fireEvent('activate', this);
621 adjustFont: function(btn){
622 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
623 //if(Roo.isSafari){ // safari
626 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
627 if(Roo.isSafari){ // safari
628 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
629 v = (v < 10) ? 10 : v;
630 v = (v > 48) ? 48 : v;
631 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
636 v = Math.max(1, v+adjust);
638 this.execCmd('FontSize', v );
641 onEditorEvent : function(e)
643 this.owner.fireEvent('editorevent', this, e);
644 // this.updateToolbar();
645 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
648 insertTag : function(tg)
650 // could be a bit smarter... -> wrap the current selected tRoo..
651 if (tg.toLowerCase() == 'span' ||
652 tg.toLowerCase() == 'code' ||
653 tg.toLowerCase() == 'sup' ||
654 tg.toLowerCase() == 'sub'
657 range = this.createRange(this.getSelection());
658 var wrappingNode = this.doc.createElement(tg.toLowerCase());
659 wrappingNode.appendChild(range.extractContents());
660 range.insertNode(wrappingNode);
667 this.execCmd("formatblock", tg);
671 insertText : function(txt)
675 var range = this.createRange();
676 range.deleteContents();
677 //alert(Sender.getAttribute('label'));
679 range.insertNode(this.doc.createTextNode(txt));
685 * Executes a Midas editor command on the editor document and performs necessary focus and
686 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
687 * @param {String} cmd The Midas command
688 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
690 relayCmd : function(cmd, value){
692 this.execCmd(cmd, value);
693 this.owner.fireEvent('editorevent', this);
694 //this.updateToolbar();
695 this.owner.deferFocus();
699 * Executes a Midas editor command directly on the editor document.
700 * For visual commands, you should use {@link #relayCmd} instead.
701 * <b>This should only be called after the editor is initialized.</b>
702 * @param {String} cmd The Midas command
703 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
705 execCmd : function(cmd, value){
706 this.doc.execCommand(cmd, false, value === undefined ? null : value);
713 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
715 * @param {String} text | dom node..
717 insertAtCursor : function(text)
724 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
728 // from jquery ui (MIT licenced)
732 if (win.getSelection && win.getSelection().getRangeAt) {
734 // delete the existing?
736 this.createRange(this.getSelection()).deleteContents();
737 range = win.getSelection().getRangeAt(0);
738 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
739 range.insertNode(node);
740 } else if (win.document.selection && win.document.selection.createRange) {
741 // no firefox support
742 var txt = typeof(text) == 'string' ? text : text.outerHTML;
743 win.document.selection.createRange().pasteHTML(txt);
745 // no firefox support
746 var txt = typeof(text) == 'string' ? text : text.outerHTML;
747 this.execCmd('InsertHTML', txt);
756 mozKeyPress : function(e){
758 var c = e.getCharCode(), cmd;
761 c = String.fromCharCode(c).toLowerCase();
775 // this.cleanUpPaste.defer(100, this);
791 fixKeys : function(){ // load time branching for fastest keydown performance
794 var k = e.getKey(), r;
797 r = this.doc.selection.createRange();
800 r.pasteHTML('    ');
807 r = this.doc.selection.createRange();
809 var target = r.parentElement();
810 if(!target || target.tagName.toLowerCase() != 'li'){
812 r.pasteHTML('<br/>');
818 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
819 // this.cleanUpPaste.defer(100, this);
825 }else if(Roo.isOpera){
831 this.execCmd('InsertHTML','    ');
834 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
835 // this.cleanUpPaste.defer(100, this);
840 }else if(Roo.isSafari){
846 this.execCmd('InsertText','\t');
850 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
851 // this.cleanUpPaste.defer(100, this);
859 getAllAncestors: function()
861 var p = this.getSelectedNode();
864 a.push(p); // push blank onto stack..
865 p = this.getParentElement();
869 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
873 a.push(this.doc.body);
880 getSelection : function()
883 return Roo.isIE ? this.doc.selection : this.win.getSelection();
887 * @param {DomElement} node the node to select
889 selectNode : function(node)
892 var nodeRange = node.ownerDocument.createRange();
894 nodeRange.selectNode(node);
896 nodeRange.selectNodeContents(node);
898 //nodeRange.collapse(true);
899 var s = this.win.getSelection();
901 s.addRange(nodeRange);
904 getSelectedNode: function()
906 // this may only work on Gecko!!!
908 // should we cache this!!!!
913 var range = this.createRange(this.getSelection()).cloneRange();
916 var parent = range.parentElement();
918 var testRange = range.duplicate();
919 testRange.moveToElementText(parent);
920 if (testRange.inRange(range)) {
923 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
926 parent = parent.parentElement;
931 // is ancestor a text element.
932 var ac = range.commonAncestorContainer;
933 if (ac.nodeType == 3) {
937 var ar = ac.childNodes;
940 var other_nodes = [];
941 var has_other_nodes = false;
942 for (var i=0;i<ar.length;i++) {
943 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
946 // fullly contained node.
948 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
953 // probably selected..
954 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
955 other_nodes.push(ar[i]);
959 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
964 has_other_nodes = true;
966 if (!nodes.length && other_nodes.length) {
969 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
975 createRange: function(sel)
977 // this has strange effects when using with
978 // top toolbar - not sure if it's a great idea.
979 //this.editor.contentWindow.focus();
980 if (typeof sel != "undefined") {
982 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
984 return this.doc.createRange();
987 return this.doc.createRange();
990 getParentElement: function()
994 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
996 var range = this.createRange(sel);
999 var p = range.commonAncestorContainer;
1000 while (p.nodeType == 3) { // text node
1011 * Range intersection.. the hard stuff...
1015 * [ -- selected range --- ]
1019 * if end is before start or hits it. fail.
1020 * if start is after end or hits it fail.
1022 * if either hits (but other is outside. - then it's not
1028 // @see http://www.thismuchiknow.co.uk/?p=64.
1029 rangeIntersectsNode : function(range, node)
1031 var nodeRange = node.ownerDocument.createRange();
1033 nodeRange.selectNode(node);
1035 nodeRange.selectNodeContents(node);
1038 var rangeStartRange = range.cloneRange();
1039 rangeStartRange.collapse(true);
1041 var rangeEndRange = range.cloneRange();
1042 rangeEndRange.collapse(false);
1044 var nodeStartRange = nodeRange.cloneRange();
1045 nodeStartRange.collapse(true);
1047 var nodeEndRange = nodeRange.cloneRange();
1048 nodeEndRange.collapse(false);
1050 return rangeStartRange.compareBoundaryPoints(
1051 Range.START_TO_START, nodeEndRange) == -1 &&
1052 rangeEndRange.compareBoundaryPoints(
1053 Range.START_TO_START, nodeStartRange) == 1;
1057 rangeCompareNode : function(range, node)
1059 var nodeRange = node.ownerDocument.createRange();
1061 nodeRange.selectNode(node);
1063 nodeRange.selectNodeContents(node);
1067 range.collapse(true);
1069 nodeRange.collapse(true);
1071 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
1072 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
1074 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
1076 var nodeIsBefore = ss == 1;
1077 var nodeIsAfter = ee == -1;
1079 if (nodeIsBefore && nodeIsAfter) {
1082 if (!nodeIsBefore && nodeIsAfter) {
1083 return 1; //right trailed.
1086 if (nodeIsBefore && !nodeIsAfter) {
1087 return 2; // left trailed.
1093 cleanWordChars : function(input) {// change the chars to hex code
1096 [ 8211, "–" ],
1097 [ 8212, "—" ],
1106 Roo.each(swapCodes, function(sw) {
1107 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
1109 output = output.replace(swapper, sw[1]);
1119 cleanUpChild : function (node)
1122 new Roo.htmleditor.FilterComment({node : node});
1123 new Roo.htmleditor.FilterAttributes({
1125 attrib_black : this.ablack,
1126 attrib_clean : this.aclean,
1127 style_white : this.cwhite,
1128 style_black : this.cblack
1130 new Roo.htmleditor.FilterBlack({ node : node, tag : this.black});
1131 new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} );
1137 * Clean up MS wordisms...
1138 * @deprecated - use filter directly
1140 cleanWord : function(node)
1142 new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
1149 * @deprecated - use filters
1151 cleanTableWidths : function(node)
1153 new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
1160 applyBlacklists : function()
1162 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
1163 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
1165 this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean : Roo.HtmlEditorCore.aclean;
1166 this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack : Roo.HtmlEditorCore.ablack;
1167 this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove : Roo.HtmlEditorCore.tag_remove;
1171 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
1172 if (b.indexOf(tag) > -1) {
1175 this.white.push(tag);
1179 Roo.each(w, function(tag) {
1180 if (b.indexOf(tag) > -1) {
1183 if (this.white.indexOf(tag) > -1) {
1186 this.white.push(tag);
1191 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
1192 if (w.indexOf(tag) > -1) {
1195 this.black.push(tag);
1199 Roo.each(b, function(tag) {
1200 if (w.indexOf(tag) > -1) {
1203 if (this.black.indexOf(tag) > -1) {
1206 this.black.push(tag);
1211 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
1212 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
1216 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
1217 if (b.indexOf(tag) > -1) {
1220 this.cwhite.push(tag);
1224 Roo.each(w, function(tag) {
1225 if (b.indexOf(tag) > -1) {
1228 if (this.cwhite.indexOf(tag) > -1) {
1231 this.cwhite.push(tag);
1236 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
1237 if (w.indexOf(tag) > -1) {
1240 this.cblack.push(tag);
1244 Roo.each(b, function(tag) {
1245 if (w.indexOf(tag) > -1) {
1248 if (this.cblack.indexOf(tag) > -1) {
1251 this.cblack.push(tag);
1256 setStylesheets : function(stylesheets)
1258 if(typeof(stylesheets) == 'string'){
1259 Roo.get(this.iframe.contentDocument.head).createChild({
1270 Roo.each(stylesheets, function(s) {
1275 Roo.get(_this.iframe.contentDocument.head).createChild({
1286 removeStylesheets : function()
1290 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
1295 setStyle : function(style)
1297 Roo.get(this.iframe.contentDocument.head).createChild({
1306 // hide stuff that is not compatible
1324 * @cfg {String} fieldClass @hide
1327 * @cfg {String} focusClass @hide
1330 * @cfg {String} autoCreate @hide
1333 * @cfg {String} inputType @hide
1336 * @cfg {String} invalidClass @hide
1339 * @cfg {String} invalidText @hide
1342 * @cfg {String} msgFx @hide
1345 * @cfg {String} validateOnBlur @hide
1349 Roo.HtmlEditorCore.white = [
1350 'AREA', 'BR', 'IMG', 'INPUT', 'HR', 'WBR',
1352 'ADDRESS', 'BLOCKQUOTE', 'CENTER', 'DD', 'DIR', 'DIV',
1353 'DL', 'DT', 'H1', 'H2', 'H3', 'H4',
1354 'H5', 'H6', 'HR', 'ISINDEX', 'LISTING', 'MARQUEE',
1355 'MENU', 'MULTICOL', 'OL', 'P', 'PLAINTEXT', 'PRE',
1356 'TABLE', 'UL', 'XMP',
1358 'CAPTION', 'COL', 'COLGROUP', 'TBODY', 'TD', 'TFOOT', 'TH',
1361 'DIR', 'MENU', 'OL', 'UL', 'DL',
1367 Roo.HtmlEditorCore.black = [
1368 // 'embed', 'object', // enable - backend responsiblity to clean thiese
1370 'BASE', 'BASEFONT', 'BGSOUND', 'BLINK', 'BODY',
1371 'FRAME', 'FRAMESET', 'HEAD', 'HTML', 'ILAYER',
1372 'IFRAME', 'LAYER', 'LINK', 'META', 'OBJECT',
1373 'SCRIPT', 'STYLE' ,'TITLE', 'XML',
1374 //'FONT' // CLEAN LATER..
1375 'COLGROUP', 'COL' // messy tables.
1378 Roo.HtmlEditorCore.clean = [ // ?? needed???
1379 'SCRIPT', 'STYLE', 'TITLE', 'XML'
1381 Roo.HtmlEditorCore.tag_remove = [
1386 Roo.HtmlEditorCore.ablack = [
1390 Roo.HtmlEditorCore.aclean = [
1391 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
1395 Roo.HtmlEditorCore.pwhite= [
1396 'http', 'https', 'mailto'
1399 // white listed style attributes.
1400 Roo.HtmlEditorCore.cwhite= [
1401 // 'text-align', /// default is to allow most things..
1407 // black listed style attributes.
1408 Roo.HtmlEditorCore.cblack= [
1409 // 'font-size' -- this can be set by the project