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;
543 if (images.length > 0) {
544 Roo.each(d.getElementsByTagName('img'), function(img, i) {
545 img.setAttribute('src', images[i]);
550 Roo.log(cd.getData('text/rtf'));
551 Roo.log(cd.getData('text/richtext'));
553 Roo.each(cd.items, function(item) {
556 new Roo.htmleditor.FilterStyleToTag({ node : d });
557 new Roo.htmleditor.FilterAttributes({
559 attrib_white : ['href', 'src', 'name'],
560 attrib_clean : ['href', 'src', 'name']
562 new Roo.htmleditor.FilterBlack({ node : d, tag : this.black});
564 new Roo.htmleditor.FilterKeepChildren({node : d, tag : [ 'FONT' ]} );
565 new Roo.htmleditor.FilterParagraph({ node : d });
566 new Roo.htmleditor.FilterSpan({ node : d });
567 new Roo.htmleditor.FilterLongBr({ node : d });
571 this.insertAtCursor(d.innerHTML);
575 // default behaveiour should be our local cleanup paste? (optional?)
576 // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable..
577 //this.owner.fireEvent('paste', e, v);
580 onDestroy : function(){
586 //for (var i =0; i < this.toolbars.length;i++) {
587 // // fixme - ask toolbars for heights?
588 // this.toolbars[i].onDestroy();
591 //this.wrap.dom.innerHTML = '';
592 //this.wrap.remove();
597 onFirstFocus : function(){
602 this.activated = true;
605 if(Roo.isGecko){ // prevent silly gecko errors
607 var s = this.win.getSelection();
608 if(!s.focusNode || s.focusNode.nodeType != 3){
609 var r = s.getRangeAt(0);
610 r.selectNodeContents((this.doc.body || this.doc.documentElement));
615 this.execCmd('useCSS', true);
616 this.execCmd('styleWithCSS', false);
619 this.owner.fireEvent('activate', this);
623 adjustFont: function(btn){
624 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
625 //if(Roo.isSafari){ // safari
628 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
629 if(Roo.isSafari){ // safari
630 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
631 v = (v < 10) ? 10 : v;
632 v = (v > 48) ? 48 : v;
633 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
638 v = Math.max(1, v+adjust);
640 this.execCmd('FontSize', v );
643 onEditorEvent : function(e)
645 this.owner.fireEvent('editorevent', this, e);
646 // this.updateToolbar();
647 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
650 insertTag : function(tg)
652 // could be a bit smarter... -> wrap the current selected tRoo..
653 if (tg.toLowerCase() == 'span' ||
654 tg.toLowerCase() == 'code' ||
655 tg.toLowerCase() == 'sup' ||
656 tg.toLowerCase() == 'sub'
659 range = this.createRange(this.getSelection());
660 var wrappingNode = this.doc.createElement(tg.toLowerCase());
661 wrappingNode.appendChild(range.extractContents());
662 range.insertNode(wrappingNode);
669 this.execCmd("formatblock", tg);
673 insertText : function(txt)
677 var range = this.createRange();
678 range.deleteContents();
679 //alert(Sender.getAttribute('label'));
681 range.insertNode(this.doc.createTextNode(txt));
687 * Executes a Midas editor command on the editor document and performs necessary focus and
688 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
689 * @param {String} cmd The Midas command
690 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
692 relayCmd : function(cmd, value){
694 this.execCmd(cmd, value);
695 this.owner.fireEvent('editorevent', this);
696 //this.updateToolbar();
697 this.owner.deferFocus();
701 * Executes a Midas editor command directly on the editor document.
702 * For visual commands, you should use {@link #relayCmd} instead.
703 * <b>This should only be called after the editor is initialized.</b>
704 * @param {String} cmd The Midas command
705 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
707 execCmd : function(cmd, value){
708 this.doc.execCommand(cmd, false, value === undefined ? null : value);
715 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
717 * @param {String} text | dom node..
719 insertAtCursor : function(text)
726 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
730 // from jquery ui (MIT licenced)
734 if (win.getSelection && win.getSelection().getRangeAt) {
736 // delete the existing?
738 this.createRange(this.getSelection()).deleteContents();
739 range = win.getSelection().getRangeAt(0);
740 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
741 range.insertNode(node);
742 } else if (win.document.selection && win.document.selection.createRange) {
743 // no firefox support
744 var txt = typeof(text) == 'string' ? text : text.outerHTML;
745 win.document.selection.createRange().pasteHTML(txt);
747 // no firefox support
748 var txt = typeof(text) == 'string' ? text : text.outerHTML;
749 this.execCmd('InsertHTML', txt);
758 mozKeyPress : function(e){
760 var c = e.getCharCode(), cmd;
763 c = String.fromCharCode(c).toLowerCase();
777 // this.cleanUpPaste.defer(100, this);
793 fixKeys : function(){ // load time branching for fastest keydown performance
796 var k = e.getKey(), r;
799 r = this.doc.selection.createRange();
802 r.pasteHTML('    ');
809 r = this.doc.selection.createRange();
811 var target = r.parentElement();
812 if(!target || target.tagName.toLowerCase() != 'li'){
814 r.pasteHTML('<br/>');
820 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
821 // this.cleanUpPaste.defer(100, this);
827 }else if(Roo.isOpera){
833 this.execCmd('InsertHTML','    ');
836 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
837 // this.cleanUpPaste.defer(100, this);
842 }else if(Roo.isSafari){
848 this.execCmd('InsertText','\t');
852 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
853 // this.cleanUpPaste.defer(100, this);
861 getAllAncestors: function()
863 var p = this.getSelectedNode();
866 a.push(p); // push blank onto stack..
867 p = this.getParentElement();
871 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
875 a.push(this.doc.body);
882 getSelection : function()
885 return Roo.isIE ? this.doc.selection : this.win.getSelection();
889 * @param {DomElement} node the node to select
891 selectNode : function(node)
894 var nodeRange = node.ownerDocument.createRange();
896 nodeRange.selectNode(node);
898 nodeRange.selectNodeContents(node);
900 //nodeRange.collapse(true);
901 var s = this.win.getSelection();
903 s.addRange(nodeRange);
906 getSelectedNode: function()
908 // this may only work on Gecko!!!
910 // should we cache this!!!!
915 var range = this.createRange(this.getSelection()).cloneRange();
918 var parent = range.parentElement();
920 var testRange = range.duplicate();
921 testRange.moveToElementText(parent);
922 if (testRange.inRange(range)) {
925 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
928 parent = parent.parentElement;
933 // is ancestor a text element.
934 var ac = range.commonAncestorContainer;
935 if (ac.nodeType == 3) {
939 var ar = ac.childNodes;
942 var other_nodes = [];
943 var has_other_nodes = false;
944 for (var i=0;i<ar.length;i++) {
945 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
948 // fullly contained node.
950 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
955 // probably selected..
956 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
957 other_nodes.push(ar[i]);
961 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
966 has_other_nodes = true;
968 if (!nodes.length && other_nodes.length) {
971 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
977 createRange: function(sel)
979 // this has strange effects when using with
980 // top toolbar - not sure if it's a great idea.
981 //this.editor.contentWindow.focus();
982 if (typeof sel != "undefined") {
984 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
986 return this.doc.createRange();
989 return this.doc.createRange();
992 getParentElement: function()
996 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
998 var range = this.createRange(sel);
1001 var p = range.commonAncestorContainer;
1002 while (p.nodeType == 3) { // text node
1013 * Range intersection.. the hard stuff...
1017 * [ -- selected range --- ]
1021 * if end is before start or hits it. fail.
1022 * if start is after end or hits it fail.
1024 * if either hits (but other is outside. - then it's not
1030 // @see http://www.thismuchiknow.co.uk/?p=64.
1031 rangeIntersectsNode : function(range, node)
1033 var nodeRange = node.ownerDocument.createRange();
1035 nodeRange.selectNode(node);
1037 nodeRange.selectNodeContents(node);
1040 var rangeStartRange = range.cloneRange();
1041 rangeStartRange.collapse(true);
1043 var rangeEndRange = range.cloneRange();
1044 rangeEndRange.collapse(false);
1046 var nodeStartRange = nodeRange.cloneRange();
1047 nodeStartRange.collapse(true);
1049 var nodeEndRange = nodeRange.cloneRange();
1050 nodeEndRange.collapse(false);
1052 return rangeStartRange.compareBoundaryPoints(
1053 Range.START_TO_START, nodeEndRange) == -1 &&
1054 rangeEndRange.compareBoundaryPoints(
1055 Range.START_TO_START, nodeStartRange) == 1;
1059 rangeCompareNode : function(range, node)
1061 var nodeRange = node.ownerDocument.createRange();
1063 nodeRange.selectNode(node);
1065 nodeRange.selectNodeContents(node);
1069 range.collapse(true);
1071 nodeRange.collapse(true);
1073 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
1074 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
1076 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
1078 var nodeIsBefore = ss == 1;
1079 var nodeIsAfter = ee == -1;
1081 if (nodeIsBefore && nodeIsAfter) {
1084 if (!nodeIsBefore && nodeIsAfter) {
1085 return 1; //right trailed.
1088 if (nodeIsBefore && !nodeIsAfter) {
1089 return 2; // left trailed.
1095 cleanWordChars : function(input) {// change the chars to hex code
1098 [ 8211, "–" ],
1099 [ 8212, "—" ],
1108 Roo.each(swapCodes, function(sw) {
1109 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
1111 output = output.replace(swapper, sw[1]);
1121 cleanUpChild : function (node)
1124 new Roo.htmleditor.FilterComment({node : node});
1125 new Roo.htmleditor.FilterAttributes({
1127 attrib_black : this.ablack,
1128 attrib_clean : this.aclean,
1129 style_white : this.cwhite,
1130 style_black : this.cblack
1132 new Roo.htmleditor.FilterBlack({ node : node, tag : this.black});
1133 new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} );
1139 * Clean up MS wordisms...
1140 * @deprecated - use filter directly
1142 cleanWord : function(node)
1144 new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
1151 * @deprecated - use filters
1153 cleanTableWidths : function(node)
1155 new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
1162 applyBlacklists : function()
1164 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
1165 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
1167 this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean : Roo.HtmlEditorCore.aclean;
1168 this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack : Roo.HtmlEditorCore.ablack;
1169 this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove : Roo.HtmlEditorCore.tag_remove;
1173 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
1174 if (b.indexOf(tag) > -1) {
1177 this.white.push(tag);
1181 Roo.each(w, function(tag) {
1182 if (b.indexOf(tag) > -1) {
1185 if (this.white.indexOf(tag) > -1) {
1188 this.white.push(tag);
1193 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
1194 if (w.indexOf(tag) > -1) {
1197 this.black.push(tag);
1201 Roo.each(b, function(tag) {
1202 if (w.indexOf(tag) > -1) {
1205 if (this.black.indexOf(tag) > -1) {
1208 this.black.push(tag);
1213 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
1214 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
1218 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
1219 if (b.indexOf(tag) > -1) {
1222 this.cwhite.push(tag);
1226 Roo.each(w, function(tag) {
1227 if (b.indexOf(tag) > -1) {
1230 if (this.cwhite.indexOf(tag) > -1) {
1233 this.cwhite.push(tag);
1238 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
1239 if (w.indexOf(tag) > -1) {
1242 this.cblack.push(tag);
1246 Roo.each(b, function(tag) {
1247 if (w.indexOf(tag) > -1) {
1250 if (this.cblack.indexOf(tag) > -1) {
1253 this.cblack.push(tag);
1258 setStylesheets : function(stylesheets)
1260 if(typeof(stylesheets) == 'string'){
1261 Roo.get(this.iframe.contentDocument.head).createChild({
1272 Roo.each(stylesheets, function(s) {
1277 Roo.get(_this.iframe.contentDocument.head).createChild({
1288 removeStylesheets : function()
1292 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
1297 setStyle : function(style)
1299 Roo.get(this.iframe.contentDocument.head).createChild({
1308 // hide stuff that is not compatible
1326 * @cfg {String} fieldClass @hide
1329 * @cfg {String} focusClass @hide
1332 * @cfg {String} autoCreate @hide
1335 * @cfg {String} inputType @hide
1338 * @cfg {String} invalidClass @hide
1341 * @cfg {String} invalidText @hide
1344 * @cfg {String} msgFx @hide
1347 * @cfg {String} validateOnBlur @hide
1351 Roo.HtmlEditorCore.white = [
1352 'AREA', 'BR', 'IMG', 'INPUT', 'HR', 'WBR',
1354 'ADDRESS', 'BLOCKQUOTE', 'CENTER', 'DD', 'DIR', 'DIV',
1355 'DL', 'DT', 'H1', 'H2', 'H3', 'H4',
1356 'H5', 'H6', 'HR', 'ISINDEX', 'LISTING', 'MARQUEE',
1357 'MENU', 'MULTICOL', 'OL', 'P', 'PLAINTEXT', 'PRE',
1358 'TABLE', 'UL', 'XMP',
1360 'CAPTION', 'COL', 'COLGROUP', 'TBODY', 'TD', 'TFOOT', 'TH',
1363 'DIR', 'MENU', 'OL', 'UL', 'DL',
1369 Roo.HtmlEditorCore.black = [
1370 // 'embed', 'object', // enable - backend responsiblity to clean thiese
1372 'BASE', 'BASEFONT', 'BGSOUND', 'BLINK', 'BODY',
1373 'FRAME', 'FRAMESET', 'HEAD', 'HTML', 'ILAYER',
1374 'IFRAME', 'LAYER', 'LINK', 'META', 'OBJECT',
1375 'SCRIPT', 'STYLE' ,'TITLE', 'XML',
1376 //'FONT' // CLEAN LATER..
1377 'COLGROUP', 'COL' // messy tables.
1380 Roo.HtmlEditorCore.clean = [ // ?? needed???
1381 'SCRIPT', 'STYLE', 'TITLE', 'XML'
1383 Roo.HtmlEditorCore.tag_remove = [
1388 Roo.HtmlEditorCore.ablack = [
1392 Roo.HtmlEditorCore.aclean = [
1393 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
1397 Roo.HtmlEditorCore.pwhite= [
1398 'http', 'https', 'mailto'
1401 // white listed style attributes.
1402 Roo.HtmlEditorCore.cwhite= [
1403 // 'text-align', /// default is to allow most things..
1409 // black listed style attributes.
1410 Roo.HtmlEditorCore.cblack= [
1411 // 'font-size' -- this can be set by the project