Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / docs / source / debug.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             this.getTreeEl().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         /*
309         function onNodeSelect(t, n, last){
310             return;
311             if(last && last.unframe){
312                 last.unframe();
313             }
314             var props = {};
315             if(n && n.htmlNode){
316                 if(frameEl.pressed){
317                     n.frame();
318                 }
319                 if(inspecting){
320                     return;
321                 }
322                 addStyle.enable();
323                 reload.setDisabled(n.leaf);
324                 var dom = n.htmlNode;
325                 stylePanel.setTitle(nodeTitle(dom));
326                 if(styles && !showAll.pressed){
327                     var s = dom.style ? dom.style.cssText : '';
328                     if(s){
329                         var m;
330                         while ((m = styleRe.exec(s)) != null){
331                             props[m[1].toLowerCase()] = m[2];
332                         }
333                     }
334                 }else if(styles){
335                     var cl = Ext.debug.cssList;
336                     var s = dom.style, fly = Ext.fly(dom);
337                     if(s){
338                         for(var i = 0, len = cl.length; i<len; i++){
339                             var st = cl[i];
340                             var v = s[st] || fly.getStyle(st);
341                             if(v != undefined && v !== null && v !== ''){
342                                 props[st] = v;
343                             }
344                         }
345                     }
346                 }else{
347                     for(var a in dom){
348                         var v = dom[a];
349                         if((isNaN(a+10)) && v != undefined && v !== null && v !== '' && !(Ext.isGecko && a[0] == a[0].toUpperCase())){
350                             props[a] = v;
351                         }
352                     }
353                 }
354             }else{
355                 if(inspecting){
356                     return;
357                 }
358                 addStyle.disable();
359                 reload.disabled();
360             }
361             stylesGrid.setSource(props);
362             stylesGrid.treeNode = n;
363             stylesGrid.view.fitColumns();
364         }
365         */
366
367         this.loader = new Ext.tree.TreeLoader();
368         this.loader.load = function(n, cb){
369             var isBody = n.htmlNode == document.body;
370             var cn = n.htmlNode.childNodes;
371             for(var i = 0, c; c = cn[i]; i++){
372                 if(isBody && c.id == 'x-debug-browser'){
373                     continue;
374                 }
375                 if(c.nodeType == 1){
376                     n.appendChild(new Ext.debug.HtmlNode(c));
377                 }else if(c.nodeType == 3 && !nonSpace.test(c.nodeValue)){
378                     n.appendChild(new Ext.tree.TreeNode({
379                         text:'<em>' + ellipsis(html(String(c.nodeValue)), 35) + '</em>',
380                         cls: 'x-tree-noicon'
381                     }));
382                 }
383             }
384             cb();
385         };
386
387         //tree.getSelectionModel().on('selectionchange', onNodeSelect, null, {buffer:250});
388
389         this.root = this.setRootNode(new Ext.tree.TreeNode('Ext'));
390
391         hnode = this.root.appendChild(new Ext.debug.HtmlNode(
392                 document.getElementsByTagName('html')[0]
393         ));
394
395     }
396 });
397
398 Ext.debug.ComponentNodeUI = Ext.extend(Ext.tree.TreeNodeUI,{
399     onOver : function(e){
400         Ext.debug.ComponentNodeUI.superclass.onOver.call(this);
401         var cmp = this.node.attributes.component;
402         if (cmp.el && cmp.el.mask && cmp.id !='x-debug-browser') {
403             try { // Oddly bombs on some elements in IE, gets any we care about though
404                 cmp.el.mask();
405             } catch(e) {}
406         }
407     },
408
409     onOut : function(e){
410         Ext.debug.ComponentNodeUI.superclass.onOut.call(this);
411         var cmp = this.node.attributes.component;
412         if (cmp.el && cmp.el.unmask && cmp.id !='x-debug-browser') {
413             try {
414                 cmp.el.unmask();
415             } catch(e) {}
416         }
417     }
418 });
419
420 Ext.debug.ComponentInspector = Ext.extend(Ext.tree.TreePanel, {
421     enableDD:false ,
422     lines:false,
423     rootVisible:false,
424     animate:false,
425     hlColor:'ffff9c',
426     autoScroll: true,
427     region:'center',
428     border:false,
429
430     initComponent : function(){
431         this.loader = new Ext.tree.TreeLoader();
432         this.bbar = new Ext.Toolbar([{
433             text: 'Refresh',
434             handler: this.refresh,
435             scope: this
436         }]);
437         Ext.debug.ComponentInspector.superclass.initComponent.call(this);
438
439         this.root = this.setRootNode(new Ext.tree.TreeNode({
440             text: 'Ext Components',
441             component: Ext.ComponentMgr.all,
442             leaf: false
443         }));
444         this.parseRootNode();
445
446         this.on('click', this.onClick, this);
447     },
448
449     createNode: function(n,c) {
450         var leaf = (c.items && c.items.length > 0);
451         return n.appendChild(new Ext.tree.TreeNode({
452             text: c.id + (c.getXType() ? ' [ ' + c.getXType() + ' ]': '' ),
453             component: c,
454             uiProvider:Ext.debug.ComponentNodeUI,
455             leaf: !leaf
456         }));
457     },
458
459     parseChildItems: function(n) {
460         var cn = n.attributes.component.items;
461         if (cn) {
462             for (var i = 0;i < cn.length; i++) {
463                 var c = cn.get(i);
464                 if (c.id != this.id && c.id != this.bottomToolbar.id) {
465                     var newNode = this.createNode(n,c);
466                     if (!newNode.leaf) {
467                         this.parseChildItems(newNode)
468                     }
469                 }
470             }
471         }
472     },
473
474     parseRootNode: function() {
475         var n = this.root;
476         var cn = n.attributes.component.items;
477         for (var i = 0,c;c = cn[i];i++) {
478             if (c.id != this.id && c.id != this.bottomToolbar.id) {
479                 if (!c.ownerCt) {
480                     var newNode = this.createNode(n,c);
481                     if (!newNode.leaf) {
482                         this.parseChildItems(newNode);
483                     }
484                 }
485             }
486         }
487     },
488
489     onClick: function(node, e) {
490         var oi = Ext.getCmp('x-debug-objinspector');
491         oi.refreshNodes(node.attributes.component);
492         oi.ownerCt.show();
493     },
494
495     refresh: function() {
496         while (this.root.firstChild) {
497             this.root.removeChild(this.root.firstChild);
498         }
499         this.parseRootNode();
500         var ci = Ext.getCmp('x-debug-compinfo');
501         if (ci) {
502             ci.message('refreshed component tree - '+Ext.ComponentMgr.all.length)
503         }
504     }
505 });
506
507 Ext.debug.ComponentInfoPanel = Ext.extend(Ext.Panel,{
508     id:'x-debug-compinfo',
509     region: 'east',
510     minWidth: 200,
511     split: true,
512     width: 350,
513     border: false,
514     autoScroll: true,
515     layout:'anchor',
516     style:'border-width:0 0 0 1px;',
517
518     initComponent: function() {
519         this.watchBox = new Ext.form.Checkbox({
520             id: 'x-debug-watchcomp',
521             boxLabel: 'Watch ComponentMgr',
522             listeners: {
523                 check: function(cb, val) {
524                     if (val) {
525                         Ext.ComponentMgr.all.on('add', this.onAdd, this);
526                         Ext.ComponentMgr.all.on('remove', this.onRemove, this);
527                     } else {
528                         Ext.ComponentMgr.all.un('add', this.onAdd, this);
529                         Ext.ComponentMgr.all.un('remove', this.onRemove, this);
530                     }
531                 },
532                 scope: this
533             }
534         });
535
536         this.tbar = new Ext.Toolbar([{
537             text: 'Clear',
538             handler: this.clear,
539             scope: this
540         },'->',this.watchBox
541         ]);
542         Ext.debug.ComponentInfoPanel.superclass.initComponent.call(this);
543     },
544
545     onAdd: function(i, o, key) {
546         var markup = ['<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
547                     'Added: '+o.id,
548                     '</div>'].join('');
549         this.insertMarkup(markup);
550     },
551
552     onRemove: function(o, key) {
553         var markup = ['<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
554                     'Removed: '+o.id,
555                     '</div>'].join('');
556         this.insertMarkup(markup);
557     },
558
559     message: function(msg) {
560         var markup = ['<div style="padding:5px !important;border-bottom:1px solid #ccc;">',
561                     msg,
562                     '</div>'].join('');
563         this.insertMarkup(markup);
564     },
565     insertMarkup: function(markup) {
566         this.body.insertHtml('beforeend', markup);
567         this.body.scrollTo('top', 100000);
568     },
569     clear : function(){
570         this.body.update('');
571         this.body.dom.scrollTop = 0;
572     }
573 });
574
575 Ext.debug.ColumnNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
576     focus: Ext.emptyFn, // prevent odd scrolling behavior
577
578     renderElements : function(n, a, targetNode, bulkRender){
579         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
580
581         var t = n.getOwnerTree();
582         var cols = t.columns;
583         var bw = t.borderWidth;
584         var c = cols[0];
585
586         var buf = [
587              '<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf ', a.cls,'">',
588                 '<div class="x-tree-col" style="width:',c.width-bw,'px;">',
589                     '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
590                     '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow"/>',
591                     '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on"/>',
592                     '<a hidefocus="on" class="x-tree-node-anchor" href="',a.href ? a.href : "#",'" tabIndex="1" ',
593                     a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '>',
594                     '<span unselectable="on">', n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</span></a>",
595                 "</div>"];
596          for(var i = 1, len = cols.length; i < len; i++){
597              c = cols[i];
598
599              buf.push('<div class="x-tree-col ',(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
600                         '<div class="x-tree-col-text">',(c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</div>",
601                       "</div>");
602          }
603          buf.push(
604             '<div class="x-clear"></div></div>',
605             '<ul class="x-tree-node-ct" style="display:none;"></ul>',
606             "</li>");
607
608         if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
609             this.wrap = Ext.DomHelper.insertHtml("beforeBegin",
610                                 n.nextSibling.ui.getEl(), buf.join(""));
611         }else{
612             this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
613         }
614
615         this.elNode = this.wrap.childNodes[0];
616         this.ctNode = this.wrap.childNodes[1];
617         var cs = this.elNode.firstChild.childNodes;
618         this.indentNode = cs[0];
619         this.ecNode = cs[1];
620         this.iconNode = cs[2];
621         this.anchor = cs[3];
622         this.textNode = cs[3].firstChild;
623     }
624 });
625
626 Ext.debug.ObjectInspector = Ext.extend(Ext.tree.TreePanel, {
627     id: 'x-debug-objinspector',
628     enableDD:false ,
629     lines:false,
630     rootVisible:false,
631     animate:false,
632     hlColor:'ffff9c',
633     autoScroll: true,
634     region:'center',
635     border:false,
636     lines:false,
637     borderWidth: Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
638     cls:'x-column-tree',
639
640     initComponent : function(){
641         this.showFunc = false;
642         this.toggleFunc = function() {
643             this.showFunc = !this.showFunc;
644             this.refreshNodes(this.currentObject);
645         }
646         this.bbar = new Ext.Toolbar([{
647             text: 'Show Functions',
648             enableToggle: true,
649             pressed: false,
650             handler: this.toggleFunc,
651             scope: this
652         }]);
653
654         Ext.apply(this,{
655             title: ' ',
656             loader: new Ext.tree.TreeLoader(),
657             columns:[{
658                 header:'Property',
659                 width: 300,
660                 dataIndex:'name'
661             },{
662                 header:'Value',
663                 width: 900,
664                 dataIndex:'value'
665             }]
666         });
667
668         Ext.debug.ObjectInspector.superclass.initComponent.call(this);
669
670         this.root = this.setRootNode(new Ext.tree.TreeNode({
671             text: 'Dummy Node',
672             leaf: false
673         }));
674
675         if (this.currentObject) {
676             this.parseNodes();
677         }
678     },
679
680     refreshNodes: function(newObj) {
681         this.currentObject = newObj;
682         var node = this.root;
683         while(node.firstChild){
684             node.removeChild(node.firstChild);
685         }
686         this.parseNodes();
687     },
688
689     parseNodes: function() {
690         for (var o in this.currentObject) {
691             if (!this.showFunc) {
692                 if (Ext.isFunction(this.currentObject[o])) {
693                     continue;
694                 }
695             }
696             this.createNode(o);
697         }
698     },
699
700     createNode: function(o) {
701         return this.root.appendChild(new Ext.tree.TreeNode({
702             name: o,
703             value: this.currentObject[o],
704             uiProvider:Ext.debug.ColumnNodeUI,
705             iconCls: 'x-debug-node',
706             leaf: true
707         }));
708     },
709
710     onRender : function(){
711         Ext.debug.ObjectInspector.superclass.onRender.apply(this, arguments);
712         this.headers = this.header.createChild({cls:'x-tree-headers'});
713
714         var cols = this.columns, c;
715         var totalWidth = 0;
716
717         for(var i = 0, len = cols.length; i < len; i++){
718              c = cols[i];
719              totalWidth += c.width;
720              this.headers.createChild({
721                  cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
722                  cn: {
723                      cls:'x-tree-hd-text',
724                      html: c.header
725                  },
726                  style:'width:'+(c.width-this.borderWidth)+'px;'
727              });
728         }
729         this.headers.createChild({cls:'x-clear'});
730         // prevent floats from wrapping when clipped
731         this.headers.setWidth(totalWidth);
732         this.innerCt.setWidth(totalWidth);
733     }
734 });
735
736
737 Ext.debug.StoreInspector = Ext.extend(Ext.tree.TreePanel, {
738     enableDD:false ,
739     lines:false,
740     rootVisible:false,
741     animate:false,
742     hlColor:'ffff9c',
743     autoScroll: true,
744     region:'center',
745     border:false,
746
747     initComponent: function() {
748         this.bbar = new Ext.Toolbar([{
749             text: 'Refresh',
750             handler: this.refresh,
751             scope: this
752         }]);
753         Ext.debug.StoreInspector.superclass.initComponent.call(this);
754
755         this.root = this.setRootNode(new Ext.tree.TreeNode({
756             text: 'Data Stores',
757             leaf: false
758         }));
759         this.on('click', this.onClick, this);
760
761         this.parseStores();
762     },
763
764     parseStores: function() {
765         var cn = Ext.StoreMgr.items;
766         for (var i = 0,c;c = cn[i];i++) {
767             this.root.appendChild({
768                 text: c.storeId + ' - ' + c.totalLength + ' records',
769                 component: c,
770                 leaf: true
771             });
772         }
773     },
774
775     onClick: function(node, e) {
776         var oi = Ext.getCmp('x-debug-objinspector');
777         oi.refreshNodes(node.attributes.component);
778         oi.ownerCt.show();
779     },
780
781     refresh: function() {
782         while (this.root.firstChild) {
783             this.root.removeChild(this.root.firstChild);
784         }
785         this.parseStores();
786     }
787 });
788
789 // highly unusual class declaration
790 Ext.debug.HtmlNode = function(){
791     var html = Ext.util.Format.htmlEncode;
792     var ellipsis = Ext.util.Format.ellipsis;
793     var nonSpace = /^\s*$/;
794
795     var attrs = [
796         {n: 'id', v: 'id'},
797         {n: 'className', v: 'class'},
798         {n: 'name', v: 'name'},
799         {n: 'type', v: 'type'},
800         {n: 'src', v: 'src'},
801         {n: 'href', v: 'href'}
802     ];
803
804     function hasChild(n){
805         for(var i = 0, c; c = n.childNodes[i]; i++){
806             if(c.nodeType == 1){
807                 return true;
808             }
809         }
810         return false;
811     }
812
813     function renderNode(n, leaf){
814         var tag = n.tagName.toLowerCase();
815         var s = '&lt;' + tag;
816         for(var i = 0, len = attrs.length; i < len; i++){
817             var a = attrs[i];
818             var v = n[a.n];
819             if(v && !nonSpace.test(v)){
820                 s += ' ' + a.v + '=&quot;<i>' + html(v) +'</i>&quot;';
821             }
822         }
823         var style = n.style ? n.style.cssText : '';
824         if(style){
825             s += ' style=&quot;<i>' + html(style.toLowerCase()) +'</i>&quot;';
826         }
827         if(leaf && n.childNodes.length > 0){
828             s+='&gt;<em>' + ellipsis(html(String(n.innerHTML)), 35) + '</em>&lt;/'+tag+'&gt;';
829         }else if(leaf){
830             s += ' /&gt;';
831         }else{
832             s += '&gt;';
833         }
834         return s;
835     }
836
837     var HtmlNode = function(n){
838         var leaf = !hasChild(n);
839         this.htmlNode = n;
840         this.tagName = n.tagName.toLowerCase();
841         var attr = {
842             text : renderNode(n, leaf),
843             leaf : leaf,
844             cls: 'x-tree-noicon'
845         };
846         HtmlNode.superclass.constructor.call(this, attr);
847         this.attributes.htmlNode = n; // for searching
848         if(!leaf){
849             this.on('expand', this.onExpand,  this);
850             this.on('collapse', this.onCollapse,  this);
851         }
852     };
853
854
855     Ext.extend(HtmlNode, Ext.tree.AsyncTreeNode, {
856         cls: 'x-tree-noicon',
857         preventHScroll: true,
858         refresh : function(highlight){
859             var leaf = !hasChild(this.htmlNode);
860             this.setText(renderNode(this.htmlNode, leaf));
861             if(highlight){
862                 Ext.fly(this.ui.textNode).highlight();
863             }
864         },
865
866         onExpand : function(){
867             if(!this.closeNode && this.parentNode){
868                 this.closeNode = this.parentNode.insertBefore(new Ext.tree.TreeNode({
869                     text:'&lt;/' + this.tagName + '&gt;',
870                     cls: 'x-tree-noicon'
871                 }), this.nextSibling);
872             }else if(this.closeNode){
873                 this.closeNode.ui.show();
874             }
875         },
876
877         onCollapse : function(){
878             if(this.closeNode){
879                 this.closeNode.ui.hide();
880             }
881         },
882
883         render : function(bulkRender){
884             HtmlNode.superclass.render.call(this, bulkRender);
885         },
886
887         highlightNode : function(){
888             //Ext.fly(this.htmlNode).highlight();
889         },
890
891         highlight : function(){
892             //Ext.fly(this.ui.textNode).highlight();
893         },
894
895         frame : function(){
896             this.htmlNode.style.border = '1px solid #0000ff';
897             //this.highlightNode();
898         },
899
900         unframe : function(){
901             //Ext.fly(this.htmlNode).removeClass('x-debug-frame');
902             this.htmlNode.style.border = '';
903         }
904     });
905
906     return HtmlNode;
907 }();</pre>    \r
908 </body>\r
909 </html>