firebug.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. if (!window.console || !console.firebug) { (function()
  2. {
  3. window.console =
  4. {
  5. log: function()
  6. {
  7. logFormatted(arguments, "");
  8. },
  9. debug: function()
  10. {
  11. logFormatted(arguments, "debug");
  12. },
  13. info: function()
  14. {
  15. logFormatted(arguments, "info");
  16. },
  17. warn: function()
  18. {
  19. logFormatted(arguments, "warning");
  20. },
  21. error: function()
  22. {
  23. logFormatted(arguments, "error");
  24. },
  25. assert: function(truth, message)
  26. {
  27. if (!truth)
  28. {
  29. var args = [];
  30. for (var i = 1; i < arguments.length; ++i)
  31. args.push(arguments[i]);
  32. logFormatted(args.length ? args : ["Assertion Failure"], "error");
  33. throw message ? message : "Assertion Failure";
  34. }
  35. },
  36. dir: function(object)
  37. {
  38. var html = [];
  39. var pairs = [];
  40. for (var name in object)
  41. {
  42. try
  43. {
  44. pairs.push([name, object[name]]);
  45. }
  46. catch (exc)
  47. {
  48. }
  49. }
  50. pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1; });
  51. html.push('<table>');
  52. for (var i = 0; i < pairs.length; ++i)
  53. {
  54. var name = pairs[i][0], value = pairs[i][1];
  55. html.push('<tr>',
  56. '<td class="propertyNameCell"><span class="propertyName">',
  57. escapeHTML(name), '</span></td>', '<td><span class="propertyValue">');
  58. appendObject(value, html);
  59. html.push('</span></td></tr>');
  60. }
  61. html.push('</table>');
  62. logRow(html, "dir");
  63. },
  64. dirxml: function(node)
  65. {
  66. var html = [];
  67. appendNode(node, html);
  68. logRow(html, "dirxml");
  69. },
  70. group: function()
  71. {
  72. logRow(arguments, "group", pushGroup);
  73. },
  74. groupEnd: function()
  75. {
  76. logRow(arguments, "", popGroup);
  77. },
  78. time: function(name)
  79. {
  80. timeMap[name] = (new Date()).getTime();
  81. },
  82. timeEnd: function(name)
  83. {
  84. if (name in timeMap)
  85. {
  86. var delta = (new Date()).getTime() - timeMap[name];
  87. logFormatted([name+ ":", delta+"ms"]);
  88. delete timeMap[name];
  89. }
  90. },
  91. count: function()
  92. {
  93. this.warn(["count() not supported."]);
  94. },
  95. trace: function()
  96. {
  97. this.warn(["trace() not supported."]);
  98. },
  99. profile: function()
  100. {
  101. this.warn(["profile() not supported."]);
  102. },
  103. profileEnd: function()
  104. {
  105. },
  106. clear: function()
  107. {
  108. consoleBody.innerHTML = "";
  109. },
  110. open: function()
  111. {
  112. toggleConsole(true);
  113. },
  114. close: function()
  115. {
  116. if (frameVisible)
  117. toggleConsole();
  118. }
  119. };
  120. // ********************************************************************************************
  121. var consoleFrame = null;
  122. var consoleBody = null;
  123. var commandLine = null;
  124. var frameVisible = false;
  125. var messageQueue = [];
  126. var groupStack = [];
  127. var timeMap = {};
  128. var clPrefix = ">>> ";
  129. var isFirefox = navigator.userAgent.indexOf("Firefox") != -1;
  130. var isIE = navigator.userAgent.indexOf("MSIE") != -1;
  131. var isOpera = navigator.userAgent.indexOf("Opera") != -1;
  132. var isSafari = navigator.userAgent.indexOf("AppleWebKit") != -1;
  133. // ********************************************************************************************
  134. function toggleConsole(forceOpen)
  135. {
  136. frameVisible = forceOpen || !frameVisible;
  137. if (consoleFrame)
  138. consoleFrame.style.visibility = frameVisible ? "visible" : "hidden";
  139. else
  140. waitForBody();
  141. }
  142. function focusCommandLine()
  143. {
  144. toggleConsole(true);
  145. if (commandLine)
  146. commandLine.focus();
  147. }
  148. function waitForBody()
  149. {
  150. if (document.body)
  151. createFrame();
  152. else
  153. setTimeout(waitForBody, 200);
  154. }
  155. function createFrame()
  156. {
  157. if (consoleFrame)
  158. return;
  159. window.onFirebugReady = function(doc)
  160. {
  161. window.onFirebugReady = null;
  162. var toolbar = doc.getElementById("toolbar");
  163. toolbar.onmousedown = onSplitterMouseDown;
  164. commandLine = doc.getElementById("commandLine");
  165. addEvent(commandLine, "keydown", onCommandLineKeyDown);
  166. addEvent(doc, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
  167. consoleBody = doc.getElementById("log");
  168. layout();
  169. flush();
  170. }
  171. var baseURL = getFirebugURL();
  172. consoleFrame = document.createElement("iframe");
  173. consoleFrame.setAttribute("src", baseURL+"/firebug.html");
  174. consoleFrame.setAttribute("frameBorder", "0");
  175. consoleFrame.style.visibility = (frameVisible ? "visible" : "hidden");
  176. consoleFrame.style.zIndex = "2147483583";
  177. consoleFrame.style.position = document.all ? "absolute" : "fixed";
  178. consoleFrame.style.width = "100%";
  179. consoleFrame.style.left = "0";
  180. consoleFrame.style.bottom = "0";
  181. consoleFrame.style.height = "200px";
  182. document.body.appendChild(consoleFrame);
  183. }
  184. function getFirebugURL()
  185. {
  186. var scripts = document.getElementsByTagName("script");
  187. for (var i = 0; i < scripts.length; ++i)
  188. {
  189. if (scripts[i].src.indexOf("firebug.js") != -1)
  190. {
  191. var lastSlash = scripts[i].src.lastIndexOf("/");
  192. return scripts[i].src.substr(0, lastSlash);
  193. }
  194. }
  195. }
  196. function evalCommandLine()
  197. {
  198. var text = commandLine.value;
  199. commandLine.value = "";
  200. logRow([clPrefix, text], "command");
  201. var value;
  202. try
  203. {
  204. value = eval(text);
  205. }
  206. catch (exc)
  207. {
  208. }
  209. console.log(value);
  210. }
  211. function layout()
  212. {
  213. var toolbar = consoleBody.ownerDocument.getElementById("toolbar");
  214. var height = consoleFrame.offsetHeight - (toolbar.offsetHeight + commandLine.offsetHeight);
  215. height = Math.max(height, 0);
  216. consoleBody.style.top = toolbar.offsetHeight + "px";
  217. consoleBody.style.height = height + "px";
  218. commandLine.style.top = (consoleFrame.offsetHeight - commandLine.offsetHeight) + "px";
  219. }
  220. function logRow(message, className, handler)
  221. {
  222. if (consoleBody)
  223. writeMessage(message, className, handler);
  224. else
  225. {
  226. messageQueue.push([message, className, handler]);
  227. waitForBody();
  228. }
  229. }
  230. function flush()
  231. {
  232. var queue = messageQueue;
  233. messageQueue = [];
  234. for (var i = 0; i < queue.length; ++i)
  235. writeMessage(queue[i][0], queue[i][1], queue[i][2]);
  236. }
  237. function writeMessage(message, className, handler)
  238. {
  239. var isScrolledToBottom =
  240. consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight;
  241. if (!handler)
  242. handler = writeRow;
  243. handler(message, className);
  244. if (isScrolledToBottom)
  245. consoleBody.scrollTop = consoleBody.scrollHeight - consoleBody.offsetHeight;
  246. }
  247. function appendRow(row)
  248. {
  249. var container = groupStack.length ? groupStack[groupStack.length-1] : consoleBody;
  250. container.appendChild(row);
  251. }
  252. function writeRow(message, className)
  253. {
  254. var row = consoleBody.ownerDocument.createElement("div");
  255. row.className = "logRow" + (className ? " logRow-"+className : "");
  256. row.innerHTML = message.join("");
  257. appendRow(row);
  258. }
  259. function pushGroup(message, className)
  260. {
  261. logFormatted(message, className);
  262. var groupRow = consoleBody.ownerDocument.createElement("div");
  263. groupRow.className = "logGroup";
  264. var groupRowBox = consoleBody.ownerDocument.createElement("div");
  265. groupRowBox.className = "logGroupBox";
  266. groupRow.appendChild(groupRowBox);
  267. appendRow(groupRowBox);
  268. groupStack.push(groupRowBox);
  269. }
  270. function popGroup()
  271. {
  272. groupStack.pop();
  273. }
  274. // ********************************************************************************************
  275. function logFormatted(objects, className)
  276. {
  277. var html = [];
  278. var format = objects[0];
  279. var objIndex = 0;
  280. if (typeof(format) != "string")
  281. {
  282. format = "";
  283. objIndex = -1;
  284. }
  285. var parts = parseFormat(format);
  286. for (var i = 0; i < parts.length; ++i)
  287. {
  288. var part = parts[i];
  289. if (part && typeof(part) == "object")
  290. {
  291. var object = objects[++objIndex];
  292. part.appender(object, html);
  293. }
  294. else
  295. appendText(part, html);
  296. }
  297. for (var i = objIndex+1; i < objects.length; ++i)
  298. {
  299. appendText(" ", html);
  300. var object = objects[i];
  301. if (typeof(object) == "string")
  302. appendText(object, html);
  303. else
  304. appendObject(object, html);
  305. }
  306. logRow(html, className);
  307. }
  308. function parseFormat(format)
  309. {
  310. var parts = [];
  311. var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;
  312. var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};
  313. for (var m = reg.exec(format); m; m = reg.exec(format))
  314. {
  315. var type = m[8] ? m[8] : m[5];
  316. var appender = type in appenderMap ? appenderMap[type] : appendObject;
  317. var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
  318. parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
  319. parts.push({appender: appender, precision: precision});
  320. format = format.substr(m.index+m[0].length);
  321. }
  322. parts.push(format);
  323. return parts;
  324. }
  325. function escapeHTML(value)
  326. {
  327. function replaceChars(ch)
  328. {
  329. switch (ch)
  330. {
  331. case "<":
  332. return "&lt;";
  333. case ">":
  334. return "&gt;";
  335. case "&":
  336. return "&amp;";
  337. case "'":
  338. return "&#39;";
  339. case '"':
  340. return "&quot;";
  341. }
  342. return "?";
  343. };
  344. return String(value).replace(/[<>&"']/g, replaceChars);
  345. }
  346. function objectToString(object)
  347. {
  348. try
  349. {
  350. return object+"";
  351. }
  352. catch (exc)
  353. {
  354. return null;
  355. }
  356. }
  357. // ********************************************************************************************
  358. function appendText(object, html)
  359. {
  360. html.push(escapeHTML(objectToString(object)));
  361. }
  362. function appendNull(object, html)
  363. {
  364. html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
  365. }
  366. function appendString(object, html)
  367. {
  368. html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
  369. '&quot;</span>');
  370. }
  371. function appendInteger(object, html)
  372. {
  373. html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
  374. }
  375. function appendFloat(object, html)
  376. {
  377. html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
  378. }
  379. function appendFunction(object, html)
  380. {
  381. var reName = /function ?(.*?)\(/;
  382. var m = reName.exec(objectToString(object));
  383. var name = m ? m[1] : "function";
  384. html.push('<span class="objectBox-function">', escapeHTML(name), '()</span>');
  385. }
  386. function appendObject(object, html)
  387. {
  388. try
  389. {
  390. if (object == undefined)
  391. appendNull("undefined", html);
  392. else if (object == null)
  393. appendNull("null", html);
  394. else if (typeof object == "string")
  395. appendString(object, html);
  396. else if (typeof object == "number")
  397. appendInteger(object, html);
  398. else if (typeof object == "function")
  399. appendFunction(object, html);
  400. else if (object.nodeType == 1)
  401. appendSelector(object, html);
  402. else if (typeof object == "object")
  403. appendObjectFormatted(object, html);
  404. else
  405. appendText(object, html);
  406. }
  407. catch (exc)
  408. {
  409. }
  410. }
  411. function appendObjectFormatted(object, html)
  412. {
  413. var text = objectToString(object);
  414. var reObject = /\[object (.*?)\]/;
  415. var m = reObject.exec(text);
  416. html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
  417. }
  418. function appendSelector(object, html)
  419. {
  420. html.push('<span class="objectBox-selector">');
  421. html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
  422. if (object.id)
  423. html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
  424. if (object.className)
  425. html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
  426. html.push('</span>');
  427. }
  428. function appendNode(node, html)
  429. {
  430. if (node.nodeType == 1)
  431. {
  432. html.push(
  433. '<div class="objectBox-element">',
  434. '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
  435. for (var i = 0; i < node.attributes.length; ++i)
  436. {
  437. var attr = node.attributes[i];
  438. if (!attr.specified)
  439. continue;
  440. html.push('&nbsp;<span class="nodeName">', attr.nodeName.toLowerCase(),
  441. '</span>=&quot;<span class="nodeValue">', escapeHTML(attr.nodeValue),
  442. '</span>&quot;')
  443. }
  444. if (node.firstChild)
  445. {
  446. html.push('&gt;</div><div class="nodeChildren">');
  447. for (var child = node.firstChild; child; child = child.nextSibling)
  448. appendNode(child, html);
  449. html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">',
  450. node.nodeName.toLowerCase(), '&gt;</span></div>');
  451. }
  452. else
  453. html.push('/&gt;</div>');
  454. }
  455. else if (node.nodeType == 3)
  456. {
  457. html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
  458. '</div>');
  459. }
  460. }
  461. // ********************************************************************************************
  462. function addEvent(object, name, handler)
  463. {
  464. if (document.all)
  465. object.attachEvent("on"+name, handler);
  466. else
  467. object.addEventListener(name, handler, false);
  468. }
  469. function removeEvent(object, name, handler)
  470. {
  471. if (document.all)
  472. object.detachEvent("on"+name, handler);
  473. else
  474. object.removeEventListener(name, handler, false);
  475. }
  476. function cancelEvent(event)
  477. {
  478. if (document.all)
  479. event.cancelBubble = true;
  480. else
  481. event.stopPropagation();
  482. }
  483. function onError(msg, href, lineNo)
  484. {
  485. var html = [];
  486. var lastSlash = href.lastIndexOf("/");
  487. var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
  488. html.push(
  489. '<span class="errorMessage">', msg, '</span>',
  490. '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
  491. );
  492. logRow(html, "error");
  493. };
  494. function onKeyDown(event)
  495. {
  496. if (event.keyCode == 123)
  497. toggleConsole();
  498. else if ((event.keyCode == 108 || event.keyCode == 76) && event.shiftKey
  499. && (event.metaKey || event.ctrlKey))
  500. focusCommandLine();
  501. else
  502. return;
  503. cancelEvent(event);
  504. }
  505. function onSplitterMouseDown(event)
  506. {
  507. if (isSafari || isOpera)
  508. return;
  509. addEvent(document, "mousemove", onSplitterMouseMove);
  510. addEvent(document, "mouseup", onSplitterMouseUp);
  511. for (var i = 0; i < frames.length; ++i)
  512. {
  513. addEvent(frames[i].document, "mousemove", onSplitterMouseMove);
  514. addEvent(frames[i].document, "mouseup", onSplitterMouseUp);
  515. }
  516. }
  517. function onSplitterMouseMove(event)
  518. {
  519. var win = document.all
  520. ? event.srcElement.ownerDocument.parentWindow
  521. : event.target.ownerDocument.defaultView;
  522. var clientY = event.clientY;
  523. if (win != win.parent)
  524. clientY += win.frameElement ? win.frameElement.offsetTop : 0;
  525. var height = consoleFrame.offsetTop + consoleFrame.clientHeight;
  526. var toolbar = consoleBody.ownerDocument.getElementById("toolbar");
  527. var y = Math.max(height - clientY,
  528. toolbar.offsetHeight + commandLine.offsetHeight);
  529. consoleFrame.style.height = y + "px";
  530. layout();
  531. }
  532. function onSplitterMouseUp(event)
  533. {
  534. removeEvent(document, "mousemove", onSplitterMouseMove);
  535. removeEvent(document, "mouseup", onSplitterMouseUp);
  536. for (var i = 0; i < frames.length; ++i)
  537. {
  538. removeEvent(frames[i].document, "mousemove", onSplitterMouseMove);
  539. removeEvent(frames[i].document, "mouseup", onSplitterMouseUp);
  540. }
  541. }
  542. function onCommandLineKeyDown(event)
  543. {
  544. if (event.keyCode == 13)
  545. evalCommandLine();
  546. else if (event.keyCode == 27)
  547. commandLine.value = "";
  548. }
  549. window.onerror = onError;
  550. addEvent(document, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
  551. if (document.documentElement.getAttribute("debug") == "true")
  552. toggleConsole(true);
  553. })();
  554. }