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