1 define("dojo/_firebug/firebug", ["../_base/kernel", "require", "../_base/html", "../_base/sniff", "../_base/array", "../_base/lang", "../_base/event", "../_base/unload"], function(dojo
, require
) {
3 // dojo/_firebug/firebug
7 // summary: Firebug Lite, the baby brother to Joe Hewitt's Firebug for Mozilla Firefox
9 // Opens a console for logging, debugging, and error messages.
10 // Contains partial functionality to Firebug. See function list below.
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
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
22 // Supports inline objects in object inspector window (only simple trace of dom nodes, however)
23 // | console.log("my object", {foo:"bar"})
25 // Option for console to open in popup window
26 // | var djConfig = {isDebug: true, popup:true };
28 // Option for console height (ignored for popup)
29 // | var djConfig = {isDebug: true, debugHeight:100 }
32 var isNewIE
= (/Trident/.test(window
.navigator
.userAgent
));
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
++){
39 if(!console
[m
] ||console
[m
]._fake
){
40 // IE9 doesn't have console.debug method, a fake one is added later
44 console
[n
] = console
[m
];
45 console
[m
] = (function(){
48 console
[type
](Array
.prototype.join
.call(arguments
, " "));
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
){}
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
70 // don't build firebug in iframes
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
;
79 }catch(e
){/*squelch*/}
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.
85 // most of the objects in this script are run anonomously
86 var _firebugDoc
= document
;
87 var _firebugWin
= window
;
88 var __consoleAnchorId__
= 0;
90 var consoleFrame
= null;
91 var consoleBody
= null;
92 var consoleObjectInspector
= null;
93 var fireBugTabs
= null;
94 var commandLine
= null;
95 var consoleToolbar
= null;
97 var frameVisible
= false;
98 var messageQueue
= [];
103 var consoleDomInspector
= null;
104 var _inspectionMoveConnection
;
105 var _inspectionClickConnection
;
106 var _inspectionEnabled
= false;
107 var _inspectionTimer
= null;
108 var _inspectTempNode
= document
.createElement("div");
111 var _inspectCurrentNode
;
112 var _restoreBorderStyle
;
114 // ***************************************************************************
120 // Sends arguments to console.
121 logFormatted(arguments
, "");
126 // Sends arguments to console. Missing finctionality to show script line of trace.
127 logFormatted(arguments
, "debug");
132 // Sends arguments to console, highlighted with (I) icon.
133 logFormatted(arguments
, "info");
138 // Sends warning arguments to console, highlighted with (!) icon and blue style.
139 logFormatted(arguments
, "warning");
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");
149 assert: function(truth
, message
){
151 // Tests for true. Throws exception if false.
154 for(var i
= 1; i
< arguments
.length
; ++i
){
155 args
.push(arguments
[i
]);
158 logFormatted(args
.length
? args
: ["Assertion Failure"], "error");
159 throw message
? message
: "Assertion Failure";
164 var str
= printObject( obj
);
165 str
= str
.replace(/\n/g, "<br />");
166 str
= str
.replace(/\t/g, " ");
167 logRow([str
], "dir");
170 dirxml: function(node
){
174 appendNode(node
, html
);
175 logRow(html
, "dirxml");
180 // collects log messages into a group, starting with this call and ending with
181 // groupEnd(). Missing collapse functionality
182 logRow(arguments
, "group", pushGroup
);
185 groupEnd: function(){
187 // Closes group. See above
188 logRow(arguments
, "", popGroup
);
191 time: function(name
){
193 // Starts timers assigned to name given in argument. Timer stops and displays on timeEnd(title);
195 // | console.time("load");
196 // | console.time("myFunction");
197 // | console.timeEnd("load");
198 // | console.timeEnd("myFunction");
199 timeMap
[name
] = new Date().getTime();
202 timeEnd: function(name
){
206 var delta
= (new Date()).getTime() - timeMap
[name
];
207 logFormatted([name
+ ":", delta
+"ms"]);
208 delete timeMap
[name
];
212 count: function(name
){
215 if(!countMap
[name
]) countMap
[name
] = 0;
217 logFormatted([name
+": "+countMap
[name
]]);
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();
227 for (var a
= 0; a
< f
.arguments
.length
; a
++) {
228 args
.push(f
.arguments
[a
]);
230 if(f
.arguments
.length
){
231 console
.dir({"function":func
, "arguments":args
});
233 console
.dir({"function":func
});
243 this.warn(["profile() not supported."]);
246 profileEnd: function(){ },
250 // Clears message console. Do not call this directly
252 while(consoleBody
.childNodes
.length
){
253 dojo
.destroy(consoleBody
.firstChild
);
256 dojo
.forEach(this._connects
,dojo
.disconnect
);
261 // Opens message console. Do not call this directly
267 // Closes message console. Do not call this directly
272 _restoreBorder: function(){
273 if(_inspectCurrentNode
){
274 _inspectCurrentNode
.style
.border
= _restoreBorderStyle
;
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);
290 var node
= evt
.target
;
291 if(node
&& (_inspectCurrentNode
!== node
)){
294 console
._restoreBorder();
296 appendNode(node
, html
);
297 consoleDomInspector
.innerHTML
= html
.join("");
299 _inspectCurrentNode
= node
;
300 _restoreBorderStyle
= _inspectCurrentNode
.style
.border
;
301 _inspectCurrentNode
.style
.border
= "#0000FF 1px solid";
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();
313 _closeDomInspector: function(){
314 document
.body
.style
.cursor
= "";
315 dojo
.disconnect(_inspectionMoveConnection
);
316 dojo
.disconnect(_inspectionClickConnection
);
317 _inspectionEnabled
= false;
318 console
._restoreBorder();
320 openConsole:function(){
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();
328 openObjectInspector:function(){
329 consoleBody
.style
.display
= "none";
330 consoleDomInspector
.style
.display
= "none";
331 consoleObjectInspector
.style
.display
= "block";
332 console
._closeDomInspector();
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
++){
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();
349 // ***************************************************************************
351 function toggleConsole(forceOpen
){
352 frameVisible
= forceOpen
|| !frameVisible
;
354 consoleFrame
.style
.display
= frameVisible
? "block" : "none";
358 function focusCommandLine(){
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");
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.";
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>' +
380 newDoc
.write(HTMLstring
);
385 function createResizeHandler(wn
){
387 // Creates handle for onresize window. Called from script in popup's body tag (so that it will work with IE).
391 d
.setTime(d
.getTime()+(60*24*60*60*1000)); // 60 days
394 var dc
= wn
.document
,
398 getViewport = function(){
399 return{w
:wn
.innerWidth
, h
:wn
.innerHeight
};
401 }else if (dc
.documentElement
&& dc
.documentElement
.clientWidth
){
402 getViewport = function(){
403 return{w
:dc
.documentElement
.clientWidth
, h
:dc
.documentElement
.clientHeight
};
406 getViewport = function(){
407 return{w
:dc
.body
.clientWidth
, h
:dc
.body
.clientHeight
};
412 window
.onFirebugResize = function(){
414 //resize the height of the console log body
415 layout(getViewport().h
);
417 clearInterval(wn
._firebugWin_resize
);
418 wn
._firebugWin_resize
= setTimeout(function(){
419 var x
= wn
.screenLeft
,
421 w
= wn
.outerWidth
|| wn
.document
.body
.offsetWidth
,
422 h
= wn
.outerHeight
|| wn
.document
.body
.offsetHeight
;
424 document
.cookie
= "_firebugPosition=" + [x
,y
,w
,h
].join(",") + "; expires="+d
+"; path=/";
426 }, 5000); //can't capture window.onMove - long timeout gives better chance of capturing a resize, then the move
432 /*****************************************************************************/
435 function createFrame(){
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];
445 _firebugWin
= openWin(p
[0],p
[1],p
[2],p
[3]); // global
446 _firebugDoc
= _firebugWin
.document
; // global
448 dojo
.config
.debugContainerId
= 'fb';
451 _firebugWin
.console
= window
.console
;
452 _firebugWin
.dojo
= window
.dojo
;
454 _firebugDoc
= document
;
455 containerHeight
= (dojo
.config
.debugHeight
|| 300) + "px";
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");
464 styleParent
= styleParent
[0];
467 styleParent
= _firebugDoc
.getElementsByTagName("html")[0];
470 window
.setTimeout(function(){ styleParent
.appendChild(styleElement
); }, 0);
472 styleParent
.appendChild(styleElement
);
475 if(dojo
.config
.debugContainerId
){
476 consoleFrame
= _firebugDoc
.getElementById(dojo
.config
.debugContainerId
);
479 consoleFrame
= _firebugDoc
.createElement("div");
480 _firebugDoc
.body
.appendChild(consoleFrame
);
482 consoleFrame
.className
+= " firebug";
483 consoleFrame
.style
.height
= containerHeight
;
484 consoleFrame
.style
.display
= (frameVisible
? "block" : "none");
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>';
489 consoleFrame
.innerHTML
=
490 '<div id="firebugToolbar">'
491 + ' <ul id="fireBugTabs" class="tabs">'
493 + buildLink("Clear", "Remove All Console Logs", "clear", "")
494 + buildLink("ReCSS", "Refresh CSS without reloading page", "recss", "")
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"))
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>';
509 consoleToolbar
= _firebugDoc
.getElementById("firebugToolbar");
511 commandLine
= _firebugDoc
.getElementById("firebugCommandLine");
512 addEvent(commandLine
, "keydown", onCommandLineKeyDown
);
514 addEvent(_firebugDoc
, dojo
.isIE
|| dojo
.isSafari
? "keydown" : "keypress", onKeyDown
);
516 consoleBody
= _firebugDoc
.getElementById("firebugLog");
517 consoleObjectInspector
= _firebugDoc
.getElementById("objectLog");
518 consoleDomInspector
= _firebugDoc
.getElementById("domInspect");
519 fireBugTabs
= _firebugDoc
.getElementById("fireBugTabs");
524 dojo
.addOnLoad(createFrame
);
526 function clearFrame(){
529 if(_firebugWin
.console
){
530 _firebugWin
.console
.clear();
535 consoleObjectInspector
= null;
536 consoleDomInspector
= null;
544 function evalCommandLine(){
545 var text
= commandLine
.value
;
546 commandLine
.value
= "";
548 logRow(["> ", text
], "command");
554 console
.debug(e
); // put exception on the console
561 var tHeight
= 25; //consoleToolbar.offsetHeight; // tab style not ready on load - throws off layout
563 h
- (tHeight
+ commandLine
.offsetHeight
+25 + (h
*.01)) + "px" :
564 (consoleFrame
.offsetHeight
- tHeight
- commandLine
.offsetHeight
) + "px";
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;
574 dojo
.addOnWindowUnload(clearFrame
);
577 function logRow(message
, className
, handler
){
579 writeMessage(message
, className
, handler
);
581 messageQueue
.push([message
, className
, handler
]);
586 var queue
= messageQueue
;
589 for(var i
= 0; i
< queue
.length
; ++i
){
590 writeMessage(queue
[i
][0], queue
[i
][1], queue
[i
][2]);
594 function writeMessage(message
, className
, handler
){
595 var isScrolledToBottom
=
596 consoleBody
.scrollTop
+ consoleBody
.offsetHeight
>= consoleBody
.scrollHeight
;
598 handler
= handler
||writeRow
;
600 handler(message
, className
);
602 if(isScrolledToBottom
){
603 consoleBody
.scrollTop
= consoleBody
.scrollHeight
- consoleBody
.offsetHeight
;
607 function appendRow(row
){
608 var container
= groupStack
.length
? groupStack
[groupStack
.length
-1] : consoleBody
;
609 container
.appendChild(row
);
612 function writeRow(message
, className
){
613 var row
= consoleBody
.ownerDocument
.createElement("div");
614 row
.className
= "logRow" + (className
? " logRow-"+className
: "");
615 row
.innerHTML
= message
.join("");
619 function pushGroup(message
, className
){
620 logFormatted(message
, className
);
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
);
635 // ***************************************************************************
637 function logFormatted(objects
, className
){
640 var format
= objects
[0];
643 if(typeof(format
) != "string"){
648 var parts
= parseFormat(format
);
650 for(var i
= 0; i
< parts
.length
; ++i
){
652 if(part
&& typeof part
== "object"){
653 part
.appender(objects
[++objIndex
], html
);
655 appendText(part
, html
);
662 for(i
= objIndex
+1; i
< objects
.length
; ++i
){
663 appendText(" ", html
);
665 var object
= objects
[i
];
666 if(object
=== undefined || object
=== null ){
667 appendNull(object
, html
);
669 }else if(typeof(object
) == "string"){
670 appendText(object
, html
);
672 }else if(object
instanceof Date
){
673 appendText(object
.toString(), html
);
675 }else if(object
.nodeType
== 9){
676 appendText("[ XmlDoc ]", html
);
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__
++;
683 // need to save the object, so the arrays line up
685 var str
= '<a id="'+id
+'" href="javascript:void(0);">'+getObjectAbbr(object
)+'</a>';
687 appendLink( str
, html
);
691 logRow(html
, className
);
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; }
698 // store the object in the dom btn for reference later
699 // avoid parsing these objects unless necessary
702 _firebugWin
.console
._connects
.push(dojo
.connect(btn
, "onclick", function(){
704 console
.openObjectInspector();
707 printObject(this.obj
);
711 consoleObjectInspector
.innerHTML
= "<pre>" + printObject( this.obj
) + "</pre>";
716 function parseFormat(format
){
719 var reg
= /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;
720 var appenderMap
= {s
: appendText
, d
: appendInteger
, i
: appendInteger
, f
: appendFloat
};
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);
727 parts
.push(format
.substr(0, m
[0][0] == "%" ? m
.index
: m
.index
+1));
728 parts
.push({appender
: appender
, precision
: precision
});
730 format
= format
.substr(m
.index
+m
[0].length
);
738 function escapeHTML(value
){
739 function replaceChars(ch
){
754 return String(value
).replace(/[<>&"']/g, replaceChars
);
757 function objectToString(object
){
765 // ***************************************************************************
766 function appendLink(object
, html
){
767 // needed for object links - no HTML escaping
768 html
.push( objectToString(object
) );
771 function appendText(object
, html
){
772 html
.push(escapeHTML(objectToString(object
)));
775 function appendNull(object
, html
){
776 html
.push('<span class="objectBox-null">', escapeHTML(objectToString(object
)), '</span>');
779 function appendString(object
, html
){
780 html
.push('<span class="objectBox-string">"', escapeHTML(objectToString(object
)),
784 function appendInteger(object
, html
){
785 html
.push('<span class="objectBox-number">', escapeHTML(objectToString(object
)), '</span>');
788 function appendFloat(object
, html
){
789 html
.push('<span class="objectBox-number">', escapeHTML(objectToString(object
)), '</span>');
792 function appendFunction(object
, html
){
793 html
.push('<span class="objectBox-function">', getObjectAbbr(object
), '</span>');
796 function appendObject(object
, html
){
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
);
813 appendText(object
, html
);
820 function appendObjectFormatted(object
, html
){
821 var text
= objectToString(object
);
822 var reObject
= /\[object (.*?)\]/;
824 var m
= reObject
.exec(text
);
825 html
.push('<span class="objectBox-object">', m
? m
[1] : text
, '</span>');
828 function appendSelector(object
, html
){
829 html
.push('<span class="objectBox-selector">');
831 html
.push('<span class="selectorTag">', escapeHTML(object
.nodeName
.toLowerCase()), '</span>');
833 html
.push('<span class="selectorId">#', escapeHTML(object
.id
), '</span>');
835 if(object
.className
){
836 html
.push('<span class="selectorClass">.', escapeHTML(object
.className
), '</span>');
839 html
.push('</span>');
842 function appendNode(node
, html
){
843 if(node
.nodeType
== 1){
845 '<div class="objectBox-element">',
846 '<<span class="nodeTag">', node
.nodeName
.toLowerCase(), '</span>');
848 for(var i
= 0; i
< node
.attributes
.length
; ++i
){
849 var attr
= node
.attributes
[i
];
850 if(!attr
.specified
){ continue; }
852 html
.push(' <span class="nodeName">', attr
.nodeName
.toLowerCase(),
853 '</span>="<span class="nodeValue">', escapeHTML(attr
.nodeValue
),
858 html
.push('></div><div class="nodeChildren">');
860 for(var child
= node
.firstChild
; child
; child
= child
.nextSibling
){
861 appendNode(child
, html
);
864 html
.push('</div><div class="objectBox-element"></<span class="nodeTag">',
865 node
.nodeName
.toLowerCase(), '></span></div>');
867 html
.push('/></div>');
869 }else if (node
.nodeType
== 3){
870 html
.push('<div class="nodeText">', escapeHTML(node
.nodeValue
),
875 // ***************************************************************************
877 function addEvent(object
, name
, handler
){
879 object
.attachEvent("on"+name
, handler
);
881 object
.addEventListener(name
, handler
, false);
885 function removeEvent(object
, name
, handler
){
887 object
.detachEvent("on"+name
, handler
);
889 object
.removeEventListener(name
, handler
, false);
893 function cancelEvent(event
){
895 event
.cancelBubble
= true;
897 event
.stopPropagation();
901 function onError(msg
, href
, lineNo
){
902 var lastSlash
= href
.lastIndexOf("/");
903 var fileName
= lastSlash
== -1 ? href
: href
.substr(lastSlash
+1);
906 '<span class="errorMessage">', msg
, '</span>',
907 '<div class="objectBox-sourceLink">', fileName
, ' (line ', lineNo
, ')</div>'
910 logRow(html
, "error");
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();
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
;
928 (ekc
== keys
.NUMPAD_ENTER
|| ekc
== 76) &&
930 (event
.metaKey
|| event
.ctrlKey
)
940 function onCommandLineKeyDown(e
){
942 if(e
.keyCode
== 13 && commandLine
.value
){
943 addToHistory(commandLine
.value
);
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
){
953 navigateHistory("older");
954 }else if(e
.keyCode
== dk
.END
|| e
.charCode
== dk
.END
){
955 historyPosition
= 999999;
956 navigateHistory("newer");
960 var historyPosition
= -1;
961 var historyCommandLine
= null;
963 function addToHistory(value
){
964 var history
= cookie("firebug_history");
965 history
= (history
) ? dojo
.fromJson(history
) : [];
966 var pos
= dojo
.indexOf(history
, value
);
968 history
.splice(pos
, 1);
971 cookie("firebug_history", dojo
.toJson(history
), 30);
972 while(history
.length
&& !cookie("firebug_history")){
974 cookie("firebug_history", dojo
.toJson(history
), 30);
976 historyCommandLine
= null;
977 historyPosition
= -1;
980 function navigateHistory(direction
){
981 var history
= cookie("firebug_history");
982 history
= (history
) ? dojo
.fromJson(history
) : [];
987 if(historyCommandLine
=== null){
988 historyCommandLine
= commandLine
.value
;
991 if(historyPosition
== -1){
992 historyPosition
= history
.length
;
995 if(direction
== "older"){
997 if(historyPosition
< 0){
1000 }else if(direction
== "newer"){
1002 if(historyPosition
> history
.length
){
1003 historyPosition
= history
.length
;
1007 if(historyPosition
== history
.length
){
1008 commandLine
.value
= historyCommandLine
;
1009 historyCommandLine
= null;
1011 commandLine
.value
= history
[historyPosition
];
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
1022 d
.setMonth(d
.getMonth()+1);
1023 document
.cookie
= name
+ "=" + encodeURIComponent(value
) + ((d
.toUtcString
) ? "; expires=" + d
.toUTCString() : "");
1027 function isArray(it
){
1028 return it
&& it
instanceof Array
|| typeof it
== "array";
1031 //***************************************************************************************************
1032 // Print Object Helpers
1033 function objectLength(o
){
1041 function printObject(o
, i
, txt
, used
){
1042 // Recursively trace object, indenting to represent depth for display in object inspector
1049 if(o
&& o
.nodeType
== 1){
1051 appendNode(o
, html
);
1052 return html
.join("");
1055 var br
=",\n", cnt
= 0, length
= objectLength(o
);
1057 if(o
instanceof Date
){
1058 return i
+ o
.toString() + br
;
1063 if(cnt
==length
){br
= "\n";}
1064 if(o
[nm
] === window
|| o
[nm
] === document
){
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
;
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
;
1078 }else if(o
[nm
] instanceof Date
){
1079 txt
+= i
+nm
+ " : " + o
[nm
].toString() + br
;
1081 }else if(typeof(o
[nm
]) == "object" && o
[nm
]){
1082 for(var j
= 0, seen
; seen
= used
[j
]; j
++){
1084 txt
+= i
+nm
+ " : RECURSION" + br
;
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
;
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
]));
1102 txt
+= i
+nm
+" : " + toString
+ br
;
1104 txt
+= i
+nm
+" : "+ escapeHTML(getObjectAbbr(o
[nm
])) + br
;
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
+ '\" />');
1119 if(obj
.nodeType
== 3){
1120 return escapeHTML('[TextNode: "'+obj
.nodeValue
+'"]');
1122 var nm
= (obj
&& (obj
.id
|| obj
.name
|| obj
.ObjectID
|| obj
.widgetId
));
1123 if(!isError
&& nm
){ return "{"+nm
+"}"; }
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)";
1137 }else if(typeof obj
== "function"){
1139 var reg
= /function\s*([^\(]*)(\([^\)]*\))[^\{]*\{/;
1140 var m
= reg
.exec(nm
);
1149 }else if(typeof obj
!= "object" || typeof obj
== "string"){
1155 if(cnt
> obCnt
){ break; }
1156 nm
+= i
+":"+escapeHTML(obj
[i
])+" ";
1164 //*************************************************************************************
1166 //window.onerror = onError;
1168 addEvent(document
, dojo
.isIE
|| dojo
.isSafari
? "keydown" : "keypress", onKeyDown
);
1170 if( (document
.documentElement
.getAttribute("debug") == "true")||
1171 (dojo
.config
.isDebug
)
1173 toggleConsole(true);
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;