/*
This file is part of Ext JS 3.4

Copyright (c) 2011-2013 Sencha Inc

Contact:  http://www.sencha.com/contact

GNU General Public License Usage
This file may be used under the terms of the GNU General Public License version 3.0 as
published by the Free Software Foundation and appearing in the file LICENSE included in the
packaging of this file.

Please review the following information to ensure the GNU General Public License version 3.0
requirements will be met: http://www.gnu.org/copyleft/gpl.html.

If you are unsure which license is appropriate for your use, please contact the sales department
at http://www.sencha.com/contact.

Build date: 2013-04-03 15:07:25
*/
Ext.debug = {};

(function(){

var cp;

function createConsole(){

    var scriptPanel = new Ext.debug.ScriptsPanel();
    var logView = new Ext.debug.LogPanel();
    var tree = new Ext.debug.DomTree();
    var compInspector = new Ext.debug.ComponentInspector();
    var compInfoPanel = new Ext.debug.ComponentInfoPanel();
    var storeInspector = new Ext.debug.StoreInspector();
    var objInspector = new Ext.debug.ObjectInspector();

    var tabs = new Ext.TabPanel({
        activeTab: 0,
        border: false,
        tabPosition: 'bottom',
        items: [{
            title: 'Debug Console',
            layout:'border',
            items: [logView, scriptPanel]
        },{
            title: 'HTML Inspector',
            layout:'border',
            items: [tree]
        },{
            title: 'Component Inspector',
            layout: 'border',
            items: [compInspector,compInfoPanel]
        },{
            title: 'Object Inspector',
            layout: 'border',
            items: [objInspector]
        },{
            title: 'Data Stores',
            layout: 'border',
            items: [storeInspector]
        }]
    });

    cp = new Ext.Panel({
        id: 'x-debug-browser',
        title: 'Console',
        collapsible: true,
        animCollapse: false,
        style: 'position:absolute;left:0;bottom:0;z-index:101',
        height:200,
        logView: logView,
        layout: 'fit',

        tools:[{
            id: 'close',
            handler: function(){
                cp.destroy();
                cp = null;
                Ext.EventManager.removeResizeListener(handleResize);
            }
        }],

        items: tabs
    });

    cp.render(Ext.getBody());

    cp.resizer = new Ext.Resizable(cp.el, {
        minHeight:50,
        handles: "n",
        pinned: true,
        transparent:true,
        resizeElement : function(){
            var box = this.proxy.getBox();
            this.proxy.hide();
            cp.setHeight(box.height);
            return box;
        }
    });

//     function handleResize(){
//         cp.setWidth(Ext.getBody().getViewSize().width);
//     }
//     Ext.EventManager.onWindowResize(handleResize);
//
//     handleResize();

    function handleResize(){
        var b = Ext.getBody();
        var size = b.getViewSize();
        if(size.height < b.dom.scrollHeight) {
            size.width -= 18;
        }
        cp.setWidth(size.width);
    }
    Ext.EventManager.onWindowResize(handleResize);
    handleResize();
}


Ext.apply(Ext, {
    log : function(){
        if(!cp){
            createConsole();
        }
        cp.logView.log.apply(cp.logView, arguments);
    },

    logf : function(format, arg1, arg2, etc){
        Ext.log(String.format.apply(String, arguments));
    },

    dump : function(o){
        if(typeof o == 'string' || typeof o == 'number' || typeof o == 'undefined' || Ext.isDate(o)){
            Ext.log(o);
        }else if(!o){
            Ext.log("null");
        }else if(typeof o != "object"){
            Ext.log('Unknown return type');
        }else if(Ext.isArray(o)){
            Ext.log('['+o.join(',')+']');
        }else{
            var b = ["{\n"];
            for(var key in o){
                var to = typeof o[key];
                if(to != "function" && to != "object"){
                    b.push(String.format("  {0}: {1},\n", key, o[key]));
                }
            }
            var s = b.join("");
            if(s.length > 3){
                s = s.substr(0, s.length-2);
            }
            Ext.log(s + "\n}");
        }
    },

    _timers : {},

    time : function(name){
        name = name || "def";
        Ext._timers[name] = new Date().getTime();
    },

    timeEnd : function(name, printResults){
        var t = new Date().getTime();
        name = name || "def";
        var v = String.format("{0} ms", t-Ext._timers[name]);
        Ext._timers[name] = new Date().getTime();
        if(printResults !== false){
            Ext.log('Timer ' + (name == "def" ? v : name + ": " + v));
        }
        return v;
    }
});

})();


Ext.debug.ScriptsPanel = Ext.extend(Ext.Panel, {
    id:'x-debug-scripts',
    region: 'east',
    minWidth: 200,
    split: true,
    width: 350,
    border: false,
    layout:'anchor',
    style:'border-width:0 0 0 1px;',

    initComponent : function(){

        this.scriptField = new Ext.form.TextArea({
            anchor: '100% -26',
            style:'border-width:0;'
        });

        this.trapBox = new Ext.form.Checkbox({
            id: 'console-trap',
            boxLabel: 'Trap Errors',
            checked: true
        });

        this.toolbar = new Ext.Toolbar([{
                text: 'Run',
                scope: this,
                handler: this.evalScript
            },{
                text: 'Clear',
                scope: this,
                handler: this.clear
            },
            '->',
            this.trapBox,
            ' ', ' '
        ]);

        this.items = [this.toolbar, this.scriptField];

        Ext.debug.ScriptsPanel.superclass.initComponent.call(this);
    },

    evalScript : function(){
        var s = this.scriptField.getValue();
        if(this.trapBox.getValue()){
            try{
                var rt = eval(s);
                Ext.dump(rt === undefined? '(no return)' : rt);
            }catch(e){
                Ext.log(e.message || e.descript);
            }
        }else{
            var rt = eval(s);
            Ext.dump(rt === undefined? '(no return)' : rt);
        }
    },

    clear : function(){
        this.scriptField.setValue('');
        this.scriptField.focus();
    }

});

Ext.debug.LogPanel = Ext.extend(Ext.Panel, {
    autoScroll: true,
    region: 'center',
    border: false,
    style:'border-width:0 1px 0 0',

    log : function(){
        var markup = [  '<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
                    Ext.util.Format.htmlEncode(Array.prototype.join.call(arguments, ', ')).replace(/\n/g, '<br/>').replace(/\s/g, '&#160;'),
                    '</div>'].join(''),
            bd = this.body.dom;

        this.body.insertHtml('beforeend', markup);
        bd.scrollTop = bd.scrollHeight;
    },

    clear : function(){
        this.body.update('');
        this.body.dom.scrollTop = 0;
    }
});

Ext.debug.DomTree = Ext.extend(Ext.tree.TreePanel, {
    enableDD:false ,
    lines:false,
    rootVisible:false,
    animate:false,
    hlColor:'ffff9c',
    autoScroll: true,
    region:'center',
    border:false,

    initComponent : function(){


        Ext.debug.DomTree.superclass.initComponent.call(this);

        // tree related stuff
        var styles = false, hnode;
        var nonSpace = /^\s*$/;
        var html = Ext.util.Format.htmlEncode;
        var ellipsis = Ext.util.Format.ellipsis;
        var styleRe = /\s?([a-z\-]*)\:([^;]*)(?:[;\s\n\r]*)/gi;

        function findNode(n){
            if(!n || n.nodeType != 1 || n == document.body || n == document){
                return false;
            }
            var pn = [n], p = n;
            while((p = p.parentNode) && p.nodeType == 1 && p.tagName.toUpperCase() != 'HTML'){
                pn.unshift(p);
            }
            var cn = hnode;
            for(var i = 0, len = pn.length; i < len; i++){
                cn.expand();
                cn = cn.findChild('htmlNode', pn[i]);
                if(!cn){ // in this dialog?
                    return false;
                }
            }
            cn.select();
            var a = cn.ui.anchor;
            this.getTreeEl().dom.scrollTop = Math.max(0 ,a.offsetTop-10);
            //treeEl.dom.scrollLeft = Math.max(0 ,a.offsetLeft-10); no likey
            cn.highlight();
            return true;
        }

        function nodeTitle(n){
            var s = n.tagName;
            if(n.id){
                s += '#'+n.id;
            }else if(n.className){
                s += '.'+n.className;
            }
            return s;
        }

        /*
        function onNodeSelect(t, n, last){
            return;
            if(last && last.unframe){
                last.unframe();
            }
            var props = {};
            if(n && n.htmlNode){
                if(frameEl.pressed){
                    n.frame();
                }
                if(inspecting){
                    return;
                }
                addStyle.enable();
                reload.setDisabled(n.leaf);
                var dom = n.htmlNode;
                stylePanel.setTitle(nodeTitle(dom));
                if(styles && !showAll.pressed){
                    var s = dom.style ? dom.style.cssText : '';
                    if(s){
                        var m;
                        while ((m = styleRe.exec(s)) != null){
                            props[m[1].toLowerCase()] = m[2];
                        }
                    }
                }else if(styles){
                    var cl = Ext.debug.cssList;
                    var s = dom.style, fly = Ext.fly(dom);
                    if(s){
                        for(var i = 0, len = cl.length; i<len; i++){
                            var st = cl[i];
                            var v = s[st] || fly.getStyle(st);
                            if(v != undefined && v !== null && v !== ''){
                                props[st] = v;
                            }
                        }
                    }
                }else{
                    for(var a in dom){
                        var v = dom[a];
                        if((isNaN(a+10)) && v != undefined && v !== null && v !== '' && !(Ext.isGecko && a[0] == a[0].toUpperCase())){
                            props[a] = v;
                        }
                    }
                }
            }else{
                if(inspecting){
                    return;
                }
                addStyle.disable();
                reload.disabled();
            }
            stylesGrid.setSource(props);
            stylesGrid.treeNode = n;
            stylesGrid.view.fitColumns();
        }
        */

        this.loader = new Ext.tree.TreeLoader();
        this.loader.load = function(n, cb){
            var isBody = n.htmlNode == document.body;
            var cn = n.htmlNode.childNodes;
            for(var i = 0, c; c = cn[i]; i++){
                if(isBody && c.id == 'x-debug-browser'){
                    continue;
                }
                if(c.nodeType == 1){
                    n.appendChild(new Ext.debug.HtmlNode(c));
                }else if(c.nodeType == 3 && !nonSpace.test(c.nodeValue)){
                    n.appendChild(new Ext.tree.TreeNode({
                        text:'<em>' + ellipsis(html(String(c.nodeValue)), 35) + '</em>',
                        cls: 'x-tree-noicon'
                    }));
                }
            }
            cb();
        };

        //tree.getSelectionModel().on('selectionchange', onNodeSelect, null, {buffer:250});

        this.root = this.setRootNode(new Ext.tree.TreeNode('Ext'));

        hnode = this.root.appendChild(new Ext.debug.HtmlNode(
                document.getElementsByTagName('html')[0]
        ));

    }
});

Ext.debug.ComponentNodeUI = Ext.extend(Ext.tree.TreeNodeUI,{
    onOver : function(e){
        Ext.debug.ComponentNodeUI.superclass.onOver.call(this);
        var cmp = this.node.attributes.component;
        if (cmp.el && cmp.el.mask && cmp.id !='x-debug-browser') {
            try { // Oddly bombs on some elements in IE, gets any we care about though
                cmp.el.mask();
            } catch(e) {}
        }
    },

    onOut : function(e){
        Ext.debug.ComponentNodeUI.superclass.onOut.call(this);
        var cmp = this.node.attributes.component;
        if (cmp.el && cmp.el.unmask && cmp.id !='x-debug-browser') {
            try {
                cmp.el.unmask();
            } catch(e) {}
        }
    }
});

Ext.debug.ComponentInspector = Ext.extend(Ext.tree.TreePanel, {
    enableDD:false ,
    lines:false,
    rootVisible:false,
    animate:false,
    hlColor:'ffff9c',
    autoScroll: true,
    region:'center',
    border:false,

    initComponent : function(){
        this.loader = new Ext.tree.TreeLoader();
        this.bbar = new Ext.Toolbar([{
            text: 'Refresh',
            handler: this.refresh,
            scope: this
        }]);
        Ext.debug.ComponentInspector.superclass.initComponent.call(this);

        this.root = this.setRootNode(new Ext.tree.TreeNode({
            text: 'Ext Components',
            component: Ext.ComponentMgr.all,
            leaf: false
        }));
        this.parseRootNode();

        this.on('click', this.onClick, this);
    },

    createNode: function(n,c) {
        var leaf = (c.items && c.items.length > 0);
        return n.appendChild(new Ext.tree.TreeNode({
            text: c.id + (c.getXType() ? ' [ ' + c.getXType() + ' ]': '' ),
            component: c,
            uiProvider:Ext.debug.ComponentNodeUI,
            leaf: !leaf
        }));
    },

    parseChildItems: function(n) {
        var cn = n.attributes.component.items;
        if (cn) {
            for (var i = 0;i < cn.length; i++) {
                var c = cn.get(i);
                if (c.id != this.id && c.id != this.bottomToolbar.id) {
                    var newNode = this.createNode(n,c);
                    if (!newNode.leaf) {
                        this.parseChildItems(newNode);
                    }
                }
            }
        }
    },

    parseRootNode: function() {
        var n = this.root;
        var cn = n.attributes.component.items;
        for (var i = 0,c;c = cn[i];i++) {
            if (c.id != this.id && c.id != this.bottomToolbar.id) {
                if (!c.ownerCt) {
                    var newNode = this.createNode(n,c);
                    if (!newNode.leaf) {
                        this.parseChildItems(newNode);
                    }
                }
            }
        }
    },

    onClick: function(node, e) {
        var oi = Ext.getCmp('x-debug-objinspector');
        oi.refreshNodes(node.attributes.component);
        oi.ownerCt.show();
    },

    refresh: function() {
        while (this.root.firstChild) {
            this.root.removeChild(this.root.firstChild);
        }
        this.parseRootNode();
        var ci = Ext.getCmp('x-debug-compinfo');
        if (ci) {
            ci.message('refreshed component tree - '+Ext.ComponentMgr.all.length);
        }
    }
});

Ext.debug.ComponentInfoPanel = Ext.extend(Ext.Panel,{
    id:'x-debug-compinfo',
    region: 'east',
    minWidth: 200,
    split: true,
    width: 350,
    border: false,
    autoScroll: true,
    layout:'anchor',
    style:'border-width:0 0 0 1px;',

    initComponent: function() {
        this.watchBox = new Ext.form.Checkbox({
            id: 'x-debug-watchcomp',
            boxLabel: 'Watch ComponentMgr',
            listeners: {
                check: function(cb, val) {
                    if (val) {
                        Ext.ComponentMgr.all.on('add', this.onAdd, this);
                        Ext.ComponentMgr.all.on('remove', this.onRemove, this);
                    } else {
                        Ext.ComponentMgr.all.un('add', this.onAdd, this);
                        Ext.ComponentMgr.all.un('remove', this.onRemove, this);
                    }
                },
                scope: this
            }
        });

        this.tbar = new Ext.Toolbar([{
            text: 'Clear',
            handler: this.clear,
            scope: this
        },'->',this.watchBox
        ]);
        Ext.debug.ComponentInfoPanel.superclass.initComponent.call(this);
    },

    onAdd: function(i, o, key) {
        var markup = ['<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
                    'Added: '+o.id,
                    '</div>'].join('');
        this.insertMarkup(markup);
    },

    onRemove: function(o, key) {
        var markup = ['<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
                    'Removed: '+o.id,
                    '</div>'].join('');
        this.insertMarkup(markup);
    },

    message: function(msg) {
        var markup = ['<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
                    msg,
                    '</div>'].join('');
        this.insertMarkup(markup);
    },
    insertMarkup: function(markup) {
        this.body.insertHtml('beforeend', markup);
        this.body.scrollTo('top', 100000);
    },
    clear : function(){
        this.body.update('');
        this.body.dom.scrollTop = 0;
    }
});

Ext.debug.ColumnNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
    focus: Ext.emptyFn, // prevent odd scrolling behavior

    renderElements : function(n, a, targetNode, bulkRender){
        this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';

        var t = n.getOwnerTree();
        var cols = t.columns;
        var bw = t.borderWidth;
        var c = cols[0];

        var buf = [
             '<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf ', a.cls,'">',
                '<div class="x-tree-col" style="width:',c.width-bw,'px;">',
                    '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
                    '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow"/>',
                    '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on"/>',
                    '<a hidefocus="on" class="x-tree-node-anchor" href="',a.href ? a.href : "#",'" tabIndex="1" ',
                    a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '>',
                    '<span unselectable="on">', n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</span></a>",
                "</div>"];
         for(var i = 1, len = cols.length; i < len; i++){
             c = cols[i];

             buf.push('<div class="x-tree-col ',(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
                        '<div class="x-tree-col-text">',(c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</div>",
                      "</div>");
         }
         buf.push(
            '<div class="x-clear"></div></div>',
            '<ul class="x-tree-node-ct" style="display:none;"></ul>',
            "</li>");

        if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
            this.wrap = Ext.DomHelper.insertHtml("beforeBegin",
                                n.nextSibling.ui.getEl(), buf.join(""));
        }else{
            this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
        }

        this.elNode = this.wrap.childNodes[0];
        this.ctNode = this.wrap.childNodes[1];
        var cs = this.elNode.firstChild.childNodes;
        this.indentNode = cs[0];
        this.ecNode = cs[1];
        this.iconNode = cs[2];
        this.anchor = cs[3];
        this.textNode = cs[3].firstChild;
    }
});

Ext.debug.ObjectInspector = Ext.extend(Ext.tree.TreePanel, {
    id: 'x-debug-objinspector',
    enableDD:false ,
    lines:false,
    rootVisible:false,
    animate:false,
    hlColor:'ffff9c',
    autoScroll: true,
    region:'center',
    border:false,
    lines:false,
    borderWidth: Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
    cls:'x-column-tree',

    initComponent : function(){
        this.showFunc = false;
        this.toggleFunc = function() {
            this.showFunc = !this.showFunc;
            this.refreshNodes(this.currentObject);
        };
        this.bbar = new Ext.Toolbar([{
            text: 'Show Functions',
            enableToggle: true,
            pressed: false,
            handler: this.toggleFunc,
            scope: this
        }]);

        Ext.apply(this,{
            title: ' ',
            loader: new Ext.tree.TreeLoader(),
            columns:[{
                header:'Property',
                width: 300,
                dataIndex:'name'
            },{
                header:'Value',
                width: 900,
                dataIndex:'value'
            }]
        });

        Ext.debug.ObjectInspector.superclass.initComponent.call(this);

        this.root = this.setRootNode(new Ext.tree.TreeNode({
            text: 'Dummy Node',
            leaf: false
        }));

        if (this.currentObject) {
            this.parseNodes();
        }
    },

    refreshNodes: function(newObj) {
        this.currentObject = newObj;
        var node = this.root;
        while(node.firstChild){
            node.removeChild(node.firstChild);
        }
        this.parseNodes();
    },

    parseNodes: function() {
        for (var o in this.currentObject) {
            if (!this.showFunc) {
                if (Ext.isFunction(this.currentObject[o])) {
                    continue;
                }
            }
            this.createNode(o);
        }
    },

    createNode: function(o) {
        return this.root.appendChild(new Ext.tree.TreeNode({
            name: o,
            value: this.currentObject[o],
            uiProvider:Ext.debug.ColumnNodeUI,
            iconCls: 'x-debug-node',
            leaf: true
        }));
    },

    onRender : function(){
        Ext.debug.ObjectInspector.superclass.onRender.apply(this, arguments);
        this.headers = this.header.createChild({cls:'x-tree-headers'});

        var cols = this.columns, c;
        var totalWidth = 0;

        for(var i = 0, len = cols.length; i < len; i++){
             c = cols[i];
             totalWidth += c.width;
             this.headers.createChild({
                 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
                 cn: {
                     cls:'x-tree-hd-text',
                     html: c.header
                 },
                 style:'width:'+(c.width-this.borderWidth)+'px;'
             });
        }
        this.headers.createChild({cls:'x-clear'});
        // prevent floats from wrapping when clipped
        this.headers.setWidth(totalWidth);
        this.innerCt.setWidth(totalWidth);
    }
});


Ext.debug.StoreInspector = Ext.extend(Ext.tree.TreePanel, {
    enableDD:false ,
    lines:false,
    rootVisible:false,
    animate:false,
    hlColor:'ffff9c',
    autoScroll: true,
    region:'center',
    border:false,

    initComponent: function() {
        this.bbar = new Ext.Toolbar([{
            text: 'Refresh',
            handler: this.refresh,
            scope: this
        }]);
        Ext.debug.StoreInspector.superclass.initComponent.call(this);

        this.root = this.setRootNode(new Ext.tree.TreeNode({
            text: 'Data Stores',
            leaf: false
        }));
        this.on('click', this.onClick, this);

        this.parseStores();
    },

    parseStores: function() {
        var cn = Ext.StoreMgr.items;
        for (var i = 0,c;c = cn[i];i++) {
            this.root.appendChild({
                text: c.storeId + ' - ' + c.totalLength + ' records',
                component: c,
                leaf: true
            });
        }
    },

    onClick: function(node, e) {
        var oi = Ext.getCmp('x-debug-objinspector');
        oi.refreshNodes(node.attributes.component);
        oi.ownerCt.show();
    },

    refresh: function() {
        while (this.root.firstChild) {
            this.root.removeChild(this.root.firstChild);
        }
        this.parseStores();
    }
});

// highly unusual class declaration
Ext.debug.HtmlNode = function(){
    var html = Ext.util.Format.htmlEncode;
    var ellipsis = Ext.util.Format.ellipsis;
    var nonSpace = /^\s*$/;

    var attrs = [
        {n: 'id', v: 'id'},
        {n: 'className', v: 'class'},
        {n: 'name', v: 'name'},
        {n: 'type', v: 'type'},
        {n: 'src', v: 'src'},
        {n: 'href', v: 'href'}
    ];

    function hasChild(n){
        for(var i = 0, c; c = n.childNodes[i]; i++){
            if(c.nodeType == 1){
                return true;
            }
        }
        return false;
    }

    function renderNode(n, leaf){
        var tag = n.tagName.toLowerCase();
        var s = '&lt;' + tag;
        for(var i = 0, len = attrs.length; i < len; i++){
            var a = attrs[i];
            var v = n[a.n];
            if(v && !nonSpace.test(v)){
                s += ' ' + a.v + '=&quot;<i>' + html(v) +'</i>&quot;';
            }
        }
        var style = n.style ? n.style.cssText : '';
        if(style){
            s += ' style=&quot;<i>' + html(style.toLowerCase()) +'</i>&quot;';
        }
        if(leaf && n.childNodes.length > 0){
            s+='&gt;<em>' + ellipsis(html(String(n.innerHTML)), 35) + '</em>&lt;/'+tag+'&gt;';
        }else if(leaf){
            s += ' /&gt;';
        }else{
            s += '&gt;';
        }
        return s;
    }

    var HtmlNode = function(n){
        var leaf = !hasChild(n);
        this.htmlNode = n;
        this.tagName = n.tagName.toLowerCase();
        var attr = {
            text : renderNode(n, leaf),
            leaf : leaf,
            cls: 'x-tree-noicon'
        };
        HtmlNode.superclass.constructor.call(this, attr);
        this.attributes.htmlNode = n; // for searching
        if(!leaf){
            this.on('expand', this.onExpand,  this);
            this.on('collapse', this.onCollapse,  this);
        }
    };


    Ext.extend(HtmlNode, Ext.tree.AsyncTreeNode, {
        cls: 'x-tree-noicon',
        preventHScroll: true,
        refresh : function(highlight){
            var leaf = !hasChild(this.htmlNode);
            this.setText(renderNode(this.htmlNode, leaf));
            if(highlight){
                Ext.fly(this.ui.textNode).highlight();
            }
        },

        onExpand : function(){
            if(!this.closeNode && this.parentNode){
                this.closeNode = this.parentNode.insertBefore(new Ext.tree.TreeNode({
                    text:'&lt;/' + this.tagName + '&gt;',
                    cls: 'x-tree-noicon'
                }), this.nextSibling);
            }else if(this.closeNode){
                this.closeNode.ui.show();
            }
        },

        onCollapse : function(){
            if(this.closeNode){
                this.closeNode.ui.hide();
            }
        },

        render : function(bulkRender){
            HtmlNode.superclass.render.call(this, bulkRender);
        },

        highlightNode : function(){
            //Ext.fly(this.htmlNode).highlight();
        },

        highlight : function(){
            //Ext.fly(this.ui.textNode).highlight();
        },

        frame : function(){
            this.htmlNode.style.border = '1px solid #0000ff';
            //this.highlightNode();
        },

        unframe : function(){
            //Ext.fly(this.htmlNode).removeClass('x-debug-frame');
            this.htmlNode.style.border = '';
        }
    });

    return HtmlNode;
}();