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 11 const nsIPrefBranch = Ci.nsIPrefBranch; 12 const nsIPrefBranch2 = Ci.nsIPrefBranch2; 13 const nsISupports = Ci.nsISupports; 14 const nsIFile = Ci.nsIFile; 15 const nsILocalFile = Ci.nsILocalFile; 16 const nsISafeOutputStream = Ci.nsISafeOutputStream; 17 const nsIURI = Ci.nsIURI; 18 19 const PrefService = Cc["@mozilla.org/preferences-service;1"]; 20 const DirService = CCSV("@mozilla.org/file/directory_service;1", "nsIDirectoryServiceProvider"); 21 22 const nsIPrefService = Ci.nsIPrefService; 23 const prefService = PrefService.getService(nsIPrefService); 24 25 const observerService = CCSV("@mozilla.org/observer-service;1", "nsIObserverService"); 26 const categoryManager = CCSV("@mozilla.org/categorymanager;1", "nsICategoryManager"); 27 const stringBundleService = CCSV("@mozilla.org/intl/stringbundle;1", "nsIStringBundleService"); 28 const promptService = CCSV("@mozilla.org/embedcomp/prompt-service;1", "nsIPromptService"); 29 30 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 31 // There is one Firebug object per browser.xul 32 33 const contentBox = $("fbContentBox"); 34 const contentSplitter = $("fbContentSplitter"); 35 const toggleCommand = $("cmd_toggleFirebug"); 36 const detachCommand = $("cmd_toggleDetachFirebug"); 37 const tabBrowser = $("content"); 38 const versionURL = "chrome://firebug/content/branch.properties"; 39 const statusBarContextMenu = $("fbStatusContextMenu"); 40 41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 42 43 const prefs = PrefService.getService(nsIPrefBranch2); 44 const NS_OS_TEMP_DIR = "TmpD" 45 46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 47 48 const firebugURLs = 49 { 50 main: "http://www.getfirebug.com", 51 docs: "http://www.getfirebug.com/docs.html", 52 keyboard: "http://www.getfirebug.com/keyboard.html", 53 discuss: "http://groups.google.com/group/firebug", 54 issues: "http://code.google.com/p/fbug/issues/list", 55 donate: "http://www.getfirebug.com/contribute.html?product" 56 }; 57 58 const prefNames = // XXXjjb TODO distribute to modules 59 [ 60 // Global 61 "defaultPanelName", "throttleMessages", "textSize", "showInfoTips", 62 "largeCommandLine", "textWrapWidth", "openInWindow", "showErrorCount", 63 "activateSameOrigin", "allPagesActivation", "hiddenPanels", 64 "panelTabMinWidth", "sourceLinkLabelWidth", 65 66 // Search 67 "searchCaseSensitive", "searchGlobal", "netSearchHeaders", "netSearchParameters", 68 "netSearchResponseBody", 69 70 // Console 71 "showJSErrors", "showJSWarnings", "showCSSErrors", "showXMLErrors", 72 "showChromeErrors", "showChromeMessages", "showExternalErrors", 73 "showXMLHttpRequests", "showNetworkErrors", 74 75 "persistBreakOnError", 76 77 // HTML 78 "showFullTextNodes", "showCommentNodes", 79 "showTextNodesWithWhitespace", "showTextNodesWithEntities", 80 "highlightMutations", "expandMutations", "scrollToMutations", "shadeBoxModel", 81 "showQuickInfoBox", 82 83 // CSS 84 "showUserAgentCSS", 85 "expandShorthandProps", 86 87 // Script 88 "decompileEvals", "replaceTabs", 89 90 // DOM 91 "showUserProps", "showUserFuncs", "showDOMProps", "showDOMFuncs", "showDOMConstants", 92 93 // Layout 94 "showRulers", 95 96 // Net 97 "netFilterCategory", "collectHttpHeaders", "netDisplayedResponseLimit", 98 "netDisplayedPostBodyLimit", "netPhaseInterval", "sizePrecision", 99 "netParamNameLimit", 100 101 // Stack 102 "omitObjectPathStack", 103 104 // Debugging 105 "clearDomplate" 106 ]; 107 108 const servicePrefNames = [ 109 "showStackTrace", // Console 110 "filterSystemURLs", // Stack 111 "showAllSourceFiles", "breakOnErrors", "trackThrowCatch" // Script 112 ]; 113 114 const scriptBlockSize = 20; 115 116 const PLACEMENT_NONE = 0; 117 const PLACEMENT_INBROWSER = 1; 118 const PLACEMENT_DETACHED = 2; 119 const PLACEMENT_MINIMIZED = 3; 120 121 // ************************************************************************************************ 122 // Globals 123 124 var modules = []; 125 var activeContexts = []; 126 var activableModules = []; 127 var extensions = []; 128 var panelTypes = []; 129 var reps = []; 130 var defaultRep = null; 131 var defaultFuncRep = null; 132 var editors = []; 133 var externalEditors = []; 134 135 var panelTypeMap = {}; 136 var optionUpdateMap = {}; 137 138 var deadWindows = []; 139 var deadWindowTimeout = 0; 140 var clearContextTimeout = 0; 141 var temporaryFiles = []; 142 var temporaryDirectory = null; 143 144 // Register default Firebug string bundle (yet before domplate templates). 145 categoryManager.addCategoryEntry("strings_firebug", 146 "chrome://firebug/locale/firebug.properties", "", true, true); 147 148 // ************************************************************************************************ 149 150 /** 151 * @class Represents the main Firebug application object. An instance of this object is 152 * created for each browser window (browser.xul). 153 */ 154 top.Firebug = 155 { 156 version: "1.5", 157 158 dispatchName: "Firebug", 159 module: modules, 160 panelTypes: panelTypes, 161 uiListeners: [], 162 reps: reps, 163 prefDomain: "extensions.firebug", 164 servicePrefDomain: "extensions.firebug.service", 165 166 stringCropLength: 50, 167 168 tabBrowser: tabBrowser, 169 originalChrome: FirebugChrome, 170 chrome: FirebugChrome, 171 172 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 173 // Initialization 174 175 initialize: function() 176 { 177 var version = this.getVersion(); 178 if (version) 179 { 180 this.version = version; 181 $('fbStatusBar').setAttribute("tooltiptext", "Firebug " + version); 182 183 var about = $('Firebug_About'); 184 if (about) 185 { 186 var aboutLabel = about.getAttribute("label"); 187 $('Firebug_About').setAttribute("label", aboutLabel + " " + version); 188 } 189 } 190 191 for (var i = 0; i < prefNames.length; ++i) 192 this[prefNames[i]] = this.getPref(this.prefDomain, prefNames[i]); 193 for (var i = 0; i < servicePrefNames.length; ++i) 194 this[servicePrefNames[i]] = this.getPref(this.servicePrefDomain, servicePrefNames[i]); 195 196 this.loadExternalEditors(); 197 198 prefs.addObserver(this.prefDomain, this, false); 199 prefs.addObserver(this.servicePrefDomain, this, false); 200 201 var basePrefNames = prefNames.length; 202 203 this.clientID = Firebug.Debugger.registerClient(this); 204 205 dispatch(modules, "initialize", [this.prefDomain, prefNames]); 206 207 for (var i = basePrefNames; i < prefNames.length; ++i) 208 this[prefNames[i]] = this.getPref(this.prefDomain, prefNames[i]); 209 210 if (FBTrace.DBG_OPTIONS) 211 { 212 for (var i = 0; i < prefNames.length; ++i) 213 FBTrace.sysout("firebug.initialize option "+this.prefDomain+"."+prefNames[i]+"="+this[prefNames[i]]+"\n"); 214 } 215 if (FBTrace.DBG_INITIALIZE) 216 FBTrace.sysout("firebug.initialize client: "+this.clientID+" with prefDomain "+this.prefDomain); 217 218 // In the case that the user opens firebug in a new window but then closes Firefox window, we don't get the 219 // quitApplicationGranted event (platform is still running) and we call shutdown (Firebug isDetached). 220 window.addEventListener('unload', shutdownFirebug, false); 221 }, 222 223 getVersion: function() 224 { 225 if (!this.fullVersion) 226 this.fullVersion = this.loadVersion(versionURL); 227 228 return this.fullVersion; 229 }, 230 231 loadVersion: function(versionURL) 232 { 233 var content = getResource(versionURL); 234 if (!content) 235 return "no content at "+versionURL; 236 237 var m = /RELEASE=(.*)/.exec(content); 238 if (m) 239 var release = m[1]; 240 else 241 return "no RELEASE in "+versionURL; 242 243 m = /VERSION=(.*)/.exec(content); 244 if (m) 245 var version = m[1]; 246 else 247 return "no VERSION in "+versionURL; 248 249 return version+""+release; 250 }, 251 252 internationalizeUI: function(doc) // Substitute strings in the UI with fall back to en-US 253 { 254 if (!doc) 255 return; 256 257 if (FBTrace.DBG_INITIALIZE) 258 FBTrace.sysout("Firebug.internationalizeUI"); 259 260 var elements = ["menu_clearConsole", "menu_resetAllOptions", 261 "menu_enablePanels", "menu_disablePanels", 262 "fbCommandLine", "fbFirebugMenu", "fbLargeCommandLine", "menu_customizeShortcuts", 263 "menu_enableA11y", "menu_activateSameOrigin", "menu_onByDefault", "fbContinueButton", 264 "fbBreakOnNextButton", "fbConsolePersist", 265 "fbMinimizeButton", "FirebugMenu_Sites", "fbResumeBoxButton", 266 "menu_AllOn", "menu_clearActivationList", "showQuickInfoBox"]; 267 268 for (var i=0; i<elements.length; i++) 269 { 270 var element = doc.getElementById(elements[i]); 271 if (!element) 272 { 273 if (FBTrace.DBG_LOCALE) 274 FBTrace.sysout("firebug.internationalizeUI; Element Not Found: " + elements[i]); 275 continue; 276 } 277 278 if (element.hasAttribute("label")) 279 FBL.internationalize(element, "label"); 280 281 if (element.hasAttribute("tooltiptext")) 282 FBL.internationalize(element, "tooltiptext"); 283 } 284 285 // Allow other modules to internationalize UI labels (called also for 286 // detached Firebug window). 287 dispatch(modules, "internationalizeUI", [doc]); 288 }, 289 290 broadcast: function(message, args) 291 { 292 // dispatch message to all XUL windows registered to firebug service. 293 // Implemented in Firebug.Debugger. 294 }, 295 296 /** 297 * Called when the UI is ready to be initialized, once the panel browsers are loaded, 298 * but before any contexts are created. 299 */ 300 initializeUI: function(detachArgs) 301 { 302 if (FBTrace.DBG_INITIALIZE) 303 FBTrace.sysout("firebug.initializeUI this.disabledAlways="+this.disabledAlways+ 304 " detachArgs:", detachArgs); 305 306 TabWatcher.initialize(this); 307 TabWatcher.addListener(this); 308 309 // Initialize all modules. 310 dispatch(modules, "initializeUI", [detachArgs]); 311 }, 312 313 314 shutdown: function() // called in browser when Firefox closes and in externalMode when fbs gets quitApplicationGranted. 315 { 316 window.removeEventListener('unload', shutdownFirebug, false); 317 318 Firebug.Debugger.unregisterClient(this); 319 320 TabWatcher.destroy(); 321 322 // Remove the listener after the TabWatcher.destroy() method is called so, 323 // destroyContext event is properly dispatched to the Firebug object and 324 // consequently to all registered modules. 325 TabWatcher.removeListener(this); 326 327 dispatch(modules, "disable", [FirebugChrome]); 328 329 prefService.savePrefFile(null); 330 prefs.removeObserver(this.prefDomain, this, false); 331 prefs.removeObserver(this.servicePrefDomain, this, false); 332 333 dispatch(modules, "shutdown"); 334 335 this.closeDeadWindows(); 336 this.deleteTemporaryFiles(); 337 338 if (FBTrace.DBG_INITIALIZE) 339 FBTrace.sysout("firebug.shutdown exited client "+this.clientID); 340 }, 341 342 // ---------------------------------------------------------------------------------------------------------------- 343 344 getSuspended: function() 345 { 346 var suspendMarker = $("fbStatusIcon"); 347 if (suspendMarker.hasAttribute("suspended")) 348 return suspendMarker.getAttribute("suspended"); 349 return null; 350 }, 351 352 setSuspended: function(value) 353 { 354 var suspendMarker = $("fbStatusIcon"); 355 if (FBTrace.DBG_ACTIVATION) 356 FBTrace.sysout("Firebug.setSuspended to "+value+". Browser: " + 357 Firebug.chrome.window.document.title); 358 359 if (value) 360 suspendMarker.setAttribute("suspended", value); 361 else 362 suspendMarker.removeAttribute("suspended"); 363 364 Firebug.resetTooltip(); 365 }, 366 367 toggleSuspend: function() 368 { 369 // getSuspended returns non-null value if Firebug is suspended. 370 if (this.getSuspended()) 371 { 372 // Firebug is suspended now. Two possible actions have been executed: 373 // 1) Firebug UI is closed and the user clicked on the status bar icon in order to 374 // show the UI and resume Firebug. 375 // 2) Firebug is detached, but suspended for the current page. The user clicked 376 // either on the status bar icon or on an activation button that is displayed 377 // within detached Firebug window. 378 this.toggleBar(true); 379 } 380 else 381 { 382 // The users wants to suspend Firebug, let's do it and pull down the visible UI. 383 // xxxHonza: the Firebug isn't suspended if detached and the user clicks on the 384 // status bar icon (the detached window should becoma blank displaying only 385 // the activation button). 386 this.suspend(); 387 388 // Close detached Firebug or 389 // show/hide Firebug UI according to the browser.showFirebug flag. 390 if (Firebug.isDetached()) 391 this.toggleDetachBar(false); 392 else 393 this.syncBar(); 394 } 395 }, 396 397 disablePanels: function(context) 398 { 399 Firebug.ModuleManager.disableModules(); 400 }, 401 402 suspend: function() // dispatch suspendFirebug to all windows 403 { 404 this.broadcast('suspendFirebug', []); 405 }, 406 407 suspendFirebug: function() // dispatch onSuspendFirebug to all modules 408 { 409 this.setSuspended("suspending"); 410 411 var cancelSuspend = dispatch2(activableModules, 'onSuspendFirebug', [FirebugContext]); // TODO no context arg 412 413 if (cancelSuspend) 414 Firebug.resume(); 415 else 416 this.setSuspended("suspended"); 417 }, 418 419 resume: function() 420 { 421 this.broadcast('resumeFirebug', []); 422 }, 423 424 resumeFirebug: function() // dispatch onResumeFirebug to all modules 425 { 426 this.setSuspended("resuming"); 427 dispatch(activableModules, 'onResumeFirebug', [FirebugContext]);// TODO no context arg 428 this.setSuspended(null); 429 }, 430 431 getEnablementStatus: function() 432 { 433 var strOn = $STR("enablement.on"); 434 var strOff = $STR("enablement.off"); 435 436 var status = ""; 437 var fbStatusIcon = $('fbStatusIcon'); 438 if (fbStatusIcon.getAttribute("console") == "on") 439 status +="Console: "+strOn+","; 440 else 441 status +="Console: "+strOff+","; 442 443 if (fbStatusIcon.getAttribute("net") == "on") 444 status +=" Net: "+strOn+","; 445 else 446 status +=" Net: "+strOff+","; 447 448 if (fbStatusIcon.getAttribute("script") == "on") 449 status +=" Script: "+strOn; 450 else 451 status +=" Script: "+strOff+""; 452 453 return status; 454 }, 455 456 resetTooltip: function() 457 { 458 if (FBTrace.DBG_TOOLTIP) 459 FBTrace.sysout("resetTooltip called"); 460 461 var tooltip = "Firebug " + Firebug.getVersion(); 462 463 tooltip += "\n" + Firebug.getEnablementStatus(); 464 465 if (Firebug.getSuspended()) 466 tooltip += "\n" + Firebug.getSuspended(); 467 else 468 tooltip += "\n" + $STRP("plural.Total_Firebugs", [TabWatcher.contexts.length]); 469 470 if (Firebug.allPagesActivation == "on") 471 { 472 var label = $STR("enablement.on"); 473 tooltip += "\n"+label+" "+$STR("enablement.for all pages"); 474 } 475 // else allPagesActivation == "none" we don't show it. 476 477 tooltip += "\n" + $STR(Firebug.getPlacement()); 478 479 $('fbStatusBar').setAttribute("tooltiptext", tooltip); 480 }, 481 482 getURLsForAllActiveContexts: function() 483 { 484 var contextURLSet = []; // create a list of all unique activeContexts 485 TabWatcher.iterateContexts( function createActiveContextList(context) 486 { 487 if (FBTrace.DBG_WINDOWS) 488 FBTrace.sysout("context "+context.getName()); 489 490 try 491 { 492 var cw = context.window; 493 if (cw) 494 { 495 if (cw.closed) 496 url = "about:closed"; 497 else 498 if ('location' in cw) 499 var url = cw.location.toString(); 500 else 501 var url = context.getName(); 502 if (url) 503 { 504 if (contextURLSet.indexOf(url) == -1) 505 contextURLSet.push(url); 506 } 507 } 508 } 509 catch(e) 510 { 511 if (FBTrace.DBG_ERRORS) 512 FBTrace.sysout("firebug.getURLsForAllActiveContexts could not get window.location for a context", e); 513 } 514 }); 515 516 if (FBTrace.DBG_ACTIVATION) 517 FBTrace.sysout("active contexts urls "+contextURLSet.length); 518 519 return contextURLSet; 520 }, 521 522 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 523 // Dead Windows XXXjjb this code is not used by 1.4, external placement. 524 525 killWindow: function(browser, chrome) 526 { 527 deadWindows.push({browser: browser, chrome: chrome}); 528 deadWindowTimeout = setTimeout(function() { Firebug.closeDeadWindows(); }, 3000); 529 }, 530 531 rescueWindow: function(browser) 532 { 533 for (var i = 0; i < deadWindows.length; ++i) 534 { 535 if (deadWindows[i].browser == browser) 536 { 537 deadWindows.splice(i, 1); 538 if (FBTrace.DBG_WINDOWS) 539 FBTrace.sysout("rescued "+browser.currentURI.spec); 540 break; 541 } 542 } 543 }, 544 545 closeDeadWindows: function() 546 { 547 for (var i = 0; i < deadWindows.length; ++i) 548 deadWindows[i].chrome.close(); 549 550 deadWindows = []; 551 deadWindowTimeout = 0; 552 }, 553 554 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 555 // Registration 556 557 registerModule: function() 558 { 559 modules.push.apply(modules, arguments); 560 561 if (FBTrace.DBG_INITIALIZE) 562 { 563 for (var i = 0; i < arguments.length; ++i) 564 FBTrace.sysout("registerModule "+arguments[i].dispatchName); 565 } 566 }, 567 568 unregisterModule: function() 569 { 570 for (var i = 0; i < arguments.length; ++i) 571 remove(modules, arguments[i]); 572 }, 573 574 registerActivableModule: function() 575 { 576 activableModules.push.apply(activableModules, arguments); 577 this.registerModule.apply(this, arguments); 578 }, 579 580 registerExtension: function() // TODO remove 581 { 582 extensions.push.apply(extensions, arguments); 583 584 for (var i = 0; i < arguments.length; ++i) 585 TabWatcher.addListener(arguments[i]); 586 587 for (var j = 0; j < arguments.length; j++) 588 Firebug.uiListeners.push(arguments[j]); 589 }, 590 591 unregisterExtension: function() // TODO remove 592 { 593 for (var i = 0; i < arguments.length; ++i) 594 { 595 TabWatcher.removeListener(arguments[i]); 596 remove(Firebug.uiListeners, arguments[i]); 597 remove(extensions, arguments[i]) 598 } 599 }, 600 601 registerUIListener: function() 602 { 603 for (var j = 0; j < arguments.length; j++) 604 Firebug.uiListeners.push(arguments[j]); 605 }, 606 607 unregisterUIListener: function() 608 { 609 for (var i = 0; i < arguments.length; ++i) 610 remove(Firebug.uiListeners, arguments[i]); 611 }, 612 613 registerPanel: function() 614 { 615 panelTypes.push.apply(panelTypes, arguments); 616 617 for (var i = 0; i < arguments.length; ++i) 618 panelTypeMap[arguments[i].prototype.name] = arguments[i]; 619 620 if (FBTrace.DBG_INITIALIZE) 621 for (var i = 0; i < arguments.length; ++i) 622 FBTrace.sysout("registerPanel "+arguments[i].prototype.name+"\n"); 623 }, 624 625 registerRep: function() 626 { 627 reps.push.apply(reps, arguments); 628 }, 629 630 unregisterRep: function() 631 { 632 for (var i = 0; i < arguments.length; ++i) 633 remove(reps, arguments[i]); 634 }, 635 636 setDefaultReps: function(funcRep, rep) 637 { 638 defaultRep = rep; 639 defaultFuncRep = funcRep; 640 }, 641 642 registerEditor: function() 643 { 644 editors.push.apply(editors, arguments); 645 }, 646 647 registerStringBundle: function(bundleURI) 648 { 649 categoryManager.addCategoryEntry("strings_firebug", bundleURI, "", true, true); 650 this.stringBundle = null; 651 }, 652 653 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 654 // Localization 655 656 getStringBundle: function() 657 { 658 if (!this.stringBundle) 659 this.stringBundle = stringBundleService.createExtensibleBundle("strings_firebug"); 660 return this.stringBundle; 661 }, 662 663 getPluralRule: function() 664 { 665 try { 666 return this.getStringBundle().GetStringFromName("pluralRule"); 667 } catch (err) { } 668 }, 669 670 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 671 // Options 672 673 togglePref: function(name) 674 { 675 this.setPref(Firebug.prefDomain, name, !this[name]); 676 }, 677 678 getPref: function(prefDomain, name) 679 { 680 var prefName = prefDomain + "." + name; 681 682 var type = prefs.getPrefType(prefName); 683 if (type == nsIPrefBranch.PREF_STRING) 684 return prefs.getCharPref(prefName); 685 else if (type == nsIPrefBranch.PREF_INT) 686 return prefs.getIntPref(prefName); 687 else if (type == nsIPrefBranch.PREF_BOOL) 688 return prefs.getBoolPref(prefName); 689 }, 690 691 setPref: function(prefDomain, name, value) 692 { 693 var prefName = prefDomain + "." + name; 694 695 var type = prefs.getPrefType(prefName); 696 if (type == nsIPrefBranch.PREF_STRING) 697 prefs.setCharPref(prefName, value); 698 else if (type == nsIPrefBranch.PREF_INT) 699 prefs.setIntPref(prefName, value); 700 else if (type == nsIPrefBranch.PREF_BOOL) 701 prefs.setBoolPref(prefName, value); 702 else if (type == nsIPrefBranch.PREF_INVALID) 703 { 704 FBTrace.sysout("firebug.setPref FAILS: Invalid preference "+prefName+" check that it is listed in defaults/prefs.js"); 705 } 706 707 if (FBTrace.DBG_OPTIONS) 708 FBTrace.sysout("firebug.setPref type="+type+" name="+prefName+" value="+value+"\n"); 709 }, 710 711 clearPref: function(prefDomain, name) 712 { 713 var prefName = prefDomain + "." + name; 714 if (prefs.prefHasUserValue(prefName)) 715 prefs.clearUserPref(prefName); 716 }, 717 718 increaseTextSize: function(amt) 719 { 720 this.setTextSize(this.textSize+amt); 721 }, 722 723 setTextSize: function(value) 724 { 725 this.setPref(Firebug.prefDomain, "textSize", value); 726 }, 727 728 updatePref: function(name, value) 729 { 730 // Prevent infinite recursion due to pref observer 731 if ( optionUpdateMap.hasOwnProperty(name) ) 732 return; 733 734 optionUpdateMap[name] = 1; 735 this[name] = value; 736 737 dispatch(modules, "updateOption", [name, value]); 738 739 // Update the current chrome... 740 Firebug.chrome.updateOption(name, value); 741 742 // ... as well as the original in-browser chrome (if Firebug is currently detached). 743 // xxxHonza, xxxJJB: John, the Firebug.externalChrome is not longer set, is it correct? 744 // it's still used in FirebugChrome.setGlobalAttribute. 745 if (Firebug.chrome != Firebug.originalChrome) 746 Firebug.originalChrome.updateOption(name, value); 747 748 if (name.substr(0, 15) == "externalEditors") 749 this.loadExternalEditors(); 750 751 delete optionUpdateMap[name]; 752 753 if (FBTrace.DBG_OPTIONS) 754 FBTrace.sysout("firebug.updatePref EXIT: "+name+"="+value+"\n"); 755 }, 756 757 // ******************************************************************************************** 758 // External editors 759 // TODO move to editors.js as Firebug.Editors module 760 761 loadExternalEditors: function() 762 { 763 const prefName = "externalEditors"; 764 const editorPrefNames = ["label", "executable", "cmdline", "image"]; 765 766 externalEditors = []; 767 var list = this.getPref(this.prefDomain, prefName).split(","); 768 for (var i = 0; i < list.length; ++i) 769 { 770 var editorId = list[i]; 771 if ( !editorId || editorId == "") 772 continue; 773 var item = { id: editorId }; 774 for( var j = 0; j < editorPrefNames.length; ++j ) 775 { 776 try { 777 item[editorPrefNames[j]] = this.getPref(this.prefDomain, prefName+"."+editorId+"."+editorPrefNames[j]); 778 } 779 catch(exc) 780 { 781 } 782 } 783 if ( item.label && item.executable ) 784 { 785 if (!item.image) 786 item.image = getIconURLForFile(item.executable); 787 externalEditors.push(item); 788 } 789 } 790 return externalEditors; 791 }, 792 793 get registeredEditors() 794 { 795 var newArray = []; 796 if ( editors.length > 0 ) 797 { 798 newArray.push.apply(newArray, editors); 799 if ( externalEditors.length > 0 ) 800 newArray.push("-"); 801 } 802 if ( externalEditors.length > 0 ) 803 newArray.push.apply(newArray, externalEditors); 804 805 return newArray; 806 }, 807 808 openEditors: function() 809 { 810 var args = { 811 FBL: FBL, 812 prefName: this.prefDomain + ".externalEditors" 813 }; 814 openWindow("Firebug:ExternalEditors", "chrome://firebug/content/editors.xul", "", args); 815 }, 816 817 openInEditor: function(context, editorId) 818 { 819 try 820 { 821 if (!editorId) 822 return; 823 824 var location; 825 if (context) 826 { 827 var panel = Firebug.chrome.getSelectedPanel(); 828 if (panel) 829 { 830 location = panel.location; 831 if (!location && panel.name == "html") 832 location = context.window.document.location; 833 if (location && (location instanceof Firebug.SourceFile || location instanceof CSSStyleSheet )) 834 location = location.href; 835 } 836 } 837 if (!location) 838 { 839 if (tabBrowser.currentURI) 840 location = tabBrowser.currentURI.asciiSpec; 841 } 842 if (!location) 843 return; 844 location = location.href || location.toString(); 845 if (Firebug.filterSystemURLs && isSystemURL(location)) 846 return; 847 848 var list = extendArray(editors, externalEditors); 849 var editor = null; 850 for( var i = 0; i < list.length; ++i ) 851 { 852 if (editorId == list[i].id) 853 { 854 editor = list[i]; 855 break; 856 } 857 } 858 if (editor) 859 { 860 if (editor.handler) 861 { 862 editor.handler(location); 863 return; 864 } 865 var args = []; 866 var localFile = null; 867 var targetAdded = false; 868 if (editor.cmdline) 869 { 870 args = editor.cmdline.split(" "); 871 for( var i = 0; i < args.length; ++i ) 872 { 873 if ( args[i] == "%url" ) 874 { 875 args[i] = location; 876 targetAdded = true; 877 } 878 else if ( args[i] == "%file" ) 879 { 880 if (!localFile) 881 localFile = this.getLocalSourceFile(context, location); 882 args[i] = localFile; 883 targetAdded = true; 884 } 885 } 886 } 887 if (!targetAdded) 888 { 889 localFile = this.getLocalSourceFile(context, location); 890 if (!localFile) 891 return; 892 args.push(localFile); 893 } 894 FBL.launchProgram(editor.executable, args); 895 } 896 } catch(exc) { ERROR(exc); } 897 }, 898 899 getLocalSourceFile: function(context, href) 900 { 901 if ( isLocalURL(href) ) 902 return getLocalPath(href); 903 904 var data; 905 if (context) 906 { 907 data = context.sourceCache.loadText(href); 908 } 909 else 910 { 911 // xxxHonza: if the fake context is used the source code is always get using 912 // (a) the browser cache or (b) request to the server. 913 var selectedBrowser = Firebug.chrome.getCurrentBrowser(); 914 var ctx = { 915 browser: selectedBrowser, 916 window: selectedBrowser.contentWindow 917 }; 918 data = new Firebug.SourceCache(ctx).loadText(href); 919 } 920 921 if (!data) 922 return; 923 924 if (!temporaryDirectory) 925 { 926 var tmpDir = DirService.getFile(NS_OS_TEMP_DIR, {}); 927 tmpDir.append("fbtmp"); 928 tmpDir.createUnique(nsIFile.DIRECTORY_TYPE, 0775); 929 temporaryDirectory = tmpDir; 930 } 931 932 var lpath = href.replace(/^[^:]+:\/*/g, "").replace(/\?.*$/g, "").replace(/[^0-9a-zA-Z\/.]/g, "_"); 933 /* dummy comment to workaround eclipse bug */ 934 if ( !/\.[\w]{1,5}$/.test(lpath) ) 935 { 936 if ( lpath.charAt(lpath.length-1) == '/' ) 937 lpath += "index"; 938 lpath += ".html"; 939 } 940 941 if ( getPlatformName() == "WINNT" ) 942 lpath = lpath.replace(/\//g, "\\"); 943 944 var file = QI(temporaryDirectory.clone(), nsILocalFile); 945 file.appendRelativePath(lpath); 946 if (!file.exists()) 947 file.create(nsIFile.NORMAL_FILE_TYPE, 0664); 948 temporaryFiles.push(file.path); 949 950 var converter = CCIN("@mozilla.org/intl/scriptableunicodeconverter", "nsIScriptableUnicodeConverter"); 951 converter.charset = 'UTF-8'; // TODO detect charset from current tab 952 data = converter.ConvertFromUnicode(data); 953 954 var stream = CCIN("@mozilla.org/network/safe-file-output-stream;1", "nsIFileOutputStream"); 955 stream.init(file, 0x04 | 0x08 | 0x20, 0664, 0); // write, create, truncate 956 stream.write(data, data.length); 957 if (stream instanceof nsISafeOutputStream) 958 stream.finish(); 959 else 960 stream.close(); 961 962 return file.path; 963 }, 964 965 deleteTemporaryFiles: function() // TODO call on "shutdown" event to modules 966 { 967 try { 968 var file = CCIN("@mozilla.org/file/local;1", "nsILocalFile"); 969 for( var i = 0; i < temporaryFiles.length; ++i) 970 { 971 file.initWithPath(temporaryFiles[i]); 972 if (file.exists()) 973 file.remove(false); 974 } 975 } 976 catch(exc) 977 { 978 } 979 try { 980 if (temporaryDirectory && temporaryDirectory.exists()) 981 temporaryDirectory.remove(true); 982 } catch(exc) 983 { 984 } 985 }, 986 987 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 988 // Browser Bottom Bar 989 990 showBar: function(show) 991 { 992 var browser = Firebug.chrome.getCurrentBrowser(); 993 if (FBTrace.DBG_WINDOWS || FBTrace.DBG_ACTIVATION) 994 FBTrace.sysout("showBar("+show+") for browser "+browser.currentURI.spec+" FirebugContext "+FirebugContext); 995 996 var contentBox = Firebug.chrome.$("fbContentBox"); 997 var contentSplitter = Firebug.chrome.$("fbContentSplitter"); 998 999 var shouldShow = show/* && !Firebug.isDetached()*/; 1000 contentBox.setAttribute("collapsed", !shouldShow); 1001 1002 if(!show) 1003 Firebug.Inspector.inspectNode(null); 1004 1005 if (contentSplitter) 1006 contentSplitter.setAttribute("collapsed", !shouldShow); 1007 1008 if (toggleCommand) 1009 toggleCommand.setAttribute("checked", !!shouldShow); 1010 1011 if (detachCommand) 1012 detachCommand.setAttribute("checked", Firebug.isDetached()); 1013 1014 this.showKeys(shouldShow); 1015 1016 dispatch(Firebug.uiListeners, show ? "showUI" : "hideUI", [browser, FirebugContext]); 1017 1018 // Sync panel state after the showUI event is dispatched. syncPanel method calls 1019 // Panel.show method, which expects the active context to be already registered. 1020 if (show) 1021 Firebug.chrome.syncPanel(); 1022 }, 1023 1024 showKeys: function(shouldShow) 1025 { 1026 if (!this.fbOnlyKeys) 1027 { 1028 var keyset = document.getElementById("mainKeyset"); 1029 this.fbOnlyKeys = keyset.getElementsByClassName("fbOnlyKey").item(0); 1030 } 1031 var keys = this.fbOnlyKeys; 1032 for (var i = 0; i < keys.length; i++) 1033 keys[i].setAttribute("disabled", !!shouldShow); 1034 }, 1035 1036 closeFirebug: function(userCommand) // this is really deactivate 1037 { 1038 var browser = FirebugChrome.getCurrentBrowser(); 1039 1040 TabWatcher.unwatchBrowser(browser, userCommand); 1041 Firebug.resetTooltip(); 1042 }, 1043 1044 /* 1045 * Primary function to activate or minimize firebug. Used by 1046 * <ol> 1047 * <li>the status bar icon click action</li> 1048 * <li>the activation button (within Firebug.xul) click action</li> 1049 * </ol> 1050 * @param forceOpen: don't minimize, stay open if open. 1051 * @param panelName: eg 'script', to select a specific panel. 1052 */ 1053 toggleBar: function(forceOpen, panelName) 1054 { 1055 var browser = FirebugChrome.getCurrentBrowser(); 1056 1057 if (panelName) 1058 Firebug.chrome.selectPanel(panelName); 1059 1060 if (FirebugContext && browser.showFirebug) // then we are already debugging the selected tab 1061 { 1062 if (Firebug.isDetached()) // if we are out of the browser focus the window 1063 Firebug.chrome.focus(); 1064 else if (Firebug.openInWindow) 1065 this.detachBar(context); 1066 else if (Firebug.isMinimized()) // toggle minimize 1067 Firebug.unMinimize(); 1068 else if (!forceOpen) // else isInBrowser 1069 Firebug.minimizeBar(); 1070 } 1071 else // closed or no context or no showFirebug 1072 { 1073 if (FBTrace.DBG_ERRORS) 1074 { 1075 var context = TabWatcher.getContextByWindow(browser.contentWindow); 1076 if (context) // ASSERT: we should not have showFirebug false on a page with a context 1077 FBTrace.sysout("Firebug.toggleBar: placement "+this.getPlacement()+ " context: "+context.getName()+" FirebugContext: "+(FirebugContext?FirebugContext.getName():"null")+" browser.showFirebug:"+browser.showFirebug); 1078 } 1079 1080 var created = TabWatcher.watchBrowser(browser); // create a context for this page 1081 if (!created) 1082 { 1083 if (FBTrace.DBG_ERRORS) 1084 FBTrace.sysout("Rejected page should explain to user!"); 1085 return false; 1086 } 1087 1088 if (Firebug.isMinimized()) // then toggle minimize 1089 Firebug.unMinimize(); 1090 } 1091 return true; 1092 }, 1093 1094 minimizeBar: function() // just pull down the UI, but don't deactivate the context 1095 { 1096 if (Firebug.isDetached()) // TODO disable minimize on externalMode 1097 { 1098 // TODO reattach 1099 Firebug.toggleDetachBar(false, false); 1100 Firebug.chrome.focus() ; 1101 } 1102 else // inBrowser -> minimized 1103 { 1104 Firebug.setPlacement("minimized"); 1105 this.showBar(false); 1106 } 1107 }, 1108 1109 unMinimize: function() 1110 { 1111 this.updateActiveContexts(FirebugContext); 1112 Firebug.setPlacement("inBrowser"); 1113 Firebug.showBar(true); 1114 }, 1115 1116 toggleDetachBar: function(forceOpen, reopenInBrowser) // detached -> closed; inBrowser -> detached TODO reattach 1117 { 1118 if (!forceOpen && Firebug.isDetached()) // detached -> minimized 1119 { 1120 Firebug.chrome.close(); 1121 detachCommand.setAttribute("checked", false); 1122 if (reopenInBrowser) 1123 { 1124 setTimeout(function delayMinimize() 1125 { 1126 Firebug.unMinimize() 1127 }); 1128 } 1129 } 1130 else 1131 this.detachBar(FirebugContext); 1132 }, 1133 1134 closeDetachedWindow: function(userCommands) 1135 { 1136 Firebug.showBar(false); 1137 1138 if (FirebugContext) 1139 TabWatcher.unwatchBrowser(FirebugContext.browser, userCommands); 1140 // else the user closed Firebug external window while not looking at a debugged web page. 1141 1142 Firebug.resetTooltip(); 1143 }, 1144 1145 setChrome: function(newChrome, newPlacement) 1146 { 1147 var oldChrome = Firebug.chrome; 1148 Firebug.chrome = newChrome; 1149 Firebug.setPlacement(newPlacement); 1150 1151 // reattach all contexts to the new chrome 1152 TabWatcher.iterateContexts(function reattach(context) 1153 { 1154 context.reattach(oldChrome, newChrome); 1155 1156 Firebug.reattachContext(context.browser, context); 1157 }); 1158 }, 1159 1160 detachBar: function(context) 1161 { 1162 if (!context) 1163 { 1164 var browser = Firebug.chrome.getCurrentBrowser(); 1165 var created = TabWatcher.watchBrowser(browser); // create a context for this page 1166 if (!created) 1167 { 1168 if (FBTrace.DBG_ERRORS) 1169 FBTrace.sysout("Firebug.detachBar, no context in "+window.location); 1170 return null; 1171 } 1172 context = TabWatcher.getContextByWindow(browser.contentWindow); 1173 } 1174 1175 if (Firebug.isDetached()) // can be set true attachBrowser 1176 { 1177 Firebug.chrome.focus(); 1178 return null; 1179 } 1180 1181 this.showBar(false); // don't show in browser.xul now 1182 1183 Firebug.chrome.setFirebugContext(context); // make sure the FirebugContext agrees with context 1184 FirebugContext = context; 1185 1186 this.setPlacement("detached"); // we'll reset it in the new window, but we seem to race with code in this window. 1187 1188 if (FBTrace.DBG_ACTIVATION) 1189 FBTrace.sysout("Firebug.detachBar opening firebug.xul for context "+FirebugContext.getName() ); 1190 1191 var args = { 1192 FBL: FBL, 1193 Firebug: this, 1194 browser: context.browser, 1195 FirebugContext: window.FirebugContext 1196 }; 1197 var win = openWindow("Firebug", "chrome://firebug/content/firebug.xul", "", args); 1198 1199 return win; 1200 }, 1201 1202 syncBar: function() // show firebug if we should 1203 { 1204 var browser = FirebugChrome.getCurrentBrowser(); 1205 this.showBar(browser && browser.showFirebug); // implicitly this is operating in the chrome of browser.xul 1206 }, 1207 1208 onClickStatusIcon: function(context, event) 1209 { 1210 if (event.button != 0) 1211 return; 1212 else if (isControl(event)) 1213 this.toggleDetachBar(true); 1214 else if (context && context.errorCount) 1215 Firebug.toggleBar(undefined, 'console'); 1216 else 1217 this.toggleBar(); 1218 }, 1219 1220 onClickStatusText: function(context, event) 1221 { 1222 if (event.button != 0) 1223 return; 1224 1225 if (!context || !context.errorCount) 1226 return; 1227 1228 var panel = Firebug.chrome.getSelectedPanel(); 1229 if (panel && panel.name != "console") 1230 { 1231 Firebug.chrome.selectPanel("console"); 1232 cancelEvent(event); 1233 } 1234 }, 1235 1236 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1237 1238 resetAllOptions: function(confirm) // to default state 1239 { 1240 if (confirm) 1241 { 1242 if (!promptService.confirm(null, $STR("Firebug"), $STR("confirmation.Reset_All_Firebug_Options"))) 1243 return; 1244 } 1245 1246 var preferences = prefs.getChildList("extensions.firebug", {}); 1247 for (var i = 0; i < preferences.length; i++) 1248 { 1249 if (preferences[i].indexOf("DBG_") == -1 && preferences[i].indexOf("filterSystemURLs") == -1) 1250 { 1251 if (FBTrace.DBG_OPTIONS) 1252 FBTrace.sysout("Clearing option: "+i+") "+preferences[i]); 1253 if (prefs.prefHasUserValue(preferences[i])) // avoid exception 1254 prefs.clearUserPref(preferences[i]); 1255 } 1256 else 1257 { 1258 if (FBTrace.DBG_OPTIONS) 1259 FBTrace.sysout("Skipped clearing option: "+i+") "+preferences[i]); 1260 } 1261 } 1262 1263 TabWatcher.iterateContexts( function clearBPs(context) 1264 { 1265 Firebug.Debugger.clearAllBreakpoints(context); 1266 }); 1267 }, 1268 1269 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1270 // Panels 1271 1272 getPanelType: function(panelName) 1273 { 1274 if (panelTypeMap.hasOwnProperty(panelName)) 1275 return panelTypeMap[panelName]; 1276 else 1277 return null; 1278 }, 1279 1280 getPanelTitle: function(panelType) 1281 { 1282 return panelType.prototype.title ? panelType.prototype.title 1283 : FBL.$STR("Panel-"+panelType.prototype.name); 1284 }, 1285 1286 getMainPanelTypes: function(context) 1287 { 1288 var resultTypes = []; 1289 1290 for (var i = 0; i < panelTypes.length; ++i) 1291 { 1292 var panelType = panelTypes[i]; 1293 if (!panelType.prototype.parentPanel) 1294 resultTypes.push(panelType); 1295 } 1296 1297 if (context.panelTypes) 1298 { 1299 for (var i = 0; i < context.panelTypes.length; ++i) 1300 { 1301 var panelType = context.panelTypes[i]; 1302 if (!panelType.prototype.parentPanel) 1303 resultTypes.push(panelType); 1304 } 1305 } 1306 1307 return resultTypes; 1308 }, 1309 1310 getSidePanelTypes: function(context, mainPanel) 1311 { 1312 if (!mainPanel) 1313 return []; 1314 1315 var resultTypes = []; 1316 1317 for (var i = 0; i < panelTypes.length; ++i) 1318 { 1319 var panelType = panelTypes[i]; 1320 if (panelType.prototype.parentPanel && (panelType.prototype.parentPanel == mainPanel.name) ) 1321 resultTypes.push(panelType); 1322 } 1323 1324 if (context.panelTypes) 1325 { 1326 for (var i = 0; i < context.panelTypes.length; ++i) 1327 { 1328 var panelType = context.panelTypes[i]; 1329 if (panelType.prototype.parentPanel == mainPanel.name) 1330 resultTypes.push(panelType); 1331 } 1332 } 1333 1334 resultTypes.sort(function(a, b) 1335 { 1336 return a.prototype.order < b.prototype.order ? -1 : 1; 1337 }); 1338 1339 return resultTypes; 1340 }, 1341 1342 /** 1343 * Gets an object containing the state of the panel from the last time 1344 * it was displayed before one or more page reloads. 1345 * The 'null' return here is a too-subtle signal to the panel code in bindings.xml. 1346 * Note that panel.context may not have a persistedState, but in addition the persisted state for panel.name may be null. 1347 */ 1348 getPanelState: function(panel) 1349 { 1350 var persistedState = panel.context.persistedState; 1351 if (!persistedState || !persistedState.panelState) 1352 return null; 1353 1354 return persistedState.panelState[panel.name]; 1355 }, 1356 1357 showPanel: function(browser, panel) 1358 { 1359 dispatch(modules, "showPanel", [browser, panel]); 1360 }, 1361 1362 showSidePanel: function(browser, sidePanel) 1363 { 1364 dispatch(modules, "showSidePanel", [browser, sidePanel]); 1365 }, 1366 1367 reattachContext: function(browser, context) 1368 { 1369 dispatch(modules, "reattachContext", [browser, context]); 1370 }, 1371 1372 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1373 // URL mapping 1374 1375 getObjectByURL: function(context, url) 1376 { 1377 for (var i = 0; i < modules.length; ++i) 1378 { 1379 var object = modules[i].getObjectByURL(context, url); 1380 if (object) 1381 return object; 1382 } 1383 }, 1384 1385 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1386 // Reps 1387 1388 getRep: function(object) 1389 { 1390 var type = typeof(object); 1391 if (type == 'object' && object instanceof String) 1392 type = 'string'; 1393 1394 for (var i = 0; i < reps.length; ++i) 1395 { 1396 var rep = reps[i]; 1397 try 1398 { 1399 if (rep.supportsObject(object, type)) 1400 { 1401 if (FBTrace.DBG_DOM) 1402 FBTrace.sysout("getRep type: "+type+" object: "+object, rep); 1403 return rep; 1404 } 1405 } 1406 catch (exc) 1407 { 1408 if (FBTrace.DBG_ERRORS) 1409 { 1410 FBTrace.sysout("firebug.getRep FAILS: "+ exc, exc); 1411 FBTrace.sysout("firebug.getRep reps["+i+"/"+reps.length+"]: "+(typeof(reps[i])), reps[i]); 1412 } 1413 } 1414 } 1415 1416 if (FBTrace.DBG_DOM) 1417 FBTrace.sysout("getRep default type: "+type+" object: "+object, rep); 1418 1419 return (type == 'function')?defaultFuncRep:defaultRep; 1420 }, 1421 1422 getRepObject: function(node) 1423 { 1424 var target = null; 1425 for (var child = node; child; child = child.parentNode) 1426 { 1427 if (hasClass(child, "repTarget")) 1428 target = child; 1429 1430 if (child.repObject) 1431 { 1432 if (!target && hasClass(child, "repIgnore")) 1433 break; 1434 else 1435 return child.repObject; 1436 } 1437 } 1438 }, 1439 1440 getRepNode: function(node) 1441 { 1442 for (var child = node; child; child = child.parentNode) 1443 { 1444 if (child.repObject) 1445 return child; 1446 } 1447 }, 1448 1449 getElementByRepObject: function(element, object) 1450 { 1451 for (var child = element.firstChild; child; child = child.nextSibling) 1452 { 1453 if (child.repObject == object) 1454 return child; 1455 } 1456 }, 1457 1458 /** 1459 * Takes an element from a panel document and finds the owning panel. 1460 */ 1461 getElementPanel: function(element) 1462 { 1463 for (; element; element = element.parentNode) 1464 { 1465 if (element.ownerPanel) 1466 return element.ownerPanel; 1467 } 1468 }, 1469 1470 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1471 1472 visitWebsite: function(which) 1473 { 1474 openNewTab(firebugURLs[which]); 1475 }, 1476 1477 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1478 // nsISupports 1479 1480 QueryInterface : function(iid) 1481 { 1482 if (iid.equals(nsISupports)) 1483 { 1484 return this; 1485 } 1486 1487 throw Components.results.NS_NOINTERFACE; 1488 }, 1489 1490 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1491 // nsIPrefObserver 1492 1493 observe: function(subject, topic, data) 1494 { 1495 if (data.indexOf("extensions.") == -1) 1496 return; 1497 1498 if (data.substring(0, Firebug.prefDomain.length) == Firebug.prefDomain) 1499 var domain = Firebug.prefDomain; 1500 if (data.substring(0, Firebug.servicePrefDomain.length) == Firebug.servicePrefDomain) 1501 var domain = Firebug.servicePrefDomain; 1502 1503 if (domain) 1504 { 1505 var name = data.substr(domain.length+1); 1506 var value = this.getPref(domain, name); 1507 if (FBTrace.DBG_OPTIONS) FBTrace.sysout("firebug.observe name = value: "+name+"= "+value+"\n"); 1508 this.updatePref(name, value); 1509 } 1510 1511 if (topic == "nsPref:changed") 1512 { 1513 if (data.indexOf(".enableSites") != -1) 1514 { 1515 if (FBTrace.DBG_PANELS) 1516 FBTrace.sysout("Firebug.observe subject: "+subject+" topic "+topic+" data: "+data+"\n"); 1517 dispatch(modules, "onEnablePrefChange", [data]); 1518 } 1519 } 1520 }, 1521 1522 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1523 // nsIFireBugClient These are per Firefox XUL window callbacks 1524 1525 enableXULWindow: function() // Called when the first context is created. 1526 { 1527 if (window.closed) 1528 throw new Error("enableXULWindow window is closed!!"); 1529 1530 if (FBTrace.DBG_ACTIVATION) 1531 FBTrace.sysout("enable XUL Window +++++++++++++++++++++++++++++++++++++++", Firebug.detachArgs); 1532 1533 dispatch(modules, "enable", [FirebugChrome]); // allows errors to flow thru fbs and callbacks to supportWindow to begin 1534 }, 1535 1536 disableXULWindow: function() 1537 { 1538 dispatch(modules, "disable", [FirebugChrome]); 1539 if (FBTrace.DBG_ACTIVATION) 1540 FBTrace.sysout("disable XUL Window --------------------------------------"); 1541 }, 1542 1543 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1544 // These are XUL window level call backs and should be moved into Firebug where is says nsIFirebugClient 1545 // xxxHonza: so I did 1546 1547 onPauseJSDRequested: function(rejection) 1548 { 1549 if (top.FirebugContext) // then we are active in this browser.xul 1550 rejection.push(true); // so reject the request 1551 1552 dispatch2(Firebug.Debugger.fbListeners, "onPauseJSDRequested", [rejection]); 1553 }, 1554 1555 onJSDActivate: function(active, why) // just before hooks are set 1556 { 1557 this.setIsJSDActive(active); 1558 1559 if (FBTrace.DBG_ACTIVATION) 1560 FBTrace.sysout("debugger.onJSDActivate "+why+" active:"+active+"\n"); 1561 1562 dispatch2(Firebug.Debugger.fbListeners, "onJSDActivate", [active, why]); 1563 }, 1564 1565 onJSDDeactivate: function(active, why) 1566 { 1567 this.setIsJSDActive(active); 1568 1569 if (FBTrace.DBG_ACTIVATION) 1570 FBTrace.sysout("debugger.onJSDDeactivate "+why+" active:"+active+"\n"); 1571 1572 dispatch2(Firebug.Debugger.fbListeners, "onJSDDeactivate", [active, why]); 1573 }, 1574 1575 setIsJSDActive: function(active) // should only be call on the jsd activation events, so it correctly reflects jsd state 1576 { 1577 if (active) 1578 $('fbStatusIcon').setAttribute("script", "on"); 1579 else 1580 $('fbStatusIcon').setAttribute("script", "off"); 1581 1582 if (FBTrace.DBG_ACTIVATION) 1583 FBTrace.sysout("debugger.setIsJSDActive "+active+"\n"); 1584 1585 }, 1586 1587 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1588 // Placement 1589 1590 isDetached: function() 1591 { 1592 return Firebug.placement == PLACEMENT_DETACHED; 1593 }, 1594 1595 isMinimized: function() 1596 { 1597 return Firebug.placement == PLACEMENT_MINIMIZED; 1598 }, 1599 1600 isInBrowser: function() 1601 { 1602 return Firebug.placement == PLACEMENT_INBROWSER; 1603 }, 1604 1605 placements: ["none", "inBrowser", "detached", "minimized"], 1606 1607 placement: 1, 1608 1609 setPlacement: function(toPlacement) 1610 { 1611 // TODO : This should probably be an event so others can link into this 1612 Firebug.chrome.$("fbSearchBox").hideOptions(); 1613 1614 if (FBTrace.DBG_ACTIVATION) 1615 FBTrace.sysout("Firebug.setPlacement from "+Firebug.getPlacement()+" to "+toPlacement+" with chrome "+Firebug.chrome.window.location); 1616 1617 for (var i = 0; i < Firebug.placements.length; i++) 1618 { 1619 if (toPlacement == Firebug.placements[i]) 1620 { 1621 if (Firebug.placement != i) // then we are changing the value 1622 { 1623 Firebug.placement = i; 1624 delete Firebug.previousPlacement; 1625 Firebug.setPref(Firebug.prefDomain, "previousPlacement", Firebug.placement); 1626 Firebug.resetTooltip(); 1627 } 1628 return Firebug.placement; 1629 } 1630 } 1631 throw new Error("Firebug.setPlacement cannot match "+toPlacement+" as a placement"); 1632 }, 1633 1634 getPlacement: function() 1635 { 1636 return Firebug.placements[Firebug.placement]; 1637 }, 1638 1639 openMinimized: function() 1640 { 1641 if (!Firebug.previousPlacement) 1642 Firebug.previousPlacement = Firebug.getPref(Firebug.prefDomain, "previousPlacement"); 1643 1644 return (Firebug.previousPlacement && (Firebug.previousPlacement == PLACEMENT_MINIMIZED) ) 1645 }, 1646 1647 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1648 // TabWatcher Listener 1649 1650 getContextType: function() 1651 { 1652 return Firebug.TabContext; 1653 }, 1654 1655 shouldShowContext: function(context) 1656 { 1657 return dispatch2(modules, "shouldShowContext", [context]); 1658 }, 1659 1660 shouldCreateContext: function(browser, url, userCommands) 1661 { 1662 return dispatch2(modules, "shouldCreateContext", [browser, url, userCommands]); 1663 }, 1664 1665 shouldNotCreateContext: function(browser, url, userCommands) 1666 { 1667 return dispatch2(modules, "shouldNotCreateContext", [browser, url, userCommands]); 1668 }, 1669 1670 initContext: function(context, persistedState) // called after a context is created. 1671 { 1672 context.panelName = context.browser.panelName; 1673 if (context.browser.sidePanelNames) 1674 context.sidePanelNames = context.browser.sidePanelNames; 1675 1676 1677 if (FBTrace.DBG_ERRORS && !context.sidePanelNames) 1678 FBTrace.sysout("firebug.initContext sidePanelNames:",context.sidePanelNames); 1679 1680 dispatch(modules, "initContext", [context, persistedState]); 1681 1682 this.updateActiveContexts(context); // a newly created context is active 1683 1684 Firebug.chrome.setFirebugContext(context); // a newly created context becomes the default for the view 1685 FirebugContext = context; 1686 1687 if (deadWindowTimeout) 1688 this.rescueWindow(context.browser); // if there is already a window, clear showDetached. 1689 }, 1690 1691 updateActiveContexts: function(context) // this should be the only method to call suspend and resume. 1692 { 1693 if (context) // either a new context or revisiting an old one 1694 { 1695 if(!this.hadFirstContext) // then we need to enable the panels iff the prefs say so 1696 { 1697 this.hadFirstContext = true; 1698 Firebug.ModuleManager.obeyPrefs(context); 1699 } 1700 if (Firebug.getSuspended()) 1701 Firebug.resume(); // This will cause onResumeFirebug for every context including this one. 1702 } 1703 else // this browser has no context 1704 { 1705 Firebug.suspend(); 1706 } 1707 1708 Firebug.resetTooltip(); 1709 }, 1710 1711 showContext: function(browser, context) // TabWatcher showContext. null context means we don't debug that browser 1712 { 1713 if (clearContextTimeout) 1714 { 1715 clearTimeout(clearContextTimeout); 1716 clearContextTimeout = 0; 1717 } 1718 1719 FirebugContext = context; 1720 Firebug.chrome.setFirebugContext(context); // the context becomes the default for its view 1721 this.updateActiveContexts(context); // resume, after setting FirebugContext 1722 1723 dispatch(modules, "showContext", [browser, context]); // tell modules we may show UI 1724 1725 // user wants detached but we are not yet 1726 if (Firebug.openInWindow && !Firebug.isDetached()) 1727 { 1728 if (context && !Firebug.isMinimized()) // don't detach if it's minimized 2067 1729 this.detachBar(context); // the placement will be set once the external window opens 1730 else // just make sure we are not showing 1731 this.showBar(false); 1732 1733 return; 1734 } 1735 1736 // previous browser.xul had placement minimized 1737 if (Firebug.openMinimized() && !Firebug.isMinimized()) 1738 { 1739 this.minimizeBar(); 1740 return; 1741 } 1742 1743 if (Firebug.isMinimized()) 1744 this.showBar(false); // don't show, we are minimized 1745 else if (Firebug.isDetached()) 1746 this.syncResumeBox(context); 1747 else // inBrowser 1748 this.showBar(context?true:false); 1749 1750 }, 1751 1752 syncResumeBox: function(context) 1753 { 1754 var contentBox = Firebug.chrome.$('fbContentBox'); 1755 var resumeBox = Firebug.chrome.$('fbResumeBox'); 1756 1757 if (!resumeBox) // the showContext is being called before the reattachContext, we'll get a second showContext 1758 return; 1759 1760 if (context) 1761 { 1762 collapse(contentBox, false); 1763 Firebug.chrome.syncPanel(); 1764 collapse(resumeBox, true); 1765 } 1766 else 1767 { 1768 collapse(contentBox, true); 1769 collapse(resumeBox, false); 1770 Firebug.chrome.window.document.title = $STR("Firebug - inactive for selected Firefox tab"); 1771 } 1772 }, 1773 1774 unwatchBrowser: function(browser) // the context for this browser has been destroyed and removed 1775 { 1776 Firebug.updateActiveContexts(null); 1777 }, 1778 1779 // Either a top level or a frame, (interior window) for an exist context is seen by the tabWatcher. 1780 watchWindow: function(context, win) 1781 { 1782 for (var panelName in context.panelMap) 1783 { 1784 var panel = context.panelMap[panelName]; 1785 panel.watchWindow(win); 1786 } 1787 1788 dispatch(modules, "watchWindow", [context, win]); 1789 }, 1790 1791 unwatchWindow: function(context, win) 1792 { 1793 for (var panelName in context.panelMap) 1794 { 1795 var panel = context.panelMap[panelName]; 1796 panel.unwatchWindow(win); 1797 } 1798 dispatch(modules, "unwatchWindow", [context, win]); 1799 }, 1800 1801 loadedContext: function(context) 1802 { 1803 if (!context.browser.currentURI) 1804 FBTrace.sysout("firebug.loadedContext problem browser ", context.browser); 1805 1806 dispatch(modules, "loadedContext", [context]); 1807 }, 1808 1809 destroyContext: function(context, persistedState, browser) 1810 { 1811 if (!context) // then we are called just to clean up 1812 return; 1813 1814 dispatch(modules, "destroyContext", [context, persistedState]); 1815 1816 if (FirebugContext == context) 1817 Firebug.chrome.setFirebugContext(null); // FirebugContext is about to be destroyed 1818 1819 var browser = context.browser; 1820 // Persist remnants of the context for restoration if the user reloads 1821 browser.panelName = context.panelName; 1822 browser.sidePanelNames = context.sidePanelNames; 1823 1824 // next the context is deleted and removed from the TabWatcher, we clean up in unWatchBrowser 1825 }, 1826 1827 onSourceFileCreated: function(context, sourceFile) 1828 { 1829 dispatch(modules, "onSourceFileCreated", [context, sourceFile]); 1830 }, 1831 1832 //********************************************************************************************* 1833 1834 getTabForWindow: function(aWindow) 1835 { 1836 aWindow = getRootWindow(aWindow); 1837 1838 if (!aWindow || !this.tabBrowser.getBrowserIndexForDocument) 1839 return null; 1840 1841 try { 1842 var targetDoc = aWindow.document; 1843 1844 var tab = null; 1845 var targetBrowserIndex = this.tabBrowser.getBrowserIndexForDocument(targetDoc); 1846 1847 if (targetBrowserIndex != -1) 1848 { 1849 tab = this.tabBrowser.tabContainer.childNodes[targetBrowserIndex]; 1850 return tab; 1851 } 1852 } catch (ex) {} 1853 1854 return null; 1855 }, 1856 1857 getTabIdForWindow: function(win) 1858 { 1859 var tab = this.getTabForWindow(win); 1860 return tab ? tab.linkedPanel : null; 1861 }, 1862 }; 1863 1864 // ************************************************************************************************ 1865 1866 /** 1867 * Support for listeners registration. This object also extended by Firebug.Module so, 1868 * all modules supports listening automatically. Notice that array of listeners 1869 * is created for each intance of a module within initialize method. Thus all derived 1870 * module classes must ensure that Firebug.Module.initialize method is called for the 1871 * super class. 1872 */ 1873 Firebug.Listener = function() 1874 { 1875 // The array is created when the first listeners is added. 1876 // It can't be created here since derived objects would share 1877 // the same array. 1878 this.fbListeners = null; 1879 } 1880 Firebug.Listener.prototype = 1881 { 1882 addListener: function(listener) 1883 { 1884 if (!this.fbListeners) 1885 this.fbListeners = []; // delay the creation until the objects are created so 'this' causes new array for each module 1886 1887 this.fbListeners.push(listener); 1888 }, 1889 1890 removeListener: function(listener) 1891 { 1892 remove(this.fbListeners, listener); // if this.fbListeners is null, remove is being called with no add 1893 } 1894 }; 1895 1896 // ************************************************************************************************ 1897 1898 /** 1899 * @module Base class for all modules. Every derived module object must be registered using 1900 * <code>Firebug.registerModule</code> method. There is always one instance of a module object 1901 * per browser window. 1902 */ 1903 Firebug.Module = extend(new Firebug.Listener(), 1904 /** @lends Firebug.Module */ 1905 { 1906 /** 1907 * Called by Firebug when Firefox window is opened. 1908 */ 1909 initialize: function() 1910 { 1911 1912 }, 1913 1914 /** 1915 * Called when the UI is ready for context creation. 1916 * Used by chromebug; normally FrameProgressListener events trigger UI synchronization, 1917 * this event allows sync without progress events. 1918 */ 1919 initializeUI: function(detachArgs) 1920 { 1921 }, 1922 1923 /** 1924 * Called by Firebug when Firefox window is closed. 1925 */ 1926 shutdown: function() 1927 { 1928 1929 }, 1930 1931 /** 1932 * Called when a new context is created but before the page is loaded. 1933 */ 1934 initContext: function(context, persistedState) 1935 { 1936 }, 1937 1938 /** 1939 * Called after a context is detached to a separate window; 1940 */ 1941 reattachContext: function(browser, context) 1942 { 1943 }, 1944 1945 /** 1946 * Called when a context is destroyed. Module may store info on persistedState for reloaded pages. 1947 */ 1948 destroyContext: function(context, persistedState) 1949 { 1950 }, 1951 1952 /** 1953 * Called when attaching to a window (top-level or frame). 1954 */ 1955 watchWindow: function(context, win) 1956 { 1957 }, 1958 1959 /** 1960 * Called when unwatching a window (top-level or frame). 1961 */ 1962 unwatchWindow: function(context, win) 1963 { 1964 }, 1965 1966 // Called when a FF tab is create or activated (user changes FF tab) 1967 // Called after context is created or with context == null (to abort?) 1968 showContext: function(browser, context) 1969 { 1970 }, 1971 1972 /** 1973 * Called after a context's page gets DOMContentLoaded 1974 */ 1975 loadedContext: function(context) 1976 { 1977 }, 1978 1979 /* 1980 * After "onSelectingPanel", a panel has been selected but is not yet visible 1981 */ 1982 showPanel: function(browser, panel) 1983 { 1984 }, 1985 1986 showSidePanel: function(browser, sidePanel) 1987 { 1988 }, 1989 1990 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1991 1992 updateOption: function(name, value) 1993 { 1994 }, 1995 1996 getObjectByURL: function(context, url) 1997 { 1998 }, 1999 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2000 // intermodule dependency 2001 2002 // caller needs module. win maybe context.window or iframe in context.window. 2003 // true means module is ready now, else getting ready 2004 isReadyElsePreparing: function(context, win) 2005 { 2006 }, 2007 }); 2008 2009 //************************************************************************************************ 2010 2011 Firebug.Extension = 2012 { 2013 acceptContext: function(win,uri) 2014 { 2015 return false; 2016 }, 2017 2018 declineContext: function(win,uri) 2019 { 2020 return false; 2021 } 2022 }; 2023 2024 // ************************************************************************************************ 2025 2026 /** 2027 * @panel Base class for all panels. Every derived panel must define a constructor and 2028 * register with <code>Firebug.registerPanel</code> method. An instance of the panel 2029 * object is created by the framework for each browser tab where Firebug is activated. 2030 */ 2031 Firebug.Panel = 2032 /** @lends Firebug.Panel */ 2033 { 2034 searchable: false, 2035 editable: true, 2036 breakable: false, 2037 order: 2147483647, 2038 statusSeparator: "<", 2039 2040 initialize: function(context, doc) 2041 { 2042 if (!context.browser) 2043 { 2044 if (FBTrace.DBG_ERRORS) 2045 FBTrace.sysout("attempt to create panel with dud context!"); 2046 return false; 2047 } 2048 2049 this.context = context; 2050 this.document = doc; 2051 2052 this.panelNode = doc.createElement("div"); 2053 this.panelNode.ownerPanel = this; 2054 2055 setClass(this.panelNode, "panelNode panelNode-"+this.name+" contextUID="+context.uid); 2056 2057 // Load persistent content if any. 2058 var persistedState = Firebug.getPanelState(this); 2059 if (persistedState) 2060 { 2061 this.persistContent = persistedState.persistContent; 2062 if (this.persistContent && persistedState.panelNode) 2063 this.loadPersistedContent(persistedState); 2064 } 2065 2066 doc.body.appendChild(this.panelNode); 2067 2068 // Update panel's tab in case the break-on-next (BON) is active. 2069 var shouldBreak = this.shouldBreakOnNext(); 2070 Firebug.Breakpoint.updatePanelTab(this, shouldBreak); 2071 2072 if (FBTrace.DBG_INITIALIZE) 2073 FBTrace.sysout("firebug.initialize panelNode for "+this.name+"\n"); 2074 2075 this.initializeNode(this.panelNode); 2076 }, 2077 2078 destroy: function(state) // Panel may store info on state 2079 { 2080 if (FBTrace.DBG_INITIALIZE) 2081 FBTrace.sysout("firebug.destroy panelNode for "+this.name+"\n"); 2082 2083 if (this.panelNode) 2084 { 2085 if (this.persistContent) 2086 this.savePersistedContent(state); 2087 else 2088 delete state.persistContent; 2089 2090 delete this.panelNode.ownerPanel; 2091 } 2092 2093 this.destroyNode(); 2094 2095 clearDomplate(this.panelNode); 2096 }, 2097 2098 savePersistedContent: function(state) 2099 { 2100 state.panelNode = this.panelNode; 2101 state.persistContent = this.persistContent; 2102 }, 2103 2104 loadPersistedContent: function(persistedState) 2105 { 2106 // move the nodes from the persistedState to the panel 2107 while (persistedState.panelNode.firstChild) 2108 this.panelNode.appendChild(persistedState.panelNode.firstChild); 2109 2110 scrollToBottom(this.panelNode); 2111 }, 2112 2113 // called when a panel in one XUL window is about to appear in another one. 2114 detach: function(oldChrome, newChrome) 2115 { 2116 }, 2117 2118 reattach: function(doc) // this is how a panel in one window reappears in another window; lazy called 2119 { 2120 this.document = doc; 2121 2122 if (this.panelNode) 2123 { 2124 this.panelNode = doc.adoptNode(this.panelNode, true); 2125 this.panelNode.ownerPanel = this; 2126 doc.body.appendChild(this.panelNode); 2127 } 2128 }, 2129 2130 // Called at the end of module.initialize; addEventListener-s here 2131 initializeNode: function(myPanelNode) 2132 { 2133 }, 2134 2135 // removeEventListener-s here. 2136 destroyNode: function() 2137 { 2138 }, 2139 2140 show: function(state) // persistedPanelState plus non-persisted hide() values 2141 { 2142 }, 2143 2144 hide: function(state) // store info on state for next show. 2145 { 2146 }, 2147 2148 watchWindow: function(win) 2149 { 2150 }, 2151 2152 unwatchWindow: function(win) 2153 { 2154 }, 2155 2156 updateOption: function(name, value) 2157 { 2158 }, 2159 2160 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2161 2162 /** 2163 * Toolbar helpers 2164 */ 2165 showToolbarButtons: function(buttonsId, show) 2166 { 2167 try 2168 { 2169 var buttons = Firebug.chrome.$(buttonsId); 2170 collapse(buttons, !show); 2171 } 2172 catch (exc) 2173 { 2174 if (FBTrace.DBG_ERRORS) 2175 FBTrace.sysout("firebug.Panel showToolbarButtons FAILS "+exc, exc); 2176 } 2177 }, 2178 2179 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2180 2181 /** 2182 * Returns a number indicating the view's ability to inspect the object. 2183 * 2184 * Zero means not supported, and higher numbers indicate specificity. 2185 */ 2186 supportsObject: function(object) 2187 { 2188 return 0; 2189 }, 2190 2191 hasObject: function(object) // beyond type testing, is this object selectable? 2192 { 2193 return false; 2194 }, 2195 2196 navigate: function(object) 2197 { 2198 if (FBTrace.DBG_PANELS) 2199 FBTrace.sysout("navigate "+this.name+" to "+object+" when this.location="+this.location+"\n"); 2200 if (!object) 2201 object = this.getDefaultLocation(this.context); 2202 if (!object) 2203 object = null; // not undefined. 2204 2205 if ( !this.location || (object != this.location) ) // if this.location undefined, may set to null 2206 { 2207 if (FBTrace.DBG_PANELS) 2208 FBTrace.sysout("navigate "+this.name+" to location "+object+"\n"); 2209 2210 this.location = object; 2211 this.updateLocation(object); 2212 2213 dispatch(Firebug.uiListeners, "onPanelNavigate", [object, this]); 2214 } 2215 }, 2216 2217 updateLocation: function(object) // if the module can return null from getDefaultLocation, then it must handle it here. 2218 { 2219 }, 2220 2221 /** 2222 * Navigates to the next document whose match parameter returns true. 2223 */ 2224 navigateToNextDocument: function(match, reverse) 2225 { 2226 // This is an approximation of the UI that is displayed by the location 2227 // selector. This should be close enough, although it may be better 2228 // to simply generate the sorted list within the module, rather than 2229 // sorting within the UI. 2230 var self = this; 2231 function compare(a, b) { 2232 var locA = self.getObjectDescription(a); 2233 var locB = self.getObjectDescription(b); 2234 if(locA.path > locB.path) 2235 return 1; 2236 if(locA.path < locB.path) 2237 return -1; 2238 if(locA.name > locB.name) 2239 return 1; 2240 if(locA.name < locB.name) 2241 return -1; 2242 return 0; 2243 } 2244 var allLocs = this.getLocationList().sort(compare); 2245 for (var curPos = 0; curPos < allLocs.length && allLocs[curPos] != this.location; curPos++); 2246 2247 function transformIndex(index) { 2248 if (reverse) { 2249 // For the reverse case we need to implement wrap around. 2250 var intermediate = curPos - index - 1; 2251 return (intermediate < 0 ? allLocs.length : 0) + intermediate; 2252 } else { 2253 return (curPos + index + 1) % allLocs.length; 2254 } 2255 }; 2256 2257 for (var next = 0; next < allLocs.length - 1; next++) 2258 { 2259 var object = allLocs[transformIndex(next)]; 2260 2261 if (match(object)) 2262 { 2263 this.navigate(object); 2264 return object; 2265 } 2266 } 2267 }, 2268 2269 select: function(object, forceUpdate) 2270 { 2271 if (!object) 2272 object = this.getDefaultSelection(this.context); 2273 2274 if(FBTrace.DBG_PANELS) 2275 FBTrace.sysout("firebug.select "+this.name+" forceUpdate: "+forceUpdate+" "+object+((object==this.selection)?"==":"!=")+this.selection); 2276 2277 if (forceUpdate || object != this.selection) 2278 { 2279 this.selection = object; 2280 this.updateSelection(object); 2281 2282 dispatch(Firebug.uiListeners, "onObjectSelected", [object, this]); 2283 } 2284 }, 2285 2286 2287 updateSelection: function(object) 2288 { 2289 }, 2290 2291 refresh: function() 2292 { 2293 2294 }, 2295 2296 markChange: function(skipSelf) 2297 { 2298 if (this.dependents) 2299 { 2300 if (skipSelf) 2301 { 2302 for (var i = 0; i < this.dependents.length; ++i) 2303 { 2304 var panelName = this.dependents[i]; 2305 if (panelName != this.name) 2306 this.context.invalidatePanels(panelName); 2307 } 2308 } 2309 else 2310 this.context.invalidatePanels.apply(this.context, this.dependents); 2311 } 2312 }, 2313 2314 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2315 2316 startInspecting: function() 2317 { 2318 }, 2319 2320 stopInspecting: function(object, cancelled) 2321 { 2322 }, 2323 2324 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2325 2326 search: function(text, reverse) 2327 { 2328 }, 2329 2330 /** 2331 * Retrieves the search options that this modules supports. 2332 * This is used by the search UI to present the proper options. 2333 */ 2334 getSearchOptionsMenuItems: function() 2335 { 2336 return [ 2337 Firebug.Search.searchOptionMenu("search.Case_Sensitive", "searchCaseSensitive") 2338 ]; 2339 }, 2340 2341 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2342 2343 // Called when "Options" clicked. Return array of 2344 // {label: 'name', nol10n: true, type: "checkbox", checked: <value>, command:function to set <value>} 2345 getOptionsMenuItems: function() 2346 { 2347 return null; 2348 }, 2349 2350 /* 2351 * Called by chrome.onContextMenu to build the context menu when this panel has focus. 2352 * See also FirebugRep for a similar function also called by onContextMenu 2353 * Extensions may monkey patch and chain off this call 2354 * @param object: the 'realObject', a model value, eg a DOM property 2355 * @param target: the HTML element clicked on. 2356 * @return an array of menu items. 2357 */ 2358 getContextMenuItems: function(object, target) 2359 { 2360 return []; 2361 }, 2362 2363 getBreakOnMenuItems: function() 2364 { 2365 return []; 2366 }, 2367 2368 getEditor: function(target, value) 2369 {