source: Dev/branches/rest-dojo-ui/client/dojo/_firebug/firebug.js @ 263

Last change on this file since 263 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 32.6 KB
Line 
1define(["../_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});
Note: See TracBrowser for help on using the repository browser.