Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / docs / source / debug1.html
1 <html>\r
2 <head>\r
3   <title>The source code</title>\r
4     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
5     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
6 </head>\r
7 <body  onload="prettyPrint();">\r
8     <pre class="prettyprint lang-js">Ext.debug = {};
9
10 (function(){
11
12 var cp;
13
14 function createConsole(){
15
16     var scriptPanel = new Ext.debug.ScriptsPanel();
17     var logView = new Ext.debug.LogPanel();
18     var tree = new Ext.debug.DomTree();
19     var compInspector = new Ext.debug.ComponentInspector();
20     var compInfoPanel = new Ext.debug.ComponentInfoPanel();
21     var storeInspector = new Ext.debug.StoreInspector();
22     var objInspector = new Ext.debug.ObjectInspector();
23
24     var tabs = new Ext.TabPanel({
25         activeTab: 0,
26         border: false,
27         tabPosition: 'bottom',
28         items: [{
29             title: 'Debug Console',
30             layout:'border',
31             items: [logView, scriptPanel]
32         },{
33             title: 'HTML Inspector',
34             layout:'border',
35             items: [tree]
36         },{
37             title: 'Component Inspector',
38             layout: 'border',
39             items: [compInspector,compInfoPanel]
40         },{
41             title: 'Object Inspector',
42             layout: 'border',
43             items: [objInspector]
44         },{
45             title: 'Data Stores',
46             layout: 'border',
47             items: [storeInspector]
48         }]
49     });
50
51     cp = new Ext.Panel({
52         id: 'x-debug-browser',
53         title: 'Console',
54         collapsible: true,
55         animCollapse: false,
56         style: 'position:absolute;left:0;bottom:0;z-index:101',
57         height:200,
58         logView: logView,
59         layout: 'fit',
60
61         tools:[{
62             id: 'close',
63             handler: function(){
64                 cp.destroy();
65                 cp = null;
66                 Ext.EventManager.removeResizeListener(handleResize);
67             }
68         }],
69
70         items: tabs
71     });
72
73     cp.render(Ext.getBody());
74
75     cp.resizer = new Ext.Resizable(cp.el, {
76         minHeight:50,
77         handles: "n",
78         pinned: true,
79         transparent:true,
80         resizeElement : function(){
81             var box = this.proxy.getBox();
82             this.proxy.hide();
83             cp.setHeight(box.height);
84             return box;
85         }
86     });
87
88 //     function handleResize(){
89 //         cp.setWidth(Ext.getBody().getViewSize().width);
90 //     }
91 //     Ext.EventManager.onWindowResize(handleResize);
92 //
93 //     handleResize();
94
95     function handleResize(){
96         var b = Ext.getBody()
97         var size = b.getViewSize();
98         if(size.height < b.dom.scrollHeight) {
99             size.width -= 18;
100         }
101         cp.setWidth(size.width);
102     }
103     Ext.EventManager.onWindowResize(handleResize);
104     handleResize();
105 }
106
107
108 Ext.apply(Ext, {
109     log : function(){
110         if(!cp){
111             createConsole();
112         }
113         cp.logView.log.apply(cp.logView, arguments);
114     },
115
116     logf : function(format, arg1, arg2, etc){
117         Ext.log(String.format.apply(String, arguments));
118     },
119
120     dump : function(o){
121         if(typeof o == 'string' || typeof o == 'number' || typeof o == 'undefined' || Ext.isDate(o)){
122             Ext.log(o);
123         }else if(!o){
124             Ext.log("null");
125         }else if(typeof o != "object"){
126             Ext.log('Unknown return type');
127         }else if(Ext.isArray(o)){
128             Ext.log('['+o.join(',')+']');
129         }else{
130             var b = ["{\n"];
131             for(var key in o){
132                 var to = typeof o[key];
133                 if(to != "function" && to != "object"){
134                     b.push(String.format("  {0}: {1},\n", key, o[key]));
135                 }
136             }
137             var s = b.join("");
138             if(s.length > 3){
139                 s = s.substr(0, s.length-2);
140             }
141             Ext.log(s + "\n}");
142         }
143     },
144
145     _timers : {},
146
147     time : function(name){
148         name = name || "def";
149         Ext._timers[name] = new Date().getTime();
150     },
151
152     timeEnd : function(name, printResults){
153         var t = new Date().getTime();
154         name = name || "def";
155         var v = String.format("{0} ms", t-Ext._timers[name]);
156         Ext._timers[name] = new Date().getTime();
157         if(printResults !== false){
158             Ext.log('Timer ' + (name == "def" ? v : name + ": " + v));
159         }
160         return v;
161     }
162 });
163
164 })();
165
166
167 Ext.debug.ScriptsPanel = Ext.extend(Ext.Panel, {
168     id:'x-debug-scripts',
169     region: 'east',
170     minWidth: 200,
171     split: true,
172     width: 350,
173     border: false,
174     layout:'anchor',
175     style:'border-width:0 0 0 1px;',
176
177     initComponent : function(){
178
179         this.scriptField = new Ext.form.TextArea({
180             anchor: '100% -26',
181             style:'border-width:0;'
182         });
183
184         this.trapBox = new Ext.form.Checkbox({
185             id: 'console-trap',
186             boxLabel: 'Trap Errors',
187             checked: true
188         });
189
190         this.toolbar = new Ext.Toolbar([{
191                 text: 'Run',
192                 scope: this,
193                 handler: this.evalScript
194             },{
195                 text: 'Clear',
196                 scope: this,
197                 handler: this.clear
198             },
199             '->',
200             this.trapBox,
201             ' ', ' '
202         ]);
203
204         this.items = [this.toolbar, this.scriptField];
205
206         Ext.debug.ScriptsPanel.superclass.initComponent.call(this);
207     },
208
209     evalScript : function(){
210         var s = this.scriptField.getValue();
211         if(this.trapBox.getValue()){
212             try{
213                 var rt = eval(s);
214                 Ext.dump(rt === undefined? '(no return)' : rt);
215             }catch(e){
216                 Ext.log(e.message || e.descript);
217             }
218         }else{
219             var rt = eval(s);
220             Ext.dump(rt === undefined? '(no return)' : rt);
221         }
222     },
223
224     clear : function(){
225         this.scriptField.setValue('');
226         this.scriptField.focus();
227     }
228
229 });
230
231 Ext.debug.LogPanel = Ext.extend(Ext.Panel, {
232     autoScroll: true,
233     region: 'center',
234     border: false,
235     style:'border-width:0 1px 0 0',
236
237     log : function(){
238         var markup = [  '<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
239                     Ext.util.Format.htmlEncode(Array.prototype.join.call(arguments, ', ')).replace(/\n/g, '<br />').replace(/\s/g, '&#160;'),
240                     '</div>'].join('');
241
242         this.body.insertHtml('beforeend', markup);
243         this.body.scrollTo('top', 100000);
244     },
245
246     clear : function(){
247         this.body.update('');
248         this.body.dom.scrollTop = 0;
249     }
250 });
251
252 Ext.debug.DomTree = Ext.extend(Ext.tree.TreePanel, {
253     enableDD:false ,
254     lines:false,
255     rootVisible:false,
256     animate:false,
257     hlColor:'ffff9c',
258     autoScroll: true,
259     region:'center',
260     border:false,
261
262     initComponent : function(){
263
264
265         Ext.debug.DomTree.superclass.initComponent.call(this);
266
267         // tree related stuff
268         var styles = false, hnode;
269         var nonSpace = /^\s*$/;
270         var html = Ext.util.Format.htmlEncode;
271         var ellipsis = Ext.util.Format.ellipsis;
272         var styleRe = /\s?([a-z\-]*)\:([^;]*)(?:[;\s\n\r]*)/gi;
273
274         function findNode(n){
275             if(!n || n.nodeType != 1 || n == document.body || n == document){
276                 return false;
277             }
278             var pn = [n], p = n;
279             while((p = p.parentNode) && p.nodeType == 1 && p.tagName.toUpperCase() != 'HTML'){
280                 pn.unshift(p);
281             }
282             var cn = hnode;
283             for(var i = 0, len = pn.length; i < len; i++){
284                 cn.expand();
285                 cn = cn.findChild('htmlNode', pn[i]);
286                 if(!cn){ // in this dialog?
287                     return false;
288                 }
289             }
290             cn.select();
291             var a = cn.ui.anchor;
292             treeEl.dom.scrollTop = Math.max(0 ,a.offsetTop-10);
293             //treeEl.dom.scrollLeft = Math.max(0 ,a.offsetLeft-10); no likey
294             cn.highlight();
295             return true;
296         }
297
298         function nodeTitle(n){
299             var s = n.tagName;
300             if(n.id){
301                 s += '#'+n.id;
302             }else if(n.className){
303                 s += '.'+n.className;
304             }
305             return s;
306         }
307
308         function onNodeSelect(t, n, last){
309             return;
310             if(last && last.unframe){
311                 last.unframe();
312             }
313             var props = {};
314             if(n && n.htmlNode){
315                 if(frameEl.pressed){
316                     n.frame();
317                 }
318                 if(inspecting){
319                     return;
320                 }
321                 addStyle.enable();
322                 reload.setDisabled(n.leaf);
323                 var dom = n.htmlNode;
324                 stylePanel.setTitle(nodeTitle(dom));
325                 if(styles && !showAll.pressed){
326                     var s = dom.style ? dom.style.cssText : '';
327                     if(s){
328                         var m;
329                         while ((m = styleRe.exec(s)) != null){
330                             props[m[1].toLowerCase()] = m[2];
331                         }
332                     }
333                 }else if(styles){
334                     var cl = Ext.debug.cssList;
335                     var s = dom.style, fly = Ext.fly(dom);
336                     if(s){
337                         for(var i = 0, len = cl.length; i<len; i++){
338                             var st = cl[i];
339                             var v = s[st] || fly.getStyle(st);
340                             if(v != undefined && v !== null && v !== ''){
341                                 props[st] = v;
342                             }
343                         }
344                     }
345                 }else{
346                     for(var a in dom){
347                         var v = dom[a];
348                         if((isNaN(a+10)) && v != undefined && v !== null && v !== '' && !(Ext.isGecko && a[0] == a[0].toUpperCase())){
349                             props[a] = v;
350                         }
351                     }
352                 }
353             }else{
354                 if(inspecting){
355                     return;
356                 }
357                 addStyle.disable();
358                 reload.disabled();
359             }
360             stylesGrid.setSource(props);
361             stylesGrid.treeNode = n;
362             stylesGrid.view.fitColumns();
363         }
364
365         this.loader = new Ext.tree.TreeLoader();
366         this.loader.load = function(n, cb){
367             var isBody = n.htmlNode == document.body;
368             var cn = n.htmlNode.childNodes;
369             for(var i = 0, c; c = cn[i]; i++){
370                 if(isBody && c.id == 'x-debug-browser'){
371                     continue;
372                 }
373                 if(c.nodeType == 1){
374                     n.appendChild(new Ext.debug.HtmlNode(c));
375                 }else if(c.nodeType == 3 && !nonSpace.test(c.nodeValue)){
376                     n.appendChild(new Ext.tree.TreeNode({
377                         text:'<em>' + ellipsis(html(String(c.nodeValue)), 35) + '</em>',
378                         cls: 'x-tree-noicon'
379                     }));
380                 }
381             }
382             cb();
383         };
384
385         //tree.getSelectionModel().on('selectionchange', onNodeSelect, null, {buffer:250});
386
387         this.root = this.setRootNode(new Ext.tree.TreeNode('Ext'));
388
389         hnode = this.root.appendChild(new Ext.debug.HtmlNode(
390                 document.getElementsByTagName('html')[0]
391         ));
392
393     }
394 });
395
396 Ext.debug.ComponentNodeUI = Ext.extend(Ext.tree.TreeNodeUI,{
397     onOver : function(e){
398         Ext.debug.ComponentNodeUI.superclass.onOver.call(this);
399         var cmp = this.node.attributes.component;
400         if (cmp.el && cmp.el.mask && cmp.id !='x-debug-browser') {
401             try { // Oddly bombs on some elements in IE, gets any we care about though
402                 cmp.el.mask();
403             } catch(e) {}
404         }
405     },
406
407     onOut : function(e){
408         Ext.debug.ComponentNodeUI.superclass.onOut.call(this);
409         var cmp = this.node.attributes.component;
410         if (cmp.el && cmp.el.unmask && cmp.id !='x-debug-browser') {
411             try {
412                 cmp.el.unmask();
413             } catch(e) {}
414         }
415     }
416 });
417
418 Ext.debug.ComponentInspector = Ext.extend(Ext.tree.TreePanel, {
419     enableDD:false ,
420     lines:false,
421     rootVisible:false,
422     animate:false,
423     hlColor:'ffff9c',
424     autoScroll: true,
425     region:'center',
426     border:false,
427
428     initComponent : function(){
429         this.loader = new Ext.tree.TreeLoader();
430         this.bbar = new Ext.Toolbar([{
431             text: 'Refresh',
432             handler: this.refresh,
433             scope: this
434         }]);
435         Ext.debug.ComponentInspector.superclass.initComponent.call(this);
436
437         this.root = this.setRootNode(new Ext.tree.TreeNode({
438             text: 'Ext Components',
439             component: Ext.ComponentMgr.all,
440             leaf: false
441         }));
442         this.parseRootNode();
443
444         this.on('click', this.onClick, this);
445     },
446
447     createNode: function(n,c) {
448         var leaf = (c.items && c.items.length > 0);
449         return n.appendChild(new Ext.tree.TreeNode({
450             text: c.id + (c.getXType() ? ' [ ' + c.getXType() + ' ]': '' ),
451             component: c,
452             uiProvider:Ext.debug.ComponentNodeUI,
453             leaf: !leaf
454         }));
455     },
456
457     parseChildItems: function(n) {
458         var cn = n.attributes.component.items;
459         if (cn) {
460             for (var i = 0;i < cn.length; i++) {
461                 var c = cn.get(i);
462                 if (c.id != this.id && c.id != this.bottomToolbar.id) {
463                     var newNode = this.createNode(n,c);
464                     if (!newNode.leaf) {
465                         this.parseChildItems(newNode)
466                     }
467                 }
468             }
469         }
470     },
471
472     parseRootNode: function() {
473         var n = this.root;
474         var cn = n.attributes.component.items;
475         for (var i = 0,c;c = cn[i];i++) {
476             if (c.id != this.id && c.id != this.bottomToolbar.id) {
477                 if (!c.ownerCt) {
478                     var newNode = this.createNode(n,c);
479                     if (!newNode.leaf) {
480                         this.parseChildItems(newNode);
481                     }
482                 }
483             }
484         }
485     },
486
487     onClick: function(node, e) {
488         var oi = Ext.getCmp('x-debug-objinspector');
489         oi.refreshNodes(node.attributes.component);
490         oi.ownerCt.show();
491     },
492
493     refresh: function() {
494         while (this.root.firstChild) {
495             this.root.removeChild(this.root.firstChild);
496         }
497         this.parseRootNode();
498         var ci = Ext.getCmp('x-debug-compinfo');
499         if (ci) {
500             ci.message('refreshed component tree - '+Ext.ComponentMgr.all.length)
501         }
502     }
503 });
504
505 Ext.debug.ComponentInfoPanel = Ext.extend(Ext.Panel,{
506     id:'x-debug-compinfo',
507     region: 'east',
508     minWidth: 200,
509     split: true,
510     width: 350,
511     border: false,
512     autoScroll: true,
513     layout:'anchor',
514     style:'border-width:0 0 0 1px;',
515
516     initComponent: function() {
517         this.watchBox = new Ext.form.Checkbox({
518             id: 'x-debug-watchcomp',
519             boxLabel: 'Watch ComponentMgr',
520             listeners: {
521                 check: function(cb, val) {
522                     if (val) {
523                         Ext.ComponentMgr.all.on('add', this.onAdd, this);
524                         Ext.ComponentMgr.all.on('remove', this.onRemove, this);
525                     } else {
526                         Ext.ComponentMgr.all.un('add', this.onAdd, this);
527                         Ext.ComponentMgr.all.un('remove', this.onRemove, this);
528                     }
529                 },
530                 scope: this
531             }
532         });
533
534         this.tbar = new Ext.Toolbar([{
535             text: 'Clear',
536             handler: this.clear,
537             scope: this
538         },'->',this.watchBox
539         ]);
540         Ext.debug.ComponentInfoPanel.superclass.initComponent.call(this);
541     },
542
543     onAdd: function(i, o, key) {
544         var markup = ['<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
545                     'Added: '+o.id,
546                     '</div>'].join('');
547         this.insertMarkup(markup);
548     },
549
550     onRemove: function(o, key) {
551         var markup = ['<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
552                     'Removed: '+o.id,
553                     '</div>'].join('');
554         this.insertMarkup(markup);
555     },
556
557     message: function(msg) {
558         var markup = ['<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
559                     msg,
560                     '</div>'].join('');
561         this.insertMarkup(markup);
562     },
563     insertMarkup: function(markup) {
564         this.body.insertHtml('beforeend', markup);
565         this.body.scrollTo('top', 100000);
566     },
567     clear : function(){
568         this.body.update('');
569         this.body.dom.scrollTop = 0;
570     }
571 });
572
573 Ext.debug.ColumnNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
574     focus: Ext.emptyFn, // prevent odd scrolling behavior
575
576     renderElements : function(n, a, targetNode, bulkRender){
577         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
578
579         var t = n.getOwnerTree();
580         var cols = t.columns;
581         var bw = t.borderWidth;
582         var c = cols[0];
583
584         var buf = [
585              '<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf ', a.cls,'">',
586                 '<div class="x-tree-col" style="width:',c.width-bw,'px;">',
587                     '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
588                     '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow">',
589                     '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on">',
590                     '<a hidefocus="on" class="x-tree-node-anchor" href="',a.href ? a.href : "#",'" tabIndex="1" ',
591                     a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '>',
592                     '<span unselectable="on">', n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</span></a>",
593                 "</div>"];
594          for(var i = 1, len = cols.length; i < len; i++){
595              c = cols[i];
596
597              buf.push('<div class="x-tree-col ',(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
598                         '<div class="x-tree-col-text">',(c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</div>",
599                       "</div>");
600          }
601          buf.push(
602             '<div class="x-clear"></div></div>',
603             '<ul class="x-tree-node-ct" style="display:none;"></ul>',
604             "</li>");
605
606         if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
607             this.wrap = Ext.DomHelper.insertHtml("beforeBegin",
608                                 n.nextSibling.ui.getEl(), buf.join(""));
609         }else{
610             this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
611         }
612
613         this.elNode = this.wrap.childNodes[0];
614         this.ctNode = this.wrap.childNodes[1];
615         var cs = this.elNode.firstChild.childNodes;
616         this.indentNode = cs[0];
617         this.ecNode = cs[1];
618         this.iconNode = cs[2];
619         this.anchor = cs[3];
620         this.textNode = cs[3].firstChild;
621     }
622 });
623
624 Ext.debug.ObjectInspector = Ext.extend(Ext.tree.TreePanel, {
625     id: 'x-debug-objinspector',
626     enableDD:false ,
627     lines:false,
628     rootVisible:false,
629     animate:false,
630     hlColor:'ffff9c',
631     autoScroll: true,
632     region:'center',
633     border:false,
634     lines:false,
635     borderWidth: Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
636     cls:'x-column-tree',
637
638     initComponent : function(){
639         this.showFunc = false;
640         this.toggleFunc = function() {
641             this.showFunc = !this.showFunc;
642             this.refreshNodes(this.currentObject);
643         }
644         this.bbar = new Ext.Toolbar([{
645             text: 'Show Functions',
646             enableToggle: true,
647             pressed: false,
648             handler: this.toggleFunc,
649             scope: this
650         }]);
651
652         Ext.apply(this,{
653             title: ' ',
654             loader: new Ext.tree.TreeLoader(),
655             columns:[{
656                 header:'Property',
657                 width: 300,
658                 dataIndex:'name'
659             },{
660                 header:'Value',
661                 width: 900,
662                 dataIndex:'value'
663             }]
664         });
665
666         Ext.debug.ObjectInspector.superclass.initComponent.call(this);
667
668         this.root = this.setRootNode(new Ext.tree.TreeNode({
669             text: 'Dummy Node',
670             leaf: false
671         }));
672
673         if (this.currentObject) {
674             this.parseNodes();
675         }
676     },
677
678     refreshNodes: function(newObj) {
679         this.currentObject = newObj;
680         var node = this.root;
681         while(node.firstChild){
682             node.removeChild(node.firstChild);
683         }
684         this.parseNodes();
685     },
686
687     parseNodes: function() {
688         for (var o in this.currentObject) {
689             if (!this.showFunc) {
690                 if (Ext.isFunction(this.currentObject[o])) {
691                     continue;
692                 }
693             }
694             this.createNode(o);
695         }
696     },
697
698     createNode: function(o) {
699         return this.root.appendChild(new Ext.tree.TreeNode({
700             name: o,
701             value: this.currentObject[o],
702             uiProvider:Ext.debug.ColumnNodeUI,
703             iconCls: 'x-debug-node',
704             leaf: true
705         }));
706     },
707
708     onRender : function(){
709         Ext.debug.ObjectInspector.superclass.onRender.apply(this, arguments);
710         this.headers = this.header.createChild({cls:'x-tree-headers'});
711
712         var cols = this.columns, c;
713         var totalWidth = 0;
714
715         for(var i = 0, len = cols.length; i < len; i++){
716              c = cols[i];
717              totalWidth += c.width;
718              this.headers.createChild({
719                  cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
720                  cn: {
721                      cls:'x-tree-hd-text',
722                      html: c.header
723                  },
724                  style:'width:'+(c.width-this.borderWidth)+'px;'
725              });
726         }
727         this.headers.createChild({cls:'x-clear'});
728         // prevent floats from wrapping when clipped
729         this.headers.setWidth(totalWidth);
730         this.innerCt.setWidth(totalWidth);
731     }
732 });
733
734
735 Ext.debug.StoreInspector = Ext.extend(Ext.tree.TreePanel, {
736     enableDD:false ,
737     lines:false,
738     rootVisible:false,
739     animate:false,
740     hlColor:'ffff9c',
741     autoScroll: true,
742     region:'center',
743     border:false,
744
745     initComponent: function() {
746         this.bbar = new Ext.Toolbar([{
747             text: 'Refresh',
748             handler: this.refresh,
749             scope: this
750         }]);
751         Ext.debug.StoreInspector.superclass.initComponent.call(this);
752
753         this.root = this.setRootNode(new Ext.tree.TreeNode({
754             text: 'Data Stores',
755             leaf: false
756         }));
757         this.on('click', this.onClick, this);
758
759         this.parseStores();
760     },
761
762     parseStores: function() {
763         var cn = Ext.StoreMgr.items;
764         for (var i = 0,c;c = cn[i];i++) {
765             this.root.appendChild({
766                 text: c.storeId + ' - ' + c.totalLength + ' records',
767                 component: c,
768                 leaf: true
769             });
770         }
771     },
772
773     onClick: function(node, e) {
774         var oi = Ext.getCmp('x-debug-objinspector');
775         oi.refreshNodes(node.attributes.component);
776         oi.ownerCt.show();
777     },
778
779     refresh: function() {
780         while (this.root.firstChild) {
781             this.root.removeChild(this.root.firstChild);
782         }
783         this.parseStores();
784     }
785 });
786
787 // highly unusual class declaration
788 Ext.debug.HtmlNode = function(){
789     var html = Ext.util.Format.htmlEncode;
790     var ellipsis = Ext.util.Format.ellipsis;
791     var nonSpace = /^\s*$/;
792
793     var attrs = [
794         {n: 'id', v: 'id'},
795         {n: 'className', v: 'class'},
796         {n: 'name', v: 'name'},
797         {n: 'type', v: 'type'},
798         {n: 'src', v: 'src'},
799         {n: 'href', v: 'href'}
800     ];
801
802     function hasChild(n){
803         for(var i = 0, c; c = n.childNodes[i]; i++){
804             if(c.nodeType == 1){
805                 return true;
806             }
807         }
808         return false;
809     }
810
811     function renderNode(n, leaf){
812         var tag = n.tagName.toLowerCase();
813         var s = '&lt;' + tag;
814         for(var i = 0, len = attrs.length; i < len; i++){
815             var a = attrs[i];
816             var v = n[a.n];
817             if(v && !nonSpace.test(v)){
818                 s += ' ' + a.v + '=&quot;<i>' + html(v) +'</i>&quot;';
819             }
820         }
821         var style = n.style ? n.style.cssText : '';
822         if(style){
823             s += ' style=&quot;<i>' + html(style.toLowerCase()) +'</i>&quot;';
824         }
825         if(leaf && n.childNodes.length > 0){
826             s+='&gt;<em>' + ellipsis(html(String(n.innerHTML)), 35) + '</em>&lt;/'+tag+'&gt;';
827         }else if(leaf){
828             s += ' /&gt;';
829         }else{
830             s += '&gt;';
831         }
832         return s;
833     }
834
835     var HtmlNode = function(n){
836         var leaf = !hasChild(n);
837         this.htmlNode = n;
838         this.tagName = n.tagName.toLowerCase();
839         var attr = {
840             text : renderNode(n, leaf),
841             leaf : leaf,
842             cls: 'x-tree-noicon'
843         };
844         HtmlNode.superclass.constructor.call(this, attr);
845         this.attributes.htmlNode = n; // for searching
846         if(!leaf){
847             this.on('expand', this.onExpand,  this);
848             this.on('collapse', this.onCollapse,  this);
849         }
850     };
851
852
853     Ext.extend(HtmlNode, Ext.tree.AsyncTreeNode, {
854         cls: 'x-tree-noicon',
855         preventHScroll: true,
856         refresh : function(highlight){
857             var leaf = !hasChild(this.htmlNode);
858             this.setText(renderNode(this.htmlNode, leaf));
859             if(highlight){
860                 Ext.fly(this.ui.textNode).highlight();
861             }
862         },
863
864         onExpand : function(){
865             if(!this.closeNode && this.parentNode){
866                 this.closeNode = this.parentNode.insertBefore(new Ext.tree.TreeNode({
867                     text:'&lt;/' + this.tagName + '&gt;',
868                     cls: 'x-tree-noicon'
869                 }), this.nextSibling);
870             }else if(this.closeNode){
871                 this.closeNode.ui.show();
872             }
873         },
874
875         onCollapse : function(){
876             if(this.closeNode){
877                 this.closeNode.ui.hide();
878             }
879         },
880
881         render : function(bulkRender){
882             HtmlNode.superclass.render.call(this, bulkRender);
883         },
884
885         highlightNode : function(){
886             //Ext.fly(this.htmlNode).highlight();
887         },
888
889         highlight : function(){
890             //Ext.fly(this.ui.textNode).highlight();
891         },
892
893         frame : function(){
894             this.htmlNode.style.border = '1px solid #0000ff';
895             //this.highlightNode();
896         },
897
898         unframe : function(){
899             //Ext.fly(this.htmlNode).removeClass('x-debug-frame');
900             this.htmlNode.style.border = '';
901         }
902     });
903
904     return HtmlNode;
905 }();</pre>    \r
906 </body>\r
907 </html>