roojs-all.js
[roojs1] / Roo / HtmlEditorCore.js
index 626069d..733d91f 100644 (file)
@@ -72,6 +72,7 @@ Roo.HtmlEditorCore = function(config){
          * @param {Roo.HtmlEditorCore} this
          */
         editorevent: true
+        
     });
     
     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
@@ -132,7 +133,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     black: false,
     white: false,
      
-    
+    bodyCls : '',
 
     /**
      * Protected method that will not generally be called directly. It
@@ -142,7 +143,6 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     getDocMarkup : function(){
         // body styles..
         var st = '';
-        Roo.log(this.stylesheets);
         
         // inherit styels from page...?? 
         if (this.stylesheets === false) {
@@ -160,23 +160,27 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                 st = '<style type="text/css">' +
                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
                    '</style>';
-        } else {
-            Roo.each(this.stylesheets, function(s) {
-                st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
-            });
-            
+        } else { 
+            st = '<style type="text/css">' +
+                    this.stylesheets +
+                '</style>';
         }
         
         st +=  '<style type="text/css">' +
             'IMG { cursor: pointer } ' +
         '</style>';
 
+        var cls = 'roo-htmleditor-body';
+        
+        if(this.bodyCls.length){
+            cls += ' ' + this.bodyCls;
+        }
         
         return '<html><head>' + st  +
             //<style type="text/css">' +
             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
             //'</style>' +
-            ' </head><body class="roo-htmleditor-body"></body></html>';
+            ' </head><body class="' +  cls + '"></body></html>';
     },
 
     // private
@@ -244,8 +248,6 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         };
         Roo.TaskMgr.start(task);
 
-        
-         
     },
 
     // private
@@ -333,17 +335,32 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             html = this.cleanHtml(html);
             // fix up the special chars.. normaly like back quotes in word...
             // however we do not want to do this with chinese..
-            html = html.replace(/([\x80-\uffff])/g, function (a, b) {
-                var cc = b.charCodeAt();
-                if (
+            html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
+                
+                var cc = match.charCodeAt();
+
+                // Get the character value, handling surrogate pairs
+                if (match.length == 2) {
+                    // It's a surrogate pair, calculate the Unicode code point
+                    var high = match.charCodeAt(0) - 0xD800;
+                    var low  = match.charCodeAt(1) - 0xDC00;
+                    cc = (high * 0x400) + low + 0x10000;
+                }  else if (
                     (cc >= 0x4E00 && cc < 0xA000 ) ||
                     (cc >= 0x3400 && cc < 0x4E00 ) ||
                     (cc >= 0xf900 && cc < 0xfb00 )
                 ) {
-                        return b;
-                }
-                return "&#"+cc+";" 
+                        return match;
+                }  
+         
+                // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
+                return "&#" + cc + ";";
+                
+                
             });
+            
+            
+             
             if(this.owner.fireEvent('beforesync', this, html) !== false){
                 this.el.dom.value = html;
                 this.owner.fireEvent('sync', this, html);
@@ -517,7 +534,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         this.execCmd('FontSize', v  );
     },
 
-    onEditorEvent : function(e){
+    onEditorEvent : function(e)
+    {
         this.owner.fireEvent('editorevent', this, e);
       //  this.updateToolbar();
         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
@@ -591,8 +609,6 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     insertAtCursor : function(text)
     {
         
-        
-        
         if(!this.activated){
             return;
         }
@@ -943,13 +959,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         var nodeIsBefore   =  ss == 1;
         var nodeIsAfter    = ee == -1;
         
-        if (nodeIsBefore && nodeIsAfter)
+        if (nodeIsBefore && nodeIsAfter) {
             return 0; // outer
-        if (!nodeIsBefore && nodeIsAfter)
+        }
+        if (!nodeIsBefore && nodeIsAfter) {
             return 1; //right trailed.
+        }
         
-        if (nodeIsBefore && !nodeIsAfter)
+        if (nodeIsBefore && !nodeIsAfter) {
             return 2;  // left trailed.
+        }
         // fully contined.
         return 3;
     },
@@ -1008,8 +1027,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             // clean up silly Windows -- stuff?
             return; 
         }
+        var lcname = node.tagName.toLowerCase();
+        // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
+        // whitelist of tags..
         
-        if (this.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
+        if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
             // remove node.
             node.parentNode.removeChild(node);
             return;
@@ -1018,6 +1040,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
         
+        // spans with no attributes - just remove them..
+        if ((!node.attributes || !node.attributes.length) && lcname == 'span') { 
+            remove_keep_children = true;
+        }
+        
         // remove <a name=....> as rendering on yahoo mailer is borked with this.
         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
         
@@ -1038,6 +1065,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         }
         
         if (!node.attributes || !node.attributes.length) {
+            
+          
+            
+            
             this.cleanUpChildren(node);
             return;
         }
@@ -1048,7 +1079,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             if (v.match(/^\./) || v.match(/^\//)) {
                 return;
             }
-            if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
+            if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
                 return;
             }
             if (v.match(/^#/)) {
@@ -1059,15 +1090,15 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             
         }
         
+        var cwhite = this.cwhite;
+        var cblack = this.cblack;
+            
         function cleanStyle(n,v)
         {
             if (v.match(/expression/)) { //XSS?? should we even bother..
                 node.removeAttribute(n);
                 return;
             }
-            var cwhite = typeof(ed.cwhite) != 'undefined' && ed.cwhite !== false ? ed.cwhite : Roo.HtmlEditorCore.cwhite;
-            var cblack = typeof(ed.cblack) != 'undefined' && ed.cwhite !== false ? ed.cblack : Roo.HtmlEditorCore.cblack;
-            
             
             var parts = v.split(/;/);
             var clean = [];
@@ -1080,7 +1111,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                 var l = p.split(':').shift().replace(/\s+/g,'');
                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
                 
-                if ( cblack.indexOf(l) > -1) {
+                if ( cwhite.length && cblack.indexOf(l) > -1) {
 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
                     //node.removeAttribute(n);
                     return true;
@@ -1137,7 +1168,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                     node.className = '';
                 }
                 
-                if (a.value.match(/body/)) {
+                if (a.value.match(/^body$/)) {
                     node.className = '';
                 }
                 continue;
@@ -1153,27 +1184,35 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         
     },
+    
     /**
      * Clean up MS wordisms...
      */
     cleanWord : function(node)
     {
-        var _t = this;
-        var cleanWordChildren = function()
-        {
-            if (!node.childNodes.length) {
-                return;
-            }
-            for (var i = node.childNodes.length-1; i > -1 ; i--) {
-               _t.cleanWord(node.childNodes[i]);
-            }
-        }
-        
-        
         if (!node) {
             this.cleanWord(this.doc.body);
             return;
         }
+        
+        if(
+                node.nodeName == 'SPAN' &&
+                !node.hasAttributes() &&
+                node.childNodes.length == 1 &&
+                node.firstChild.nodeName == "#text"  
+        ) {
+            var textNode = node.firstChild;
+            node.removeChild(textNode);
+            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
+                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
+            }
+            node.parentNode.insertBefore(textNode, node);
+            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
+                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
+            }
+            node.parentNode.removeChild(node);
+        }
+        
         if (node.nodeName == "#text") {
             // clean up silly Windows -- stuff?
             return; 
@@ -1197,7 +1236,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                 node.parentNode.insertBefore(cn, node);
             }
             node.parentNode.removeChild(node);
-            cleanWordChildren();
+            this.iterateChildren(node, this.cleanWord);
             return;
         }
         // clean styles
@@ -1241,206 +1280,334 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                 node.removeAttribute('style');
             }
         }
+        this.iterateChildren(node, this.cleanWord);
         
-        cleanWordChildren();
         
         
     },
-    domToHTML : function(currentElement, depth, nopadtext) {
+    /**
+     * iterateChildren of a Node, calling fn each time, using this as the scole..
+     * @param {DomNode} node node to iterate children of.
+     * @param {Function} fn method of this class to call on each item.
+     */
+    iterateChildren : function(node, fn)
+    {
+        if (!node.childNodes.length) {
+                return;
+        }
+        for (var i = node.childNodes.length-1; i > -1 ; i--) {
+           fn.call(this, node.childNodes[i])
+        }
+    },
+    
+    
+    /**
+     * cleanTableWidths.
+     *
+     * Quite often pasting from word etc.. results in tables with column and widths.
+     * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
+     *
+     */
+    cleanTableWidths : function(node)
+    {
+         
+         
+        if (!node) {
+            this.cleanTableWidths(this.doc.body);
+            return;
+        }
         
-            depth = depth || 0;
-            nopadtext = nopadtext || false;
+        // ignore list...
+        if (node.nodeName == "#text" || node.nodeName == "#comment") {
+            return; 
+        }
+        Roo.log(node.tagName);
+        if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
+            this.iterateChildren(node, this.cleanTableWidths);
+            return;
+        }
+        if (node.hasAttribute('width')) {
+            node.removeAttribute('width');
+        }
         
-            if (!currentElement) {
-                return this.domToHTML(this.doc.body);
-            }
-            
-            //Roo.log(currentElement);
-            var j;
-            var allText = false;
-            var nodeName = currentElement.nodeName;
-            var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
+         
+        if (node.hasAttribute("style")) {
+            // pretty basic...
             
-            if  (nodeName == '#text') {
-                return currentElement.nodeValue;
+            var styles = node.getAttribute("style").split(";");
+            var nstyle = [];
+            Roo.each(styles, function(s) {
+                if (!s.match(/:/)) {
+                    return;
+                }
+                var kv = s.split(":");
+                if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
+                    return;
+                }
+                // what ever is left... we allow.
+                nstyle.push(s);
+            });
+            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
+            if (!nstyle.length) {
+                node.removeAttribute('style');
             }
+        }
+        
+        this.iterateChildren(node, this.cleanTableWidths);
+        
+        
+    },
+    
+    
+    
+    
+    domToHTML : function(currentElement, depth, nopadtext) {
+        
+        depth = depth || 0;
+        nopadtext = nopadtext || false;
+    
+        if (!currentElement) {
+            return this.domToHTML(this.doc.body);
+        }
+        
+        //Roo.log(currentElement);
+        var j;
+        var allText = false;
+        var nodeName = currentElement.nodeName;
+        var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
+        
+        if  (nodeName == '#text') {
             
-            
-            var ret = '';
-            if (nodeName != 'BODY') {
-                 
-                var i = 0;
-                // Prints the node tagName, such as <A>, <IMG>, etc
-                if (tagName) {
-                    var attr = [];
-                    for(i = 0; i < currentElement.attributes.length;i++) {
-                        // quoting?
-                        var aname = currentElement.attributes.item(i).name;
-                        if (!currentElement.attributes.item(i).value.length) {
-                            continue;
-                        }
-                        attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
+            return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
+        }
+        
+        
+        var ret = '';
+        if (nodeName != 'BODY') {
+             
+            var i = 0;
+            // Prints the node tagName, such as <A>, <IMG>, etc
+            if (tagName) {
+                var attr = [];
+                for(i = 0; i < currentElement.attributes.length;i++) {
+                    // quoting?
+                    var aname = currentElement.attributes.item(i).name;
+                    if (!currentElement.attributes.item(i).value.length) {
+                        continue;
                     }
-                    
-                    ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
-                } 
-                else {
-                    
-                    // eack
+                    attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
                 }
-            } else {
-                tagName = false;
-            }
-            if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
-                return ret;
+                
+                ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
+            } 
+            else {
+                
+                // eack
             }
-            if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
-                nopadtext = true;
+        } else {
+            tagName = false;
+        }
+        if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
+            return ret;
+        }
+        if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
+            nopadtext = true;
+        }
+        
+        
+        // Traverse the tree
+        i = 0;
+        var currentElementChild = currentElement.childNodes.item(i);
+        var allText = true;
+        var innerHTML  = '';
+        lastnode = '';
+        while (currentElementChild) {
+            // Formatting code (indent the tree so it looks nice on the screen)
+            var nopad = nopadtext;
+            if (lastnode == 'SPAN') {
+                nopad  = true;
             }
-            
-            
-            // Traverse the tree
-            i = 0;
-            var currentElementChild = currentElement.childNodes.item(i);
-            var allText = true;
-            var innerHTML  = '';
-            lastnode = '';
-            while (currentElementChild) {
-                // Formatting code (indent the tree so it looks nice on the screen)
-                var nopad = nopadtext;
-                if (lastnode == 'SPAN') {
-                    nopad  = true;
-                }
-                // text
-                if  (currentElementChild.nodeName == '#text') {
-                    var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
-                    if (!nopad && toadd.length > 80) {
-                        innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
-                    }
-                    innerHTML  += toadd;
-                    
-                    i++;
-                    currentElementChild = currentElement.childNodes.item(i);
-                    lastNode = '';
-                    continue;
+            // text
+            if  (currentElementChild.nodeName == '#text') {
+                var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
+                toadd = nopadtext ? toadd : toadd.trim();
+                if (!nopad && toadd.length > 80) {
+                    innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
                 }
-                allText = false;
+                innerHTML  += toadd;
                 
-                innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
-                    
-                // Recursively traverse the tree structure of the child node
-                innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
-                lastnode = currentElementChild.nodeName;
                 i++;
-                currentElementChild=currentElement.childNodes.item(i);
+                currentElementChild = currentElement.childNodes.item(i);
+                lastNode = '';
+                continue;
             }
+            allText = false;
             
-            ret += innerHTML;
-            
-            if (!allText) {
-                    // The remaining code is mostly for formatting the tree
-                ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
+            innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
+                
+            // Recursively traverse the tree structure of the child node
+            innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
+            lastnode = currentElementChild.nodeName;
+            i++;
+            currentElementChild=currentElement.childNodes.item(i);
+        }
+        
+        ret += innerHTML;
+        
+        if (!allText) {
+                // The remaining code is mostly for formatting the tree
+            ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
+        }
+        
+        
+        if (tagName) {
+            ret+= "</"+tagName+">";
+        }
+        return ret;
+        
+    },
+        
+    applyBlacklists : function()
+    {
+        var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
+        var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
+        
+        this.white = [];
+        this.black = [];
+        Roo.each(Roo.HtmlEditorCore.white, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
             }
+            this.white.push(tag);
             
-            
-            if (tagName) {
-                ret+= "</"+tagName+">";
+        }, this);
+        
+        Roo.each(w, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
             }
-            return ret;
+            if (this.white.indexOf(tag) > -1) {
+                return;
+            }
+            this.white.push(tag);
             
-        },
+        }, this);
         
-        applyBlacklists : function()
-        {
-            var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
-            var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
-            
-            this.white = [];
-            this.black = [];
-            Roo.each(Roo.HtmlEditorCore.white, function(tag) {
-                if (b.indexOf(tag) > -1) {
-                    return;
-                }
-                this.white.push(tag);
-                
-            }, this);
-            
-            Roo.each(w, function(tag) {
-                if (b.indexOf(tag) > -1) {
-                    return;
-                }
-                if (this.white.indexOf(tag) > -1) {
-                    return;
-                }
-                this.white.push(tag);
-                
-            }, this);
-            
-            
-            Roo.each(Roo.HtmlEditorCore.black, function(tag) {
-                if (w.indexOf(tag) > -1) {
-                    return;
-                }
-                this.black.push(tag);
-                
-            }, this);
-            
-            Roo.each(b, function(tag) {
-                if (w.indexOf(tag) > -1) {
-                    return;
-                }
-                if (this.black.indexOf(tag) > -1) {
-                    return;
-                }
-                this.black.push(tag);
-                
-            }, this);
+        
+        Roo.each(Roo.HtmlEditorCore.black, function(tag) {
+            if (w.indexOf(tag) > -1) {
+                return;
+            }
+            this.black.push(tag);
             
+        }, this);
+        
+        Roo.each(b, function(tag) {
+            if (w.indexOf(tag) > -1) {
+                return;
+            }
+            if (this.black.indexOf(tag) > -1) {
+                return;
+            }
+            this.black.push(tag);
             
-            w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
-            b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
+        }, this);
+        
+        
+        w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
+        b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
+        
+        this.cwhite = [];
+        this.cblack = [];
+        Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
+            }
+            this.cwhite.push(tag);
             
-            this.cwhite = [];
-            this.cblack = [];
-            Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
-                if (b.indexOf(tag) > -1) {
-                    return;
-                }
-                this.cwhite.push(tag);
-                
-            }, this);
+        }, this);
+        
+        Roo.each(w, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
+            }
+            if (this.cwhite.indexOf(tag) > -1) {
+                return;
+            }
+            this.cwhite.push(tag);
             
-            Roo.each(w, function(tag) {
-                if (b.indexOf(tag) > -1) {
-                    return;
-                }
-                if (this.cwhite.indexOf(tag) > -1) {
-                    return;
-                }
-                this.cwhite.push(tag);
-                
-            }, this);
+        }, this);
+        
+        
+        Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
+            if (w.indexOf(tag) > -1) {
+                return;
+            }
+            this.cblack.push(tag);
             
+        }, this);
+        
+        Roo.each(b, function(tag) {
+            if (w.indexOf(tag) > -1) {
+                return;
+            }
+            if (this.cblack.indexOf(tag) > -1) {
+                return;
+            }
+            this.cblack.push(tag);
             
-            Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
-                if (w.indexOf(tag) > -1) {
-                    return;
-                }
-                this.cblack.push(tag);
-                
-            }, this);
+        }, this);
+    },
+    
+    setStylesheets : function(stylesheets)
+    {
+        if(typeof(stylesheets) == 'string'){
+            Roo.get(this.iframe.contentDocument.head).createChild({
+                tag : 'link',
+                rel : 'stylesheet',
+                type : 'text/css',
+                href : stylesheets
+            });
             
-            Roo.each(b, function(tag) {
-                if (w.indexOf(tag) > -1) {
-                    return;
-                }
-                if (this.cblack.indexOf(tag) > -1) {
-                    return;
-                }
-                this.cblack.push(tag);
-                
-            }, this);
+            return;
         }
+        var _this = this;
+     
+        Roo.each(stylesheets, function(s) {
+            if(!s.length){
+                return;
+            }
+            
+            Roo.get(_this.iframe.contentDocument.head).createChild({
+                tag : 'link',
+                rel : 'stylesheet',
+                type : 'text/css',
+                href : s
+            });
+        });
+
+        
+    },
+    
+    removeStylesheets : function()
+    {
+        var _this = this;
+        
+        Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
+            s.remove();
+        });
+    },
+    
+    setStyle : function(style)
+    {
+        Roo.get(this.iframe.contentDocument.head).createChild({
+            tag : 'style',
+            type : 'text/css',
+            html : style
+        });
+
+        return;
+    }
     
     // hide stuff that is not compatible
     /**