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