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