1 /* See license.txt for terms of usage */ 2 3 FBL.ns(function() { with (FBL) { 4 5 // ************************************************************************************************ 6 // Constants 7 8 const Cc = Components.classes; 9 const Ci = Components.interfaces; 10 const nsIPrefBranch2 = Ci.nsIPrefBranch2; 11 const PrefService = Cc["@mozilla.org/preferences-service;1"]; 12 const prefs = PrefService.getService(nsIPrefBranch2); 13 14 // ************************************************************************************************ 15 16 var maxQueueRequests = 500; 17 18 // ************************************************************************************************ 19 20 Firebug.ConsoleBase = 21 { 22 log: function(object, context, className, rep, noThrottle, sourceLink) 23 { 24 dispatch(this.fbListeners,"log",[context, object, className, sourceLink]); 25 return this.logRow(appendObject, object, context, className, rep, sourceLink, noThrottle); 26 }, 27 28 logFormatted: function(objects, context, className, noThrottle, sourceLink) 29 { 30 dispatch(this.fbListeners,"logFormatted",[context, objects, className, sourceLink]); 31 return this.logRow(appendFormatted, objects, context, className, null, sourceLink, noThrottle); 32 }, 33 34 openGroup: function(objects, context, className, rep, noThrottle, sourceLink, noPush) 35 { 36 return this.logRow(appendOpenGroup, objects, context, className, rep, sourceLink, noThrottle); 37 }, 38 39 closeGroup: function(context, noThrottle) 40 { 41 return this.logRow(appendCloseGroup, null, context, null, null, null, noThrottle, true); 42 }, 43 44 logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow) 45 { 46 if (!context) 47 context = FirebugContext; 48 49 if (FBTrace.DBG_ERRORS && !context) 50 FBTrace.sysout("Console.logRow has no context, skipping objects", objects); 51 52 if (!context) 53 return; 54 55 if (noThrottle || !context) 56 { 57 var panel = this.getPanel(context); 58 if (panel) 59 { 60 var row = panel.append(appender, objects, className, rep, sourceLink, noRow); 61 var container = panel.panelNode; 62 var template = Firebug.NetMonitor.NetLimit; 63 64 while (container.childNodes.length > maxQueueRequests + 1) 65 { 66 clearDomplate(container.firstChild.nextSibling); 67 container.removeChild(container.firstChild.nextSibling); 68 panel.limit.limitInfo.totalCount++; 69 template.updateCounter(panel.limit); 70 } 71 dispatch([Firebug.A11yModel], "onLogRowCreated", [panel , row]); 72 return row; 73 } 74 } 75 else 76 { 77 if (!context.throttle) 78 { 79 FBTrace.sysout("console.logRow has not context.throttle! "); 80 return; 81 } 82 var args = [appender, objects, context, className, rep, sourceLink, true, noRow]; 83 context.throttle(this.logRow, this, args); 84 } 85 }, 86 87 appendFormatted: function(args, row, context) 88 { 89 if (!context) 90 context = FirebugContext; 91 92 var panel = this.getPanel(context); 93 panel.appendFormatted(args, row); 94 }, 95 96 clear: function(context) 97 { 98 if (!context) 99 context = FirebugContext; 100 101 if (context) 102 Firebug.Errors.clear(context); 103 104 var panel = this.getPanel(context, true); 105 if (panel) 106 panel.clear(); 107 }, 108 109 // Override to direct output to your panel 110 getPanel: function(context, noCreate) 111 { 112 if (context) 113 return context.getPanel("console", noCreate); 114 }, 115 116 }; 117 118 // ************************************************************************************************ 119 120 var ActivableConsole = extend(Firebug.ActivableModule, Firebug.ConsoleBase); 121 122 Firebug.Console = extend(ActivableConsole, 123 { 124 dispatchName: "console", 125 126 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 127 // extends Module 128 129 showPanel: function(browser, panel) 130 { 131 }, 132 133 getFirebugConsoleElement: function(context, win) 134 { 135 var element = win.document.getElementById("_firebugConsole"); 136 if (!element) 137 { 138 if (FBTrace.DBG_CONSOLE) 139 FBTrace.sysout("getFirebugConsoleElement forcing element"); 140 var elementForcer = "(function(){var r=null; try { r = window._getFirebugConsoleElement();}catch(exc){r=exc;} return r;})();"; // we could just add the elements here 141 142 if (context.stopped) 143 Firebug.Console.injector.evaluateConsoleScript(context); // todo evaluate consoleForcer on stack 144 else 145 var r = Firebug.CommandLine.evaluateInWebPage(elementForcer, context, win); 146 147 if (FBTrace.DBG_CONSOLE) 148 FBTrace.sysout("getFirebugConsoleElement forcing element result "+r, r); 149 150 var element = win.document.getElementById("_firebugConsole"); 151 if (!element) // elementForce fails 152 { 153 if (FBTrace.DBG_ERRORS) FBTrace.sysout("console.getFirebugConsoleElement: no _firebugConsole in win:", win); 154 Firebug.Console.logFormatted(["Firebug cannot find _firebugConsole element", r, win], context, "error", true); 155 } 156 } 157 158 return element; 159 }, 160 161 isReadyElsePreparing: function(context, win) // this is the only code that should call injector.attachIfNeeded 162 { 163 if (FBTrace.DBG_CONSOLE) 164 FBTrace.sysout("console.isReadyElsePreparing, win is " + 165 (win?"an argument: ":"null, context.window: ") + 166 (win?win.location:context.window.location), (win?win:context.window)); 167 168 if (win) 169 return this.injector.attachIfNeeded(context, win); 170 else 171 { 172 var attached = true; 173 for (var i = 0; i < context.windows.length; i++) 174 attached = attached && this.injector.attachIfNeeded(context, context.windows[i]); 175 // already in the list above attached = attached && this.injector.attachIfNeeded(context, context.window); 176 if (context.windows.indexOf(context.window) == -1) 177 FBTrace.sysout("isReadyElsePreparing ***************** context.window not in context.windows"); 178 if (FBTrace.DBG_CONSOLE) 179 FBTrace.sysout("console.isReadyElsePreparing attached to "+context.windows.length+" and returns "+attached); 180 return attached; 181 } 182 }, 183 184 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 185 // extends ActivableModule 186 187 initialize: function() 188 { 189 this.panelName = "console"; 190 191 Firebug.ActivableModule.initialize.apply(this, arguments); 192 Firebug.Debugger.addListener(this); 193 194 }, 195 196 enable: function() 197 { 198 if (Firebug.Console.isAlwaysEnabled()) 199 this.watchForErrors(); 200 }, 201 202 disable: function() 203 { 204 if (Firebug.Console.isAlwaysEnabled()) 205 this.unwatchForErrors(); 206 }, 207 208 initContext: function(context, persistedState) 209 { 210 Firebug.ActivableModule.initContext.apply(this, arguments); 211 context.consoleReloadWarning = true; // mark as need to warn. 212 }, 213 214 loadedContext: function(context) 215 { 216 for (var url in context.sourceFileMap) 217 return; // if there are any sourceFiles, then do nothing 218 219 // else we saw no JS, so the reload warning it not needed. 220 this.clearReloadWarning(context); 221 }, 222 223 clearReloadWarning: function(context) // remove the warning about reloading. 224 { 225 if (context.consoleReloadWarning) 226 { 227 var panel = context.getPanel(this.panelName); 228 panel.clearReloadWarning(); 229 delete context.consoleReloadWarning; 230 } 231 }, 232 233 togglePersist: function(context) 234 { 235 var panel = context.getPanel(this.panelName); 236 panel.persistContent = panel.persistContent ? false : true; 237 Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", panel.persistContent); 238 }, 239 240 showContext: function(browser, context) 241 { 242 Firebug.chrome.setGlobalAttribute("cmd_clearConsole", "disabled", !context); 243 244 Firebug.ActivableModule.showContext.apply(this, arguments); 245 }, 246 247 destroyContext: function(context, persistedState) 248 { 249 Firebug.Console.injector.detachConsole(context, context.window); // TODO iterate windows? 250 }, 251 252 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 253 254 onPanelEnable: function(panelName) 255 { 256 if (panelName != this.panelName) // we don't care about other panels 257 return; 258 259 if (FBTrace.DBG_CONSOLE) 260 FBTrace.sysout("console.onPanelEnable**************"); 261 262 this.watchForErrors(); 263 Firebug.Debugger.addDependentModule(this); // we inject the console during JS compiles so we need jsd 264 }, 265 266 onPanelDisable: function(panelName) 267 { 268 if (panelName != this.panelName) // we don't care about other panels 269 return; 270 271 if (FBTrace.DBG_CONSOLE) 272 FBTrace.sysout("console.onPanelDisable**************"); 273 274 Firebug.Debugger.removeDependentModule(this); // we inject the console during JS compiles so we need jsd 275 this.unwatchForErrors(); 276 277 // Make sure possible errors coming from the page and displayed in the Firefox 278 // status bar are removed. 279 this.clear(); 280 }, 281 282 onSuspendFirebug: function() 283 { 284 if (FBTrace.DBG_CONSOLE) 285 FBTrace.sysout("console.onSuspendFirebug\n"); 286 if (Firebug.Console.isAlwaysEnabled()) 287 this.unwatchForErrors(); 288 }, 289 290 onResumeFirebug: function() 291 { 292 if (FBTrace.DBG_CONSOLE) 293 FBTrace.sysout("console.onResumeFirebug\n"); 294 if (Firebug.Console.isAlwaysEnabled()) 295 this.watchForErrors(); 296 }, 297 298 watchForErrors: function() 299 { 300 Firebug.Errors.checkEnabled(); 301 $('fbStatusIcon').setAttribute("console", "on"); 302 }, 303 304 unwatchForErrors: function() 305 { 306 Firebug.Errors.checkEnabled(); 307 $('fbStatusIcon').removeAttribute("console"); 308 }, 309 310 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 311 // Firebug.Debugger listener 312 313 onMonitorScript: function(context, frame) 314 { 315 Firebug.Console.log(frame, context); 316 }, 317 318 onFunctionCall: function(context, frame, depth, calling) 319 { 320 if (calling) 321 Firebug.Console.openGroup([frame, "depth:"+depth], context); 322 else 323 Firebug.Console.closeGroup(context); 324 }, 325 326 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 327 328 logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow) 329 { 330 if (!context) 331 context = FirebugContext; 332 333 if (FBTrace.DBG_WINDOWS && !context) FBTrace.sysout("Console.logRow: no context \n"); 334 335 if (this.isAlwaysEnabled()) 336 return Firebug.ConsoleBase.logRow.apply(this, arguments); 337 }, 338 }); 339 340 Firebug.ConsoleListener = 341 { 342 log: function(context, object, className, sourceLink) 343 { 344 }, 345 346 logFormatted: function(context, objects, className, sourceLink) 347 { 348 } 349 }; 350 351 // ************************************************************************************************ 352 353 Firebug.ConsolePanel = function () {} // XXjjb attach Firebug so this panel can be extended. 354 355 Firebug.ConsolePanel.prototype = extend(Firebug.ActivablePanel, 356 { 357 wasScrolledToBottom: false, 358 messageCount: 0, 359 lastLogTime: 0, 360 groups: null, 361 limit: null, 362 363 append: function(appender, objects, className, rep, sourceLink, noRow) 364 { 365 var container = this.getTopContainer(); 366 367 if (noRow) 368 { 369 appender.apply(this, [objects]); 370 } 371 else 372 { 373 // Don't update the this.wasScrolledToBottom flag now. At the beginning (when the 374 // first log is created) the isScrolledToBottom always returns true. 375 // But make sure the panel scrolls if it should. 376 var wasScrolledToBottom = false; 377 if (this.panelNode.offsetHeight) 378 wasScrolledToBottom = isScrolledToBottom(this.panelNode); 379 380 var row = this.createRow("logRow", className); 381 appender.apply(this, [objects, row, rep]); 382 383 if (sourceLink) 384 FirebugReps.SourceLink.tag.append({object: sourceLink}, row); 385 386 container.appendChild(row); 387 388 this.filterLogRow(row, this.wasScrolledToBottom); 389 390 if (wasScrolledToBottom) 391 scrollToBottom(this.panelNode); 392 393 return row; 394 } 395 }, 396 397 clear: function() 398 { 399 if (this.panelNode) 400 { 401 if (FBTrace.DBG_CONSOLE) 402 FBTrace.sysout("ConsolePanel.clear"); 403 clearNode(this.panelNode); 404 this.insertLogLimit(this.context); 405 } 406 }, 407 408 insertLogLimit: function() 409 { 410 // Create limit row. This row is the first in the list of entries 411 // and initially hidden. It's displayed as soon as the number of 412 // entries reaches the limit. 413 var row = this.createRow("limitRow"); 414 415 var limitInfo = { 416 totalCount: 0, 417 limitPrefsTitle: $STRF("LimitPrefsTitle", [Firebug.prefDomain+".console.logLimit"]) 418 }; 419 420 var netLimitRep = Firebug.NetMonitor.NetLimit; 421 var nodes = netLimitRep.createTable(row, limitInfo); 422 423 this.limit = nodes[1]; 424 425 var container = this.panelNode; 426 container.insertBefore(nodes[0], container.firstChild); 427 }, 428 429 insertReloadWarning: function() 430 { 431 // put the message in, we will clear if the window console is injected. 432 this.warningRow = this.append(appendObject, $STR("message.Reload to activate window console"), "info"); 433 }, 434 435 clearReloadWarning: function() 436 { 437 if (this.warningRow) 438 { 439 this.warningRow.parentNode.removeChild(this.warningRow); 440 delete this.warningRow; 441 } 442 }, 443 444 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 445 446 appendObject: function(object, row, rep) 447 { 448 if (!rep) 449 rep = Firebug.getRep(object); 450 return rep.tag.append({object: object}, row); 451 }, 452 453 appendFormatted: function(objects, row, rep) 454 { 455 if (!objects || !objects.length) 456 return; 457 458 function logText(text, row) 459 { 460 var node = row.ownerDocument.createTextNode(text); 461 row.appendChild(node); 462 } 463 464 var format = objects[0]; 465 var objIndex = 0; 466 467 if (typeof(format) != "string") 468 { 469 format = ""; 470 objIndex = -1; 471 } 472 else // a string 473 { 474 if (objects.length === 1) // then we have only a string... 475 { 476 if (format.length < 1) { // ...and it has no characters. 477 logText("(an empty string)", row); 478 return; 479 } 480 } 481 } 482 483 var parts = parseFormat(format); 484 var trialIndex = objIndex; 485 for (var i= 0; i < parts.length; i++) 486 { 487 var part = parts[i]; 488 if (part && typeof(part) == "object") 489 { 490 if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted. 491 { 492 format = ""; 493 objIndex = -1; 494 parts.length = 0; 495 break; 496 } 497 } 498 499 } 500 for (var i = 0; i < parts.length; ++i) 501 { 502 var part = parts[i]; 503 if (part && typeof(part) == "object") 504 { 505 var object = objects[++objIndex]; 506 if (part.type == "%c") 507 row.setAttribute("style", object.toString()); 508 else if (typeof(object) != "undefined") 509 this.appendObject(object, row, part.rep); 510 else 511 this.appendObject(part.type, row, FirebugReps.Text); 512 } 513 else 514 FirebugReps.Text.tag.append({object: part}, row); 515 } 516 517 for (var i = objIndex+1; i < objects.length; ++i) 518 { 519 logText(" ", row); 520 var object = objects[i]; 521 if (typeof(object) == "string") 522 FirebugReps.Text.tag.append({object: object}, row); 523 else 524 this.appendObject(object, row); 525 } 526 }, 527 528 appendOpenGroup: function(objects, row, rep) 529 { 530 if (!this.groups) 531 this.groups = []; 532 533 setClass(row, "logGroup"); 534 setClass(row, "opened"); 535 536 var innerRow = this.createRow("logRow"); 537 setClass(innerRow, "logGroupLabel"); 538 if (rep) 539 rep.tag.replace({"objects": objects}, innerRow); 540 else 541 this.appendFormatted(objects, innerRow, rep); 542 row.appendChild(innerRow); 543 dispatch([Firebug.A11yModel], 'onLogRowCreated', [this, innerRow]); 544 var groupBody = this.createRow("logGroupBody"); 545 row.appendChild(groupBody); 546 groupBody.setAttribute('role', 'group'); 547 this.groups.push(groupBody); 548 549 innerRow.addEventListener("mousedown", function(event) 550 { 551 if (isLeftClick(event)) 552 { 553 var groupRow = event.currentTarget.parentNode; 554 if (hasClass(groupRow, "opened")) 555 { 556 removeClass(groupRow, "opened"); 557 event.target.setAttribute('aria-expanded', 'false'); 558 } 559 else 560 { 561 setClass(groupRow, "opened"); 562 event.target.setAttribute('aria-expanded', 'true'); 563 } 564 } 565 }, false); 566 }, 567 568 appendCloseGroup: function(object, row, rep) 569 { 570 if (this.groups) 571 this.groups.pop(); 572 }, 573 574 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 575 // extends Panel 576 577 name: "console", 578 searchable: true, 579 breakable: true, 580 editable: false, 581 582 initialize: function() 583 { 584 Firebug.ActivablePanel.initialize.apply(this, arguments); // loads persisted content 585 586 if (!this.persistedContent && Firebug.Console.isAlwaysEnabled()) 587 { 588 this.insertLogLimit(this.context); 589 590 // Initialize log limit and listen for changes. 591 this.updateMaxLimit(); 592 593 if (this.context.consoleReloadWarning) // we have not yet injected the console 594 this.insertReloadWarning(); 595 } 596 597 prefs.addObserver(Firebug.prefDomain, this, false); 598 }, 599 600 initializeNode : function() 601 { 602 dispatch([Firebug.A11yModel], 'onInitializeNode', [this]); 603 if (FBTrace.DBG_CONSOLE) 604 { 605 this.onScroller = bind(this.onScroll, this); 606 this.panelNode.addEventListener("scroll", this.onScroller, true); 607 } 608 609 this.onResizer = bind(this.onResize, this); 610 this.resizeEventTarget = Firebug.chrome.$('fbContentBox'); 611 this.resizeEventTarget.addEventListener("resize", this.onResizer, true); 612 }, 613 614 destroyNode : function() 615 { 616 dispatch([Firebug.A11yModel], 'onDestroyNode', [this]); 617 if (this.onScroller) 618 this.panelNode.removeEventListener("scroll", this.onScroller, true); 619 620 this.resizeEventTarget.removeEventListener("resize", this.onResizer, true); 621 }, 622 623 shutdown: function() 624 { 625 prefs.removeObserver(Firebug.prefDomain, this, false); 626 }, 627 628 show: function(state) 629 { 630 if (FBTrace.DBG_CONSOLE) 631 FBTrace.sysout("Console.panel show; " + this.context.getName(), state); 632 633 var enabled = Firebug.Console.isAlwaysEnabled(); 634 if (enabled) 635 { 636 Firebug.Console.disabledPanelPage.hide(this); 637 this.showCommandLine(true); 638 this.showToolbarButtons("fbConsoleButtons", true); 639 Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", this.persistContent); 640 641 if (state && state.wasScrolledToBottom) 642 { 643 this.wasScrolledToBottom = state.wasScrolledToBottom; 644 delete state.wasScrolledToBottom; 645 } 646 647 if (this.wasScrolledToBottom) 648 scrollToBottom(this.panelNode); 649 650 if (FBTrace.DBG_CONSOLE) 651 FBTrace.sysout("console.show ------------------ wasScrolledToBottom: " + 652 this.wasScrolledToBottom + ", " + this.context.getName()); 653 654 if (state && state.profileRow) // then we reloaded while profiling 655 { 656 FBTrace.sysout("console.initialize state.profileRow:", state.profileRow); 657 this.context.profileRow = state.profileRow; 658 this.panelNode.appendChild(state.profileRow); 659 delete state.profileRow; 660 } 661 } 662 else 663 { 664 this.hide(state); 665 Firebug.Console.disabledPanelPage.show(this); 666 } 667 }, 668 669 hide: function(state) 670 { 671 if (FBTrace.DBG_CONSOLE) 672 FBTrace.sysout("Console.panel hide; " + this.context.getName(), state); 673 674 this.showToolbarButtons("fbConsoleButtons", false); 675 this.showCommandLine(false); 676 677 if (FBTrace.DBG_CONSOLE) 678 FBTrace.sysout("console.hide ------------------ wasScrolledToBottom: " + 679 this.wasScrolledToBottom + ", " + this.context.getName()); 680 }, 681 682 destroy: function(state) 683 { 684 Firebug.ActivablePanel.destroy.apply(this, arguments); 685 686 if (this.panelNode.offsetHeight) 687 this.wasScrolledToBottom = isScrolledToBottom(this.panelNode); 688 689 if (state) 690 state.wasScrolledToBottom = this.wasScrolledToBottom; 691 692 // If we are profiling and reloading, save the profileRow for the new context 693 if (this.context.profileRow && this.context.profileRow.ownerDocument) 694 { 695 this.context.profileRow.parentNode.removeChild(this.context.profileRow); 696 state.profileRow = this.context.profileRow; 697 } 698 699 if (FBTrace.DBG_CONSOLE) 700 FBTrace.sysout("console.destroy ------------------ wasScrolledToBottom: " + 701 this.wasScrolledToBottom + ", " + this.context.getName()); 702 }, 703 704 shouldBreakOnNext: function() 705 { 706 // xxxHonza: shouldn't the breakOnErrors be context related? 707 // xxxJJB, yes, but we can't support it because we can't yet tell 708 // which window the error is on. 709 return Firebug.getPref(Firebug.servicePrefDomain, "breakOnErrors"); 710 }, 711 712 getBreakOnNextTooltip: function(enabled) 713 { 714 return (enabled ? $STR("console.Disable Break On All Errors") : 715 $STR("console.Break On All Errors")); 716 }, 717 718 enablePanel: function(module) 719 { 720 if (FBTrace.DBG_CONSOLE) 721 FBTrace.sysout("console.ConsolePanel.enablePanel; " + this.context.getName()); 722 723 Firebug.ActivablePanel.enablePanel.apply(this, arguments); 724 725 this.showCommandLine(true); 726 727 if (this.wasScrolledToBottom) 728 scrollToBottom(this.panelNode); 729 }, 730 731 disablePanel: function(module) 732 { 733 if (FBTrace.DBG_CONSOLE) 734 FBTrace.sysout("console.ConsolePanel.disablePanel; " + this.context.getName()); 735 736 Firebug.ActivablePanel.disablePanel.apply(this, arguments); 737 738 this.showCommandLine(false); 739 }, 740 741 getOptionsMenuItems: function() 742 { 743 return [ 744 optionMenu("ShowJavaScriptErrors", "showJSErrors"), 745 optionMenu("ShowJavaScriptWarnings", "showJSWarnings"), 746 optionMenu("ShowCSSErrors", "showCSSErrors"), 747 optionMenu("ShowXMLErrors", "showXMLErrors"), 748 optionMenu("ShowXMLHttpRequests", "showXMLHttpRequests"), 749 optionMenu("ShowChromeErrors", "showChromeErrors"), 750 optionMenu("ShowChromeMessages", "showChromeMessages"), 751 optionMenu("ShowExternalErrors", "showExternalErrors"), 752 optionMenu("ShowNetworkErrors", "showNetworkErrors"), 753 this.getShowStackTraceMenuItem(), 754 this.getStrictOptionMenuItem(), 755 "-", 756 optionMenu("LargeCommandLine", "largeCommandLine") 757 ]; 758 }, 759 760 getShowStackTraceMenuItem: function() 761 { 762 var menuItem = serviceOptionMenu("ShowStackTrace", "showStackTrace"); 763 if (FirebugContext && !Firebug.Debugger.isAlwaysEnabled()) 764 menuItem.disabled = true; 765 return menuItem; 766 }, 767 768 getStrictOptionMenuItem: function() 769 { 770 var strictDomain = "javascript.options"; 771 var strictName = "strict"; 772 var strictValue = prefs.getBoolPref(strictDomain+"."+strictName); 773 return {label: "JavascriptOptionsStrict", type: "checkbox", checked: strictValue, 774 command: bindFixed(Firebug.setPref, Firebug, strictDomain, strictName, !strictValue) }; 775 }, 776 777 getBreakOnMenuItems: function() 778 { 779 //xxxHonza: no BON options for now. 780 /*return [ 781 optionMenu("console.option.Persist Break On Error", "persistBreakOnError") 782 ];*/ 783 return []; 784 }, 785 786 search: function(text) 787 { 788 if (!text) 789 return; 790 791 // Make previously visible nodes invisible again 792 if (this.matchSet) 793 { 794 for (var i in this.matchSet) 795 removeClass(this.matchSet[i], "matched"); 796 } 797 798 this.matchSet = []; 799 800 function findRow(node) { return getAncestorByClass(node, "logRow"); } 801 var search = new TextSearch(this.panelNode, findRow); 802 803 var logRow = search.find(text); 804 if (!logRow) 805 { 806 dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, []]); 807 return false; 808 } 809 for (; logRow; logRow = search.findNext()) 810 { 811 setClass(logRow, "matched"); 812 this.matchSet.push(logRow); 813 } 814 dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, this.matchSet]); 815 return true; 816 }, 817 818 breakOnNext: function(breaking) 819 { 820 Firebug.setPref(Firebug.servicePrefDomain, "breakOnErrors", breaking); 821 }, 822 823 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 824 // private 825 826 createRow: function(rowName, className) 827 { 828 var elt = this.document.createElement("div"); 829 elt.className = rowName + (className ? " " + rowName + "-" + className : ""); 830 return elt; 831 }, 832 833 getTopContainer: function() 834 { 835 if (this.groups && this.groups.length) 836 return this.groups[this.groups.length-1]; 837 else 838 return this.panelNode; 839 }, 840 841 filterLogRow: function(logRow, scrolledToBottom) 842 { 843 if (this.searchText) 844 { 845 setClass(logRow, "matching"); 846 setClass(logRow, "matched"); 847 848 // Search after a delay because we must wait for a frame to be created for 849 // the new logRow so that the finder will be able to locate it 850 setTimeout(bindFixed(function() 851 { 852 if (this.searchFilter(this.searchText, logRow)) 853 this.matchSet.push(logRow); 854 else 855 removeClass(logRow, "matched"); 856 857 removeClass(logRow, "matching"); 858 859 if (scrolledToBottom) 860 scrollToBottom(this.panelNode); 861 }, this), 100); 862 } 863 }, 864 865 searchFilter: function(text, logRow) 866 { 867 var count = this.panelNode.childNodes.length; 868 var searchRange = this.document.createRange(); 869 searchRange.setStart(this.panelNode, 0); 870 searchRange.setEnd(this.panelNode, count); 871 872 var startPt = this.document.createRange(); 873 startPt.setStartBefore(logRow); 874 875 var endPt = this.document.createRange(); 876 endPt.setStartAfter(logRow); 877 878 return finder.Find(text, searchRange, startPt, endPt) != null; 879 }, 880 881 // nsIPrefObserver 882 observe: function(subject, topic, data) 883 { 884 // We're observing preferences only. 885 if (topic != "nsPref:changed") 886 return; 887 888 // xxxHonza check this out. 889 var prefDomain = "Firebug.extension."; 890 var prefName = data.substr(prefDomain.length); 891 if (prefName == "console.logLimit") 892 this.updateMaxLimit(); 893 }, 894 895 updateMaxLimit: function() 896 { 897 var value = Firebug.getPref(Firebug.prefDomain, "console.logLimit"); 898 maxQueueRequests = value ? value : maxQueueRequests; 899 }, 900 901 showCommandLine: function(shouldShow) 902 { 903 if (shouldShow) 904 { 905 collapse(Firebug.chrome.$("fbCommandBox"), false); 906 Firebug.CommandLine.setMultiLine(Firebug.largeCommandLine, Firebug.chrome); 907 } 908 else 909 { 910 // Make sure that entire content of the Console panel is hidden when 911 // the panel is disabled. 912 Firebug.CommandLine.setMultiLine(false, Firebug.chrome, Firebug.largeCommandLine); 913 collapse(Firebug.chrome.$("fbCommandBox"), true); 914 } 915 }, 916 917 onScroll: function(event) 918 { 919 // Update the scroll position flag if the position changes. 920 this.wasScrolledToBottom = FBL.isScrolledToBottom(this.panelNode); 921 922 if (FBTrace.DBG_CONSOLE) 923 FBTrace.sysout("console.onScroll ------------------ wasScrolledToBottom: " + 924 this.wasScrolledToBottom + ", wasScrolledToBottom: " + 925 this.context.getName(), event); 926 }, 927 928 onResize: function(event) 929 { 930 if (FBTrace.DBG_CONSOLE) 931 FBTrace.sysout("console.onResize ------------------ wasScrolledToBottom: " + 932 this.wasScrolledToBottom + ", offsetHeight: " + this.panelNode.offsetHeight + 933 ", scrollTop: " + this.panelNode.scrollTop + ", scrollHeight: " + 934 this.panelNode.scrollHeight + ", " + this.context.getName(), event); 935 936 if (this.wasScrolledToBottom) 937 scrollToBottom(this.panelNode); 938 }, 939 }); 940 941 // ************************************************************************************************ 942 943 function parseFormat(format) 944 { 945 var parts = []; 946 if (format.length <= 0) 947 return parts; 948 949 var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/; 950 for (var m = reg.exec(format); m; m = reg.exec(format)) 951 { 952 if (m[0].substr(0, 2) == "%%") 953 { 954 parts.push(format.substr(0, m.index)); 955 parts.push(m[0].substr(1)); 956 } 957 else 958 { 959 var type = m[8] ? m[8] : m[5]; 960 var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); 961 962 var rep = null; 963 switch (type) 964 { 965 case "s": 966 rep = FirebugReps.Text; 967 break; 968 case "f": 969 case "i": 970 case "d": 971 rep = FirebugReps.Number; 972 break; 973 case "o": 974 case "c": 975 rep = null; 976 break; 977 } 978 979 parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); 980 parts.push({rep: rep, precision: precision, type: ("%" + type)}); 981 } 982 983 format = format.substr(m.index+m[0].length); 984 } 985 986 parts.push(format); 987 return parts; 988 } 989 990 // ************************************************************************************************ 991 992 var appendObject = Firebug.ConsolePanel.prototype.appendObject; 993 var appendFormatted = Firebug.ConsolePanel.prototype.appendFormatted; 994 var appendOpenGroup = Firebug.ConsolePanel.prototype.appendOpenGroup; 995 var appendCloseGroup = Firebug.ConsolePanel.prototype.appendCloseGroup; 996 997 // ************************************************************************************************ 998 999 Firebug.registerActivableModule(Firebug.Console); 1000 Firebug.registerPanel(Firebug.ConsolePanel); 1001 1002 // ************************************************************************************************ 1003 }}); 1004