]> git.wh0rd.org Git - tt-rss.git/blob - lib/dojo/_firebug/firebug.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dojo / _firebug / firebug.js.uncompressed.js
1 define("dojo/_firebug/firebug", ["../_base/kernel", "require", "../_base/html", "../_base/sniff", "../_base/array", "../_base/lang", "../_base/event", "../_base/unload"], function(dojo, require) {
2         // module:
3         //              dojo/_firebug/firebug
4         // summary:
5
6 // FIREBUG LITE
7         // summary: Firebug Lite, the baby brother to Joe Hewitt's Firebug for Mozilla Firefox
8         // description:
9         //              Opens a console for logging, debugging, and error messages.
10         //              Contains partial functionality to Firebug. See function list below.
11         //      NOTE:
12         //                      Firebug is a Firefox extension created by Joe Hewitt (see license). You do not need Dojo to run Firebug.
13         //                      Firebug Lite is included in Dojo by permission from Joe Hewitt
14         //                      If you are new to Firebug, or used to the Dojo 0.4 dojo.debug, you can learn Firebug
15         //                              functionality by reading the function comments below or visiting http://www.getfirebug.com/docs.html
16         //      NOTE:
17         //              To test Firebug Lite in Firefox:
18         //                      FF2: set "console = null" before loading dojo and set djConfig.isDebug=true
19         //                      FF3: disable Firebug and set djConfig.isDebug=true
20         //
21         // example:
22         //              Supports inline objects in object inspector window (only simple trace of dom nodes, however)
23         //              |       console.log("my object", {foo:"bar"})
24         // example:
25         //              Option for console to open in popup window
26         //              |       var djConfig = {isDebug: true, popup:true };
27         // example:
28         //              Option for console height (ignored for popup)
29         //              |       var djConfig = {isDebug: true, debugHeight:100 }
30
31
32         var isNewIE = (/Trident/.test(window.navigator.userAgent));
33         if(isNewIE){
34                 // Fixing IE's console
35                 // IE doesn't insert space between arguments. How annoying.
36                 var calls = ["log", "info", "debug", "warn", "error"];
37                 for(var i=0;i<calls.length;i++){
38                         var m = calls[i];
39                         if(!console[m] ||console[m]._fake){
40                                 // IE9 doesn't have console.debug method, a fake one is added later
41                                 continue;
42                         }
43                         var n = "_"+calls[i];
44                         console[n] = console[m];
45                         console[m] = (function(){
46                                 var type = n;
47                                 return function(){
48                                         console[type](Array.prototype.join.call(arguments, " "));
49                                 };
50                         })();
51                 }
52                 // clear the console on load. This is more than a convenience - too many logs crashes it.
53                 // If closed it throws an error
54                 try{ console.clear(); }catch(e){}
55         }
56
57         if(
58                 dojo.isFF ||                                                            // Firefox has Firebug
59                 dojo.isChrome ||                                                        // Chrome 3+ has a console
60                 dojo.isSafari ||                                                        // Safari 4 has a console
61                 isNewIE ||                                                                      // Has the new IE console
62                 window.firebug ||                                                       // Testing for mozilla firebug lite
63                 (typeof console != "undefined" && console.firebug) || //The firebug console
64                 dojo.config.useCustomLogger ||                          // Allow custom loggers
65                 dojo.isAIR                                                                      // isDebug triggers AIRInsector, not Firebug
66         ){
67                 return;
68         }
69
70         // don't build firebug in iframes
71         try{
72                 if(window != window.parent){
73                         // but if we've got a parent logger, connect to it
74                         if(window.parent["console"]){
75                                 window.console = window.parent.console;
76                         }
77                         return;
78                 }
79         }catch(e){/*squelch*/}
80
81         // ***************************************************************************
82         // Placing these variables before the functions that use them to avoid a
83         // shrinksafe bug where variable renaming does not happen correctly otherwise.
84
85         // most of the objects in this script are run anonomously
86         var _firebugDoc = document;
87         var _firebugWin = window;
88         var __consoleAnchorId__ = 0;
89
90         var consoleFrame = null;
91         var consoleBody = null;
92         var consoleObjectInspector = null;
93         var fireBugTabs = null;
94         var commandLine = null;
95         var consoleToolbar = null;
96
97         var frameVisible = false;
98         var messageQueue = [];
99         var groupStack = [];
100         var timeMap = {};
101         var countMap = {};
102
103         var consoleDomInspector = null;
104         var _inspectionMoveConnection;
105         var _inspectionClickConnection;
106         var _inspectionEnabled = false;
107         var _inspectionTimer = null;
108         var _inspectTempNode = document.createElement("div");
109
110
111         var _inspectCurrentNode;
112         var _restoreBorderStyle;
113
114         // ***************************************************************************
115
116         window.console = {
117                 _connects: [],
118                 log: function(){
119                         // summary:
120                         //              Sends arguments to console.
121                         logFormatted(arguments, "");
122                 },
123
124                 debug: function(){
125                         // summary:
126                         //              Sends arguments to console. Missing finctionality to show script line of trace.
127                         logFormatted(arguments, "debug");
128                 },
129
130                 info: function(){
131                         // summary:
132                         //              Sends arguments to console, highlighted with (I) icon.
133                         logFormatted(arguments, "info");
134                 },
135
136                 warn: function(){
137                         // summary:
138                         //              Sends warning arguments to console, highlighted with (!) icon and blue style.
139                         logFormatted(arguments, "warning");
140                 },
141
142                 error: function(){
143                         // summary:
144                         //              Sends error arguments (object) to console, highlighted with (X) icon and yellow style
145                         //                      NEW: error object now displays in object inspector
146                         logFormatted(arguments, "error");
147                 },
148
149                 assert: function(truth, message){
150                         // summary:
151                         //              Tests for true. Throws exception if false.
152                         if(!truth){
153                                 var args = [];
154                                 for(var i = 1; i < arguments.length; ++i){
155                                         args.push(arguments[i]);
156                                 }
157
158                                 logFormatted(args.length ? args : ["Assertion Failure"], "error");
159                                 throw message ? message : "Assertion Failure";
160                         }
161                 },
162
163                 dir: function(obj){
164                         var str = printObject( obj );
165                         str = str.replace(/\n/g, "<br />");
166                         str = str.replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp;");
167                         logRow([str], "dir");
168                 },
169
170                 dirxml: function(node){
171                         // summary:
172                         //
173                         var html = [];
174                         appendNode(node, html);
175                         logRow(html, "dirxml");
176                 },
177
178                 group: function(){
179                         // summary:
180                         //              collects log messages into a group, starting with this call and ending with
181                         //                      groupEnd(). Missing collapse functionality
182                         logRow(arguments, "group", pushGroup);
183                 },
184
185                 groupEnd: function(){
186                         // summary:
187                         //              Closes group. See above
188                         logRow(arguments, "", popGroup);
189                 },
190
191                 time: function(name){
192                         // summary:
193                         //              Starts timers assigned to name given in argument. Timer stops and displays on timeEnd(title);
194                         //      example:
195                         //      |       console.time("load");
196                         //      |       console.time("myFunction");
197                         //      |       console.timeEnd("load");
198                         //      |       console.timeEnd("myFunction");
199                         timeMap[name] = new Date().getTime();
200                 },
201
202                 timeEnd: function(name){
203                         // summary:
204                         //              See above.
205                         if(name in timeMap){
206                                 var delta = (new Date()).getTime() - timeMap[name];
207                                 logFormatted([name+ ":", delta+"ms"]);
208                                 delete timeMap[name];
209                         }
210                 },
211
212                 count: function(name){
213                         // summary:
214                         //              Not supported
215                         if(!countMap[name]) countMap[name] = 0;
216                         countMap[name]++;
217                         logFormatted([name+": "+countMap[name]]);
218                 },
219
220                 trace: function(_value){
221                         var stackAmt = _value || 3;
222                         var f = console.trace.caller; //function that called trace
223                         console.log(">>> console.trace(stack)");
224                         for(var i=0;i<stackAmt;i++){
225                                 var func = f.toString();
226                                 var args=[];
227                                 for (var a = 0; a < f.arguments.length; a++) {
228                                         args.push(f.arguments[a]);
229                                 }
230                                 if(f.arguments.length){
231                                         console.dir({"function":func, "arguments":args});
232                                 }else{
233                                         console.dir({"function":func});
234                                 }
235
236                                 f = f.caller;
237                         }
238                 },
239
240                 profile: function(){
241                         // summary:
242                         //              Not supported
243                         this.warn(["profile() not supported."]);
244                 },
245
246                 profileEnd: function(){ },
247
248                 clear: function(){
249                         // summary:
250                         //              Clears message console. Do not call this directly
251                         if(consoleBody){
252                                 while(consoleBody.childNodes.length){
253                                         dojo.destroy(consoleBody.firstChild);
254                                 }
255                         }
256                         dojo.forEach(this._connects,dojo.disconnect);
257                 },
258
259                 open: function(){
260                         // summary:
261                         //              Opens message console. Do not call this directly
262                         toggleConsole(true);
263                 },
264
265                 close: function(){
266                         // summary:
267                         //              Closes message console. Do not call this directly
268                         if(frameVisible){
269                                 toggleConsole();
270                         }
271                 },
272                 _restoreBorder: function(){
273                         if(_inspectCurrentNode){
274                                 _inspectCurrentNode.style.border = _restoreBorderStyle;
275                         }
276                 },
277                 openDomInspector: function(){
278                         _inspectionEnabled = true;
279                         consoleBody.style.display = "none";
280                         consoleDomInspector.style.display = "block";
281                         consoleObjectInspector.style.display = "none";
282                         document.body.style.cursor = "pointer";
283                         _inspectionMoveConnection = dojo.connect(document, "mousemove", function(evt){
284                                 if(!_inspectionEnabled){ return; }
285                                 if(!_inspectionTimer){
286                                         _inspectionTimer = setTimeout(function(){ _inspectionTimer = null; }, 50);
287                                 }else{
288                                         return;
289                                 }
290                                 var node = evt.target;
291                                 if(node && (_inspectCurrentNode !== node)){
292                                         var parent = true;
293
294                                         console._restoreBorder();
295                                         var html = [];
296                                         appendNode(node, html);
297                                         consoleDomInspector.innerHTML = html.join("");
298
299                                         _inspectCurrentNode = node;
300                                         _restoreBorderStyle = _inspectCurrentNode.style.border;
301                                         _inspectCurrentNode.style.border = "#0000FF 1px solid";
302                                 }
303                         });
304                         setTimeout(function(){
305                                 _inspectionClickConnection = dojo.connect(document, "click", function(evt){
306                                         document.body.style.cursor = "";
307                                         _inspectionEnabled = !_inspectionEnabled;
308                                         dojo.disconnect(_inspectionClickConnection);
309                                         // console._restoreBorder();
310                                 });
311                         }, 30);
312                 },
313                 _closeDomInspector: function(){
314                         document.body.style.cursor = "";
315                         dojo.disconnect(_inspectionMoveConnection);
316                         dojo.disconnect(_inspectionClickConnection);
317                         _inspectionEnabled = false;
318                         console._restoreBorder();
319                 },
320                 openConsole:function(){
321                         // summary:
322                         //              Closes object inspector and opens message console. Do not call this directly
323                         consoleBody.style.display = "block";
324                         consoleDomInspector.style.display = "none";
325                         consoleObjectInspector.style.display = "none";
326                         console._closeDomInspector();
327                 },
328                 openObjectInspector:function(){
329                         consoleBody.style.display = "none";
330                         consoleDomInspector.style.display = "none";
331                         consoleObjectInspector.style.display = "block";
332                         console._closeDomInspector();
333                 },
334                 recss: function(){
335                         // http://turtle.dojotoolkit.org/~david/recss.html
336                         // this is placed in dojo since the console is most likely
337                         // in another window and dojo is easilly accessible
338                         var i,a,s;a=document.getElementsByTagName('link');
339                         for(i=0;i<a.length;i++){
340                                 s=a[i];
341                                 if(s.rel.toLowerCase().indexOf('stylesheet')>=0&&s.href) {
342                                         var h=s.href.replace(/(&|%5C?)forceReload=\d+/,'');
343                                         s.href=h+(h.indexOf('?')>=0?'&':'?')+'forceReload='+new Date().valueOf();
344                                 }
345                         }
346                 }
347         };
348
349         // ***************************************************************************
350
351         function toggleConsole(forceOpen){
352                 frameVisible = forceOpen || !frameVisible;
353                 if(consoleFrame){
354                         consoleFrame.style.display = frameVisible ? "block" : "none";
355                 }
356         }
357
358         function focusCommandLine(){
359                 toggleConsole(true);
360                 if(commandLine){
361                         commandLine.focus();
362                 }
363         }
364
365         function openWin(x,y,w,h){
366                 var win = window.open("","_firebug","status=0,menubar=0,resizable=1,top="+y+",left="+x+",width="+w+",height="+h+",scrollbars=1,addressbar=0");
367                 if(!win){
368                         var msg = "Firebug Lite could not open a pop-up window, most likely because of a blocker.\n" +
369                                 "Either enable pop-ups for this domain, or change the djConfig to popup=false.";
370                         alert(msg);
371                 }
372                 createResizeHandler(win);
373                 var newDoc=win.document;
374                 //Safari needs an HTML height
375                 var HTMLstring= '<html style="height:100%;"><head><title>Firebug Lite</title></head>\n' +
376                                         '<body bgColor="#ccc" style="height:97%;" onresize="opener.onFirebugResize()">\n' +
377                                         '<div id="fb"></div>' +
378                                         '</body></html>';
379
380                 newDoc.write(HTMLstring);
381                 newDoc.close();
382                 return win;
383         }
384
385         function createResizeHandler(wn){
386                 // summary:
387                 //              Creates handle for onresize window. Called from script in popup's body tag (so that it will work with IE).
388                 //
389
390                 var d = new Date();
391                         d.setTime(d.getTime()+(60*24*60*60*1000)); // 60 days
392                         d = d.toUTCString();
393
394                         var dc = wn.document,
395                                 getViewport;
396
397                         if (wn.innerWidth){
398                                 getViewport = function(){
399                                         return{w:wn.innerWidth, h:wn.innerHeight};
400                                 };
401                         }else if (dc.documentElement && dc.documentElement.clientWidth){
402                                 getViewport = function(){
403                                         return{w:dc.documentElement.clientWidth, h:dc.documentElement.clientHeight};
404                                 };
405                         }else if (dc.body){
406                                 getViewport = function(){
407                                         return{w:dc.body.clientWidth, h:dc.body.clientHeight};
408                                 };
409                         }
410
411
412                 window.onFirebugResize = function(){
413
414                         //resize the height of the console log body
415                         layout(getViewport().h);
416
417                         clearInterval(wn._firebugWin_resize);
418                         wn._firebugWin_resize = setTimeout(function(){
419                                 var x = wn.screenLeft,
420                                         y = wn.screenTop,
421                                         w = wn.outerWidth  || wn.document.body.offsetWidth,
422                                         h = wn.outerHeight || wn.document.body.offsetHeight;
423
424                                 document.cookie = "_firebugPosition=" + [x,y,w,h].join(",") + "; expires="+d+"; path=/";
425
426                          }, 5000); //can't capture window.onMove - long timeout gives better chance of capturing a resize, then the move
427
428                 };
429         }
430
431
432         /*****************************************************************************/
433
434
435         function createFrame(){
436                 if(consoleFrame){
437                         return;
438                 }
439                 toggleConsole(true);
440                 if(dojo.config.popup){
441                         var containerHeight = "100%";
442                         var cookieMatch = document.cookie.match(/(?:^|; )_firebugPosition=([^;]*)/);
443                         var p = cookieMatch ? cookieMatch[1].split(",") : [2,2,320,480];
444
445                         _firebugWin = openWin(p[0],p[1],p[2],p[3]);     // global
446                         _firebugDoc = _firebugWin.document;                     // global
447
448                         dojo.config.debugContainerId = 'fb';
449
450                         // connecting popup
451                         _firebugWin.console = window.console;
452                         _firebugWin.dojo = window.dojo;
453                 }else{
454                         _firebugDoc = document;
455                         containerHeight = (dojo.config.debugHeight || 300) + "px";
456                 }
457
458                 var styleElement = _firebugDoc.createElement("link");
459                 styleElement.href = require.toUrl("./firebug.css");
460                 styleElement.rel = "stylesheet";
461                 styleElement.type = "text/css";
462                 var styleParent = _firebugDoc.getElementsByTagName("head");
463                 if(styleParent){
464                         styleParent = styleParent[0];
465                 }
466                 if(!styleParent){
467                         styleParent = _firebugDoc.getElementsByTagName("html")[0];
468                 }
469                 if(dojo.isIE){
470                         window.setTimeout(function(){ styleParent.appendChild(styleElement); }, 0);
471                 }else{
472                         styleParent.appendChild(styleElement);
473                 }
474
475                 if(dojo.config.debugContainerId){
476                         consoleFrame = _firebugDoc.getElementById(dojo.config.debugContainerId);
477                 }
478                 if(!consoleFrame){
479                         consoleFrame = _firebugDoc.createElement("div");
480                         _firebugDoc.body.appendChild(consoleFrame);
481                 }
482                 consoleFrame.className += " firebug";
483                 consoleFrame.style.height = containerHeight;
484                 consoleFrame.style.display = (frameVisible ? "block" : "none");
485
486                 var buildLink = function(label, title, method, _class){
487                         return '<li class="'+_class+'"><a href="javascript:void(0);" onclick="console.'+ method +'(); return false;" title="'+title+'">'+label+'</a></li>';
488                 };
489                 consoleFrame.innerHTML =
490                           '<div id="firebugToolbar">'
491                         + '  <ul id="fireBugTabs" class="tabs">'
492
493                         + buildLink("Clear", "Remove All Console Logs", "clear", "")
494                         + buildLink("ReCSS", "Refresh CSS without reloading page", "recss", "")
495
496                         + buildLink("Console", "Show Console Logs", "openConsole", "gap")
497                         + buildLink("DOM", "Show DOM Inspector", "openDomInspector", "")
498                         + buildLink("Object", "Show Object Inspector", "openObjectInspector", "")
499                         + ((dojo.config.popup) ? "" : buildLink("Close", "Close the console", "close", "gap"))
500
501                         + '     </ul>'
502                         + '</div>'
503                         + '<input type="text" id="firebugCommandLine" />'
504                         + '<div id="firebugLog"></div>'
505                         + '<div id="objectLog" style="display:none;">Click on an object in the Log display</div>'
506                         + '<div id="domInspect" style="display:none;">Hover over HTML elements in the main page. Click to hold selection.</div>';
507
508
509                 consoleToolbar = _firebugDoc.getElementById("firebugToolbar");
510
511                 commandLine = _firebugDoc.getElementById("firebugCommandLine");
512                 addEvent(commandLine, "keydown", onCommandLineKeyDown);
513
514                 addEvent(_firebugDoc, dojo.isIE || dojo.isSafari ? "keydown" : "keypress", onKeyDown);
515
516                 consoleBody = _firebugDoc.getElementById("firebugLog");
517                 consoleObjectInspector = _firebugDoc.getElementById("objectLog");
518                 consoleDomInspector = _firebugDoc.getElementById("domInspect");
519                 fireBugTabs = _firebugDoc.getElementById("fireBugTabs");
520                 layout();
521                 flush();
522         }
523
524         dojo.addOnLoad(createFrame);
525
526         function clearFrame(){
527                 _firebugDoc = null;
528
529                 if(_firebugWin.console){
530                         _firebugWin.console.clear();
531                 }
532                 _firebugWin = null;
533                 consoleFrame = null;
534                 consoleBody = null;
535                 consoleObjectInspector = null;
536                 consoleDomInspector = null;
537                 commandLine = null;
538                 messageQueue = [];
539                 groupStack = [];
540                 timeMap = {};
541         }
542
543
544         function evalCommandLine(){
545                 var text = commandLine.value;
546                 commandLine.value = "";
547
548                 logRow([">  ", text], "command");
549
550                 var value;
551                 try{
552                         value = eval(text);
553                 }catch(e){
554                         console.debug(e); // put exception on the console
555                 }
556
557                 console.log(value);
558         }
559
560         function layout(h){
561                 var tHeight = 25; //consoleToolbar.offsetHeight; // tab style not ready on load - throws off layout
562                 var height = h ?
563                         h  - (tHeight + commandLine.offsetHeight +25 + (h*.01)) + "px" :
564                         (consoleFrame.offsetHeight - tHeight - commandLine.offsetHeight) + "px";
565
566                 consoleBody.style.top = tHeight + "px";
567                 consoleBody.style.height = height;
568                 consoleObjectInspector.style.height = height;
569                 consoleObjectInspector.style.top = tHeight + "px";
570                 consoleDomInspector.style.height = height;
571                 consoleDomInspector.style.top = tHeight + "px";
572                 commandLine.style.bottom = 0;
573
574                 dojo.addOnWindowUnload(clearFrame);
575         }
576
577         function logRow(message, className, handler){
578                 if(consoleBody){
579                         writeMessage(message, className, handler);
580                 }else{
581                         messageQueue.push([message, className, handler]);
582                 }
583         }
584
585         function flush(){
586                 var queue = messageQueue;
587                 messageQueue = [];
588
589                 for(var i = 0; i < queue.length; ++i){
590                         writeMessage(queue[i][0], queue[i][1], queue[i][2]);
591                 }
592         }
593
594         function writeMessage(message, className, handler){
595                 var isScrolledToBottom =
596                         consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight;
597
598                 handler = handler||writeRow;
599
600                 handler(message, className);
601
602                 if(isScrolledToBottom){
603                         consoleBody.scrollTop = consoleBody.scrollHeight - consoleBody.offsetHeight;
604                 }
605         }
606
607         function appendRow(row){
608                 var container = groupStack.length ? groupStack[groupStack.length-1] : consoleBody;
609                 container.appendChild(row);
610         }
611
612         function writeRow(message, className){
613                 var row = consoleBody.ownerDocument.createElement("div");
614                 row.className = "logRow" + (className ? " logRow-"+className : "");
615                 row.innerHTML = message.join("");
616                 appendRow(row);
617         }
618
619         function pushGroup(message, className){
620                 logFormatted(message, className);
621
622                 //var groupRow = consoleBody.ownerDocument.createElement("div");
623                 //groupRow.className = "logGroup";
624                 var groupRowBox = consoleBody.ownerDocument.createElement("div");
625                 groupRowBox.className = "logGroupBox";
626                 //groupRow.appendChild(groupRowBox);
627                 appendRow(groupRowBox);
628                 groupStack.push(groupRowBox);
629         }
630
631         function popGroup(){
632                 groupStack.pop();
633         }
634
635         // ***************************************************************************
636
637         function logFormatted(objects, className){
638                 var html = [];
639
640                 var format = objects[0];
641                 var objIndex = 0;
642
643                 if(typeof(format) != "string"){
644                         format = "";
645                         objIndex = -1;
646                 }
647
648                 var parts = parseFormat(format);
649
650                 for(var i = 0; i < parts.length; ++i){
651                         var part = parts[i];
652                         if(part && typeof part == "object"){
653                                 part.appender(objects[++objIndex], html);
654                         }else{
655                                 appendText(part, html);
656                         }
657                 }
658
659
660                 var ids = [];
661                 var obs = [];
662                 for(i = objIndex+1; i < objects.length; ++i){
663                         appendText(" ", html);
664
665                         var object = objects[i];
666                         if(object === undefined || object === null ){
667                                 appendNull(object, html);
668
669                         }else if(typeof(object) == "string"){
670                                 appendText(object, html);
671
672                         }else if(object instanceof Date){
673                                 appendText(object.toString(), html);
674
675                         }else if(object.nodeType == 9){
676                                 appendText("[ XmlDoc ]", html);
677
678                         }else{
679                                 // Create link for object inspector
680                                 // need to create an ID for this link, since it is currently text
681                                 var id = "_a" + __consoleAnchorId__++;
682                                 ids.push(id);
683                                 // need to save the object, so the arrays line up
684                                 obs.push(object);
685                                 var str = '<a id="'+id+'" href="javascript:void(0);">'+getObjectAbbr(object)+'</a>';
686
687                                 appendLink( str , html);
688                         }
689                 }
690
691                 logRow(html, className);
692
693                 // Now that the row is inserted in the DOM, loop through all of the links that were just created
694                 for(i=0; i<ids.length; i++){
695                         var btn = _firebugDoc.getElementById(ids[i]);
696                         if(!btn){ continue; }
697
698                         // store the object in the dom btn for reference later
699                         // avoid parsing these objects unless necessary
700                         btn.obj = obs[i];
701
702                         _firebugWin.console._connects.push(dojo.connect(btn, "onclick", function(){
703
704                                 console.openObjectInspector();
705
706                                 try{
707                                         printObject(this.obj);
708                                 }catch(e){
709                                         this.obj = e;
710                                 }
711                                 consoleObjectInspector.innerHTML = "<pre>" + printObject( this.obj ) + "</pre>";
712                         }));
713                 }
714         }
715
716         function parseFormat(format){
717                 var parts = [];
718
719                 var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;
720                 var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};
721
722                 for(var m = reg.exec(format); m; m = reg.exec(format)){
723                         var type = m[8] ? m[8] : m[5];
724                         var appender = type in appenderMap ? appenderMap[type] : appendObject;
725                         var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
726
727                         parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
728                         parts.push({appender: appender, precision: precision});
729
730                         format = format.substr(m.index+m[0].length);
731                 }
732
733                 parts.push(format);
734
735                 return parts;
736         }
737
738         function escapeHTML(value){
739                 function replaceChars(ch){
740                         switch(ch){
741                                 case "<":
742                                         return "&lt;";
743                                 case ">":
744                                         return "&gt;";
745                                 case "&":
746                                         return "&amp;";
747                                 case "'":
748                                         return "&#39;";
749                                 case '"':
750                                         return "&quot;";
751                         }
752                         return "?";
753                 }
754                 return String(value).replace(/[<>&"']/g, replaceChars);
755         }
756
757         function objectToString(object){
758                 try{
759                         return object+"";
760                 }catch(e){
761                         return null;
762                 }
763         }
764
765         // ***************************************************************************
766         function appendLink(object, html){
767                 // needed for object links - no HTML escaping
768                 html.push( objectToString(object) );
769         }
770
771         function appendText(object, html){
772                 html.push(escapeHTML(objectToString(object)));
773         }
774
775         function appendNull(object, html){
776                 html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
777         }
778
779         function appendString(object, html){
780                 html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
781                         '&quot;</span>');
782         }
783
784         function appendInteger(object, html){
785                 html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
786         }
787
788         function appendFloat(object, html){
789                 html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
790         }
791
792         function appendFunction(object, html){
793                 html.push('<span class="objectBox-function">', getObjectAbbr(object), '</span>');
794         }
795
796         function appendObject(object, html){
797                 try{
798                         if(object === undefined){
799                                 appendNull("undefined", html);
800                         }else if(object === null){
801                                 appendNull("null", html);
802                         }else if(typeof object == "string"){
803                                 appendString(object, html);
804                         }else if(typeof object == "number"){
805                                 appendInteger(object, html);
806                         }else if(typeof object == "function"){
807                                 appendFunction(object, html);
808                         }else if(object.nodeType == 1){
809                                 appendSelector(object, html);
810                         }else if(typeof object == "object"){
811                                 appendObjectFormatted(object, html);
812                         }else{
813                                 appendText(object, html);
814                         }
815                 }catch(e){
816                         /* squelch */
817                 }
818         }
819
820         function appendObjectFormatted(object, html){
821                 var text = objectToString(object);
822                 var reObject = /\[object (.*?)\]/;
823
824                 var m = reObject.exec(text);
825                 html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>');
826         }
827
828         function appendSelector(object, html){
829                 html.push('<span class="objectBox-selector">');
830
831                 html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
832                 if(object.id){
833                         html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
834                 }
835                 if(object.className){
836                         html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
837                 }
838
839                 html.push('</span>');
840         }
841
842         function appendNode(node, html){
843                 if(node.nodeType == 1){
844                         html.push(
845                                 '<div class="objectBox-element">',
846                                         '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
847
848                         for(var i = 0; i < node.attributes.length; ++i){
849                                 var attr = node.attributes[i];
850                                 if(!attr.specified){ continue; }
851
852                                 html.push('&nbsp;<span class="nodeName">', attr.nodeName.toLowerCase(),
853                                         '</span>=&quot;<span class="nodeValue">', escapeHTML(attr.nodeValue),
854                                         '</span>&quot;');
855                         }
856
857                         if(node.firstChild){
858                                 html.push('&gt;</div><div class="nodeChildren">');
859
860                                 for(var child = node.firstChild; child; child = child.nextSibling){
861                                         appendNode(child, html);
862                                 }
863
864                                 html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">',
865                                         node.nodeName.toLowerCase(), '&gt;</span></div>');
866                         }else{
867                                 html.push('/&gt;</div>');
868                         }
869                 }else if (node.nodeType == 3){
870                         html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
871                                 '</div>');
872                 }
873         }
874
875         // ***************************************************************************
876
877         function addEvent(object, name, handler){
878                 if(document.all){
879                         object.attachEvent("on"+name, handler);
880                 }else{
881                         object.addEventListener(name, handler, false);
882                 }
883         }
884
885         function removeEvent(object, name, handler){
886                 if(document.all){
887                         object.detachEvent("on"+name, handler);
888                 }else{
889                         object.removeEventListener(name, handler, false);
890                 }
891         }
892
893         function cancelEvent(event){
894                 if(document.all){
895                         event.cancelBubble = true;
896                 }else{
897                         event.stopPropagation();
898                 }
899         }
900
901         function onError(msg, href, lineNo){
902                 var lastSlash = href.lastIndexOf("/");
903                 var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
904
905                 var html = [
906                         '<span class="errorMessage">', msg, '</span>',
907                         '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
908                 ];
909
910                 logRow(html, "error");
911         }
912
913
914         //After converting to div instead of iframe, now getting two keydowns right away in IE 6.
915         //Make sure there is a little bit of delay.
916         var onKeyDownTime = new Date().getTime();
917
918         function onKeyDown(event){
919                 var timestamp = (new Date()).getTime();
920                 if(timestamp > onKeyDownTime + 200){
921                         event = dojo.fixEvent(event);
922                         var keys = dojo.keys;
923                         var ekc = event.keyCode;
924                         onKeyDownTime = timestamp;
925                         if(ekc == keys.F12){
926                                 toggleConsole();
927                         }else if(
928                                 (ekc == keys.NUMPAD_ENTER || ekc == 76) &&
929                                 event.shiftKey &&
930                                 (event.metaKey || event.ctrlKey)
931                         ){
932                                 focusCommandLine();
933                         }else{
934                                 return;
935                         }
936                         cancelEvent(event);
937                 }
938         }
939
940         function onCommandLineKeyDown(e){
941                 var dk = dojo.keys;
942                 if(e.keyCode == 13 && commandLine.value){
943                         addToHistory(commandLine.value);
944                         evalCommandLine();
945                 }else if(e.keyCode == 27){
946                         commandLine.value = "";
947                 }else if(e.keyCode == dk.UP_ARROW || e.charCode == dk.UP_ARROW){
948                         navigateHistory("older");
949                 }else if(e.keyCode == dk.DOWN_ARROW || e.charCode == dk.DOWN_ARROW){
950                         navigateHistory("newer");
951                 }else if(e.keyCode == dk.HOME || e.charCode == dk.HOME){
952                         historyPosition = 1;
953                         navigateHistory("older");
954                 }else if(e.keyCode == dk.END || e.charCode == dk.END){
955                         historyPosition = 999999;
956                         navigateHistory("newer");
957                 }
958         }
959
960         var historyPosition = -1;
961         var historyCommandLine = null;
962
963         function addToHistory(value){
964                 var history = cookie("firebug_history");
965                 history = (history) ? dojo.fromJson(history) : [];
966                 var pos = dojo.indexOf(history, value);
967                 if (pos != -1){
968                         history.splice(pos, 1);
969                 }
970                 history.push(value);
971                 cookie("firebug_history", dojo.toJson(history), 30);
972                 while(history.length && !cookie("firebug_history")){
973                         history.shift();
974                         cookie("firebug_history", dojo.toJson(history), 30);
975                 }
976                 historyCommandLine = null;
977                 historyPosition = -1;
978         }
979
980         function navigateHistory(direction){
981                 var history = cookie("firebug_history");
982                 history = (history) ? dojo.fromJson(history) : [];
983                 if(!history.length){
984                         return;
985                 }
986
987                 if(historyCommandLine === null){
988                         historyCommandLine = commandLine.value;
989                 }
990
991                 if(historyPosition == -1){
992                         historyPosition = history.length;
993                 }
994
995                 if(direction == "older"){
996                         --historyPosition;
997                         if(historyPosition < 0){
998                                 historyPosition = 0;
999                         }
1000                 }else if(direction == "newer"){
1001                         ++historyPosition;
1002                         if(historyPosition > history.length){
1003                                 historyPosition = history.length;
1004                         }
1005                 }
1006
1007                 if(historyPosition == history.length){
1008                         commandLine.value = historyCommandLine;
1009                         historyCommandLine = null;
1010                 }else{
1011                         commandLine.value = history[historyPosition];
1012                 }
1013         }
1014
1015         function cookie(name, value){
1016                 var c = document.cookie;
1017                 if(arguments.length == 1){
1018                         var matches = c.match(new RegExp("(?:^|; )" + name + "=([^;]*)"));
1019                         return matches ? decodeURIComponent(matches[1]) : undefined; // String or undefined
1020                 }else{
1021                         var d = new Date();
1022                         d.setMonth(d.getMonth()+1);
1023                         document.cookie = name + "=" + encodeURIComponent(value) + ((d.toUtcString) ? "; expires=" + d.toUTCString() : "");
1024                 }
1025         }
1026
1027         function isArray(it){
1028                 return it && it instanceof Array || typeof it == "array";
1029         }
1030
1031         //***************************************************************************************************
1032         // Print Object Helpers
1033         function objectLength(o){
1034                 var cnt = 0;
1035                 for(var nm in o){
1036                         cnt++;
1037                 }
1038                 return cnt;
1039         }
1040
1041         function printObject(o, i, txt, used){
1042                 // Recursively trace object, indenting to represent depth for display in object inspector
1043                 var ind = " \t";
1044                 txt = txt || "";
1045                 i = i || ind;
1046                 used = used || [];
1047                 var opnCls;
1048
1049                 if(o && o.nodeType == 1){
1050                         var html = [];
1051                         appendNode(o, html);
1052                         return html.join("");
1053                 }
1054
1055                 var br=",\n", cnt = 0, length = objectLength(o);
1056
1057                 if(o instanceof Date){
1058                         return i + o.toString() + br;
1059                 }
1060                 looking:
1061                 for(var nm in o){
1062                         cnt++;
1063                         if(cnt==length){br = "\n";}
1064                         if(o[nm] === window || o[nm] === document){
1065                                 // do nothing
1066                         }else if(o[nm] === null){
1067                                 txt += i+nm + " : NULL" + br;
1068                         }else if(o[nm] && o[nm].nodeType){
1069                                 if(o[nm].nodeType == 1){
1070                                         //txt += i+nm + " : < "+o[nm].tagName+" id=\""+ o[nm].id+"\" />" + br;
1071                                 }else if(o[nm].nodeType == 3){
1072                                         txt += i+nm + " : [ TextNode "+o[nm].data + " ]" + br;
1073                                 }
1074
1075                         }else if(typeof o[nm] == "object" && (o[nm] instanceof String || o[nm] instanceof Number || o[nm] instanceof Boolean)){
1076                                 txt += i+nm + " : " + o[nm] + "," + br;
1077
1078                         }else if(o[nm] instanceof Date){
1079                                 txt += i+nm + " : " + o[nm].toString() + br;
1080
1081                         }else if(typeof(o[nm]) == "object" && o[nm]){
1082                                 for(var j = 0, seen; seen = used[j]; j++){
1083                                         if(o[nm] === seen){
1084                                                 txt += i+nm + " : RECURSION" + br;
1085                                                 continue looking;
1086                                         }
1087                                 }
1088                                 used.push(o[nm]);
1089
1090                                 opnCls = (isArray(o[nm]))?["[","]"]:["{","}"];
1091                                 txt += i+nm +" : " + opnCls[0] + "\n";//non-standard break, (no comma)
1092                                 txt += printObject(o[nm], i+ind, "", used);
1093                                 txt += i + opnCls[1] + br;
1094
1095                         }else if(typeof o[nm] == "undefined"){
1096                                 txt += i+nm + " : undefined" + br;
1097                         }else if(nm == "toString" && typeof o[nm] == "function"){
1098                                 var toString = o[nm]();
1099                                 if(typeof toString == "string" && toString.match(/function ?(.*?)\(/)){
1100                                         toString = escapeHTML(getObjectAbbr(o[nm]));
1101                                 }
1102                                 txt += i+nm +" : " + toString + br;
1103                         }else{
1104                                 txt += i+nm +" : "+ escapeHTML(getObjectAbbr(o[nm])) + br;
1105                         }
1106                 }
1107                 return txt;
1108         }
1109
1110         function getObjectAbbr(obj){
1111                 // Gets an abbreviation of an object for display in log
1112                 // X items in object, including id
1113                 // X items in an array
1114                 // TODO: Firebug Sr. actually goes by char count
1115                 var isError = (obj instanceof Error);
1116                 if(obj.nodeType == 1){
1117                         return escapeHTML('< '+obj.tagName.toLowerCase()+' id=\"'+ obj.id+ '\" />');
1118                 }
1119                 if(obj.nodeType == 3){
1120                         return escapeHTML('[TextNode: "'+obj.nodeValue+'"]');
1121                 }
1122                 var nm = (obj && (obj.id || obj.name || obj.ObjectID || obj.widgetId));
1123                 if(!isError && nm){ return "{"+nm+"}";  }
1124
1125                 var obCnt = 2;
1126                 var arCnt = 4;
1127                 var cnt = 0;
1128
1129                 if(isError){
1130                         nm = "[ Error: "+(obj.message || obj.description || obj)+" ]";
1131                 }else if(isArray(obj)){
1132                         nm = "[" + obj.slice(0,arCnt).join(",");
1133                         if(obj.length > arCnt){
1134                                 nm += " ... ("+obj.length+" items)";
1135                         }
1136                         nm += "]";
1137                 }else if(typeof obj == "function"){
1138                         nm = obj + "";
1139                         var reg = /function\s*([^\(]*)(\([^\)]*\))[^\{]*\{/;
1140                         var m = reg.exec(nm);
1141                         if(m){
1142                                 if(!m[1]){
1143                                         m[1] = "function";
1144                                 }
1145                                 nm = m[1] + m[2];
1146                         }else{
1147                                 nm = "function()";
1148                         }
1149                 }else if(typeof obj != "object" || typeof obj == "string"){
1150                         nm = obj + "";
1151                 }else{
1152                         nm = "{";
1153                         for(var i in obj){
1154                                 cnt++;
1155                                 if(cnt > obCnt){ break; }
1156                                 nm += i+":"+escapeHTML(obj[i])+"  ";
1157                         }
1158                         nm+="}";
1159                 }
1160
1161                 return nm;
1162         }
1163
1164         //*************************************************************************************
1165
1166         //window.onerror = onError;
1167
1168         addEvent(document, dojo.isIE || dojo.isSafari ? "keydown" : "keypress", onKeyDown);
1169
1170         if(     (document.documentElement.getAttribute("debug") == "true")||
1171                 (dojo.config.isDebug)
1172         ){
1173                 toggleConsole(true);
1174         }
1175
1176         dojo.addOnWindowUnload(function(){
1177                 // Erase the globals and event handlers I created, to prevent spurious leak warnings
1178                 removeEvent(document, dojo.isIE || dojo.isSafari ? "keydown" : "keypress", onKeyDown);
1179                 window.onFirebugResize = null;
1180                 window.console = null;
1181         });
1182
1183 });