firebug.js 33 KB

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