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