1 /* See license.txt for terms of usage */ 2 3 /** 4 * The 'context' in this file is always 'Firebug.currentContext' 5 */ 6 define([ 7 "firebug/lib/object", 8 "firebug/chrome/firefox", 9 "firebug/lib/dom", 10 "firebug/lib/css", 11 "firebug/lib/system", 12 "firebug/chrome/menu", 13 "firebug/chrome/toolbar", 14 "firebug/lib/url", 15 "firebug/lib/locale", 16 "firebug/lib/string", 17 "firebug/lib/events", 18 "firebug/js/fbs", 19 "firebug/chrome/window", 20 "firebug/lib/options" 21 ], 22 function chromeFactory(Obj, Firefox, Dom, Css, System, Menu, Toolbar, Url, Locale, String, 23 Events, FBS, Win, Options) { 24 25 // ********************************************************************************************* // 26 // Constants 27 28 const Cc = Components.classes; 29 const Ci = Components.interfaces; 30 const nsIWebNavigation = Ci.nsIWebNavigation; 31 32 const wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator); 33 34 const LOAD_FLAGS_BYPASS_PROXY = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY; 35 const LOAD_FLAGS_BYPASS_CACHE = nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; 36 const LOAD_FLAGS_NONE = nsIWebNavigation.LOAD_FLAGS_NONE; 37 38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 39 40 const panelURL = "chrome://firebug/content/panel.html"; 41 42 // URLs used in the Firebug Menu and several other places 43 const firebugURLs = 44 { 45 main: "https://getfirebug.com", 46 help: "https://getfirebug.com/help", 47 FAQ: "https://getfirebug.com/wiki/index.php/FAQ", 48 docs: "https://getfirebug.com/docs.html", 49 keyboard: "https://getfirebug.com/wiki/index.php/Keyboard_and_Mouse_Shortcuts", 50 discuss: "https://groups.google.com/forum/#!forum/firebug", 51 issues: "http://code.google.com/p/fbug/issues/list?can=1", 52 donate: "https://getfirebug.com/getinvolved", 53 extensions: "https://getfirebug.com/wiki/index.php/Firebug_Extensions", 54 issue5110: "http://code.google.com/p/fbug/issues/detail?id=5110" 55 }; 56 57 const statusCropSize = 20; 58 59 // ********************************************************************************************* // 60 61 // factory is global in module loading window 62 var ChromeFactory = 63 { 64 65 // chrome is created in caller window. 66 createFirebugChrome: function(win) 67 { 68 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 69 // Private 70 71 var panelSplitter, sidePanelDeck, panelBar1, panelBar2; 72 73 var disabledHead = null; 74 var disabledCaption = null; 75 var enableSiteLink = null; 76 var enableSystemPagesLink = null; 77 var enableAlwaysLink = null; 78 79 var FirebugChrome = 80 { 81 // TODO: remove this property, add getters for location, title, focusedElement, setter popup 82 dispatchName: "FirebugChrome", 83 84 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 85 // Initialization 86 87 /** 88 * Called by panelBarWaiter when XUL panelBar(s) (main and side) are constructed 89 * (i.e. the constructor of panelBar binding is executed twice) and when all Firebug 90 * modules + extension modules (if any) are loaded. 91 */ 92 initialize: function() 93 { 94 95 if (FBTrace.DBG_INITIALIZE) 96 FBTrace.sysout("chrome.initialize;"); 97 98 this.window = win; 99 100 panelSplitter = this.getElementById("fbPanelSplitter"); 101 sidePanelDeck = this.getElementById("fbSidePanelDeck"); 102 panelBar1 = this.getElementById("fbPanelBar1"); 103 panelBar2 = this.getElementById("fbPanelBar2"); 104 105 // Firebug has not been initialized yet 106 if (!Firebug.isInitialized) 107 Firebug.initialize(this); 108 109 // FBL should be available at this moment. 110 if (FBTrace.sysout && (!FBL || !FBL.initialize)) 111 { 112 FBTrace.sysout("Firebug is broken, FBL incomplete, if the last function is QI, " + 113 "check lib.js:", FBL); 114 } 115 116 var browser1Complete = false; 117 var browser2Complete = false; 118 119 if (panelBar1) 120 { 121 var browser1 = panelBar1.browser; 122 browser1Complete = browser1.complete; 123 124 if (!browser1Complete) 125 Events.addEventListener(browser1, "load", browser1Loaded, true); 126 127 browser1.droppedLinkHandler = function() 128 { 129 return false; 130 }; 131 132 if (FBTrace.DBG_INITIALIZE) 133 FBTrace.sysout("chrome.browser1.complete; " + browser1Complete); 134 } 135 136 if (panelBar2) 137 { 138 var browser2 = panelBar2.browser; 139 browser2Complete = browser2.complete; 140 141 if (!browser2Complete) 142 Events.addEventListener(browser2, "load", browser2Loaded, true); 143 144 browser2.droppedLinkHandler = function() 145 { 146 return false; 147 }; 148 149 if (FBTrace.DBG_INITIALIZE) 150 FBTrace.sysout("chrome.browser2.complete; " + browser2Complete); 151 } 152 153 Events.addEventListener(win, "blur", onBlur, true); 154 155 if (FBTrace.DBG_INITIALIZE) 156 FBTrace.sysout("chrome.initialized in " + win.location + " with " + 157 (panelBar1 ? panelBar1.browser.ownerDocument.documentURI : "no panel bar"), win); 158 159 // At this point both panelBars can be loaded already, since the src is specified 160 // in firebugOverlay.xul (asynchronously loaded). If yes, start up the initialization 161 // sequence now. 162 if (browser1Complete && browser2Complete) 163 { 164 setTimeout(function() 165 { 166 // chrome bound into this scope 167 FirebugChrome.initializeUI(); 168 }) 169 } 170 }, 171 172 /** 173 * Called when the UI is ready to be initialized, once the panel browsers are loaded. 174 */ 175 initializeUI: function() 176 { 177 if (FBTrace.DBG_INITIALIZE) 178 FBTrace.sysout("chrome.initializeUI;"); 179 180 // listen for panel updates 181 Firebug.registerUIListener(this); 182 183 try 184 { 185 var cmdPopupBrowser = this.getElementById("fbCommandPopupBrowser"); 186 187 this.applyTextSize(Firebug.textSize); 188 189 var doc1 = panelBar1.browser.contentDocument; 190 Events.addEventListener(doc1, "mouseover", onPanelMouseOver, false); 191 Events.addEventListener(doc1, "mouseout", onPanelMouseOut, false); 192 Events.addEventListener(doc1, "mousedown", onPanelMouseDown, false); 193 Events.addEventListener(doc1, "mouseup", onPanelMouseUp, false); 194 Events.addEventListener(doc1, "click", onPanelClick, false); 195 Events.addEventListener(panelBar1, "selectingPanel", onSelectingPanel, false); 196 Events.addEventListener(panelBar1, "DOMMouseScroll", onMouseScroll, false); 197 198 var doc2 = panelBar2.browser.contentDocument; 199 Events.addEventListener(doc2, "mouseover", onPanelMouseOver, false); 200 Events.addEventListener(doc2, "mouseout", onPanelMouseOut, false); 201 Events.addEventListener(doc2, "click", onPanelClick, false); 202 Events.addEventListener(doc2, "mousedown", onPanelMouseDown, false); 203 Events.addEventListener(doc2, "mouseup", onPanelMouseUp, false); 204 Events.addEventListener(panelBar2, "selectPanel", onSelectedSidePanel, false); 205 206 var doc3 = cmdPopupBrowser.contentDocument; 207 Events.addEventListener(doc3, "mouseover", onPanelMouseOver, false); 208 Events.addEventListener(doc3,"mouseout", onPanelMouseOut, false); 209 Events.addEventListener(doc3, "mousedown", onPanelMouseDown, false); 210 Events.addEventListener(doc3, "click", onPanelClick, false); 211 212 var mainTabBox = panelBar1.ownerDocument.getElementById("fbPanelBar1-tabBox"); 213 Events.addEventListener(mainTabBox, "mousedown", onMainTabBoxMouseDown, false); 214 215 // The side panel bar doesn't care about this event. It must, however, 216 // prevent it from bubbling now that we allow the side panel bar to be 217 // *inside* the main panel bar. 218 Events.addEventListener(panelBar2, "selectingPanel", stopBubble, false); 219 220 var locationList = this.getElementById("fbLocationList"); 221 Events.addEventListener(locationList, "selectObject", onSelectLocation, false); 222 223 this.updatePanelBar1(Firebug.panelTypes); 224 225 // Internationalize Firebug UI before firing initializeUI 226 // (so putting version into Firebug About menu operates with correct label) 227 Firebug.internationalizeUI(win.document); 228 Firebug.internationalizeUI(top.document); 229 230 // xxxHonza: Is there any reason why we don't distribute "initializeUI"? 231 // event to modules? 232 Firebug.initializeUI(); 233 234 // Append all registered stylesheets into Firebug UI 235 for (var i=0; i<Firebug.stylesheets.length; i++) 236 { 237 var uri = Firebug.stylesheets[i]; 238 this.appendStylesheet(uri); 239 } 240 241 if (FBTrace.DBG_INITIALIZE) 242 FBTrace.sysout("chrome.initializeUI; Custom stylesheet appended " + 243 Firebug.stylesheets.length, Firebug.stylesheets); 244 245 // Fire event for window event listeners 246 Firebug.sendLoadEvent(); 247 } 248 catch (exc) 249 { 250 fatalError("chrome.initializeUI ERROR "+exc, exc); 251 } 252 }, 253 254 shutdown: function() 255 { 256 var doc1 = panelBar1.browser.contentDocument; 257 Events.removeEventListener(doc1, "mouseover", onPanelMouseOver, false); 258 Events.removeEventListener(doc1, "mouseout", onPanelMouseOut, false); 259 Events.removeEventListener(doc1, "mousedown", onPanelMouseDown, false); 260 Events.removeEventListener(doc1, "mouseup", onPanelMouseUp, false); 261 Events.removeEventListener(doc1, "click", onPanelClick, false); 262 Events.removeEventListener(panelBar1, "selectingPanel", onSelectingPanel, false); 263 Events.removeEventListener(panelBar1, "DOMMouseScroll", onMouseScroll, false); 264 265 var doc2 = panelBar2.browser.contentDocument; 266 Events.removeEventListener(doc2, "mouseover", onPanelMouseOver, false); 267 Events.removeEventListener(doc2, "mouseout", onPanelMouseOut, false); 268 Events.removeEventListener(doc2, "mousedown", onPanelMouseDown, false); 269 Events.removeEventListener(doc2, "mouseup", onPanelMouseUp, false); 270 Events.removeEventListener(doc2, "click", onPanelClick, false); 271 Events.removeEventListener(panelBar2, "selectPanel", onSelectedSidePanel, false); 272 Events.removeEventListener(panelBar2, "selectingPanel", stopBubble, false); 273 274 var cmdPopupBrowser = this.getElementById("fbCommandPopupBrowser"); 275 var doc3 = cmdPopupBrowser.contentDocument; 276 Events.removeEventListener(doc3, "mouseover", onPanelMouseOver, false); 277 Events.removeEventListener(doc3, "mouseout", onPanelMouseOut, false); 278 Events.removeEventListener(doc3, "mousedown", onPanelMouseDown, false); 279 Events.removeEventListener(doc3, "click", onPanelClick, false); 280 281 var mainTabBox = panelBar1.ownerDocument.getElementById("fbPanelBar1-tabBox"); 282 Events.removeEventListener(mainTabBox, "mousedown", onMainTabBoxMouseDown, false); 283 284 var locationList = this.getElementById("fbLocationList"); 285 Events.removeEventListener(locationList, "selectObject", onSelectLocation, false); 286 287 Events.removeEventListener(win, "blur", onBlur, true); 288 289 Firebug.unregisterUIListener(this); 290 291 Firebug.shutdown(); 292 293 if (FBTrace.DBG_EVENTLISTENERS) 294 { 295 var info = []; 296 var listeners = Firebug.Events.getRegisteredListeners(); 297 for (var i=0; i<listeners.length; i++) 298 { 299 var listener = listeners[i]; 300 info.push({ 301 parentId: listener.parentId, 302 evendId: listener.eventId, 303 capturing: listener.capturing, 304 stack: listener.stack, 305 }); 306 } 307 308 FBTrace.sysout("firebug.shutdownFirebug; listeners: " + info.length, info); 309 } 310 311 if (FBTrace.DBG_INITIALIZE) 312 FBTrace.sysout("chrome.shutdown; Done for " + win.location); 313 }, 314 315 /** 316 * Checks if the Firebug window has the focus (is the most recent window) 317 */ 318 hasFocus: function() 319 { 320 try 321 { 322 return (wm.getMostRecentWindow(null).location.href.indexOf("firebug.xul") > 0); 323 } 324 catch(ex) 325 { 326 return false; 327 } 328 }, 329 330 appendStylesheet: function(uri) 331 { 332 var cmdPopupBrowser = this.getElementById("fbCommandPopupBrowser"); 333 334 var doc1 = panelBar1.browser.contentDocument; 335 var doc2 = panelBar2.browser.contentDocument; 336 var doc3 = cmdPopupBrowser.contentDocument; 337 338 Css.appendStylesheet(doc1, uri); 339 Css.appendStylesheet(doc2, uri); 340 Css.appendStylesheet(doc3, uri); 341 342 if (FBTrace.DBG_INITIALIZE) 343 FBTrace.sysout("chrome.appendStylesheet; " + uri); 344 }, 345 346 updateOption: function(name, value) 347 { 348 if (panelBar1 && panelBar1.selectedPanel) 349 panelBar1.selectedPanel.updateOption(name, value); 350 351 if (panelBar2 && panelBar2.selectedPanel) 352 panelBar2.selectedPanel.updateOption(name, value); 353 354 if (name == "textSize") 355 this.applyTextSize(value); 356 357 if (name == "omitObjectPathStack") 358 this.obeyOmitObjectPathStack(value); 359 360 if (name == "viewPanelOrient") 361 this.updateOrient(value); 362 }, 363 364 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 365 366 disableOff: function(collapse) 367 { 368 // disable/enable this button in the Firebug.chrome window 369 Dom.collapse(FirebugChrome.$("fbCloseButton"), collapse); 370 }, 371 372 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 373 374 getPanelDocument: function(panelType) 375 { 376 var cmdPopup = this.getElementById("fbCommandPopup"); 377 var cmdPopupBrowser = this.getElementById("fbCommandPopupBrowser"); 378 379 // Command Line Popup can be displayed for all the other panels 380 // (except for the Console panel) 381 // XXXjjb, xxxHonza, xxxsz: this should be somehow better, more generic and extensible, 382 // e.g. by asking each panel if it supports the Command Line Popup 383 var consolePanelType = Firebug.getPanelType("console"); 384 if (consolePanelType == panelType) 385 { 386 if (!Dom.isCollapsed(cmdPopup)) 387 return cmdPopupBrowser.contentDocument; 388 } 389 390 // Standard panel and side panel documents. 391 if (!panelType.prototype.parentPanel) 392 return panelBar1.browser.contentDocument; 393 else 394 return panelBar2.browser.contentDocument; 395 }, 396 397 getPanelBrowser: function(panel) 398 { 399 if (!panel.parentPanel) 400 return panelBar1.browser; 401 else 402 return panelBar2.browser; 403 }, 404 405 savePanels: function() 406 { 407 var path = this.writePanels(panelBar1.browser.contentDocument); 408 if (FBTrace.DBG_PANELS) 409 FBTrace.sysout("Wrote panels to "+path+"\n"); 410 }, 411 412 writePanels: function(doc) 413 { 414 var serializer = new XMLSerializer(); 415 var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"] 416 .createInstance(Components.interfaces.nsIFileOutputStream); 417 var file = Components.classes["@mozilla.org/file/directory_service;1"] 418 .getService(Components.interfaces.nsIProperties) 419 .get("TmpD", Components.interfaces.nsIFile); 420 421 // extensions sub-directory 422 file.append("firebug"); 423 file.append("panelSave.html"); 424 file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); 425 // write, create, truncate 426 foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); 427 // remember, doc is the DOM tree 428 serializer.serializeToStream(doc, foStream, ""); 429 foStream.close(); 430 return file.path; 431 }, 432 433 // part of initializeUI 434 updatePanelBar1: function(panelTypes) 435 { 436 var mainPanelTypes = []; 437 for (var i = 0; i < panelTypes.length; ++i) 438 { 439 var panelType = panelTypes[i]; 440 if (!panelType.prototype.parentPanel && !panelType.hidden) 441 mainPanelTypes.push(panelType); 442 } 443 panelBar1.updatePanels(mainPanelTypes); 444 }, 445 446 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 447 448 getName: function() 449 { 450 return win ? win.location.href : null; 451 }, 452 453 close: function() 454 { 455 if (FBTrace.DBG_INITIALIZE) 456 FBTrace.sysout("chrome.close closing window "+win.location); 457 win.close(); 458 }, 459 460 focus: function() 461 { 462 win.focus(); 463 panelBar1.browser.contentWindow.focus(); 464 }, 465 466 isFocused: function() 467 { 468 return wm.getMostRecentWindow(null) == win; 469 }, 470 471 focusWatch: function(context) 472 { 473 if (Firebug.isDetached()) 474 Firebug.chrome.focus(); 475 else 476 Firebug.toggleBar(true); 477 478 Firebug.chrome.selectPanel("script"); 479 480 var watchPanel = context.getPanel("watches", true); 481 if (watchPanel) 482 { 483 Firebug.CommandLine.isReadyElsePreparing(context); 484 watchPanel.editNewWatch(); 485 } 486 }, 487 488 isOpen: function() 489 { 490 return !(FirebugChrome.$("fbContentBox").collapsed); 491 }, 492 493 toggleOpen: function(shouldShow) 494 { 495 var contentBox = Firebug.chrome.$("fbContentBox"); 496 contentBox.setAttribute("collapsed", !shouldShow); 497 498 if (!this.inDetachedScope) 499 { 500 Dom.collapse(Firefox.getElementById('fbMainFrame'), !shouldShow); 501 502 var contentSplitter = Firefox.getElementById('fbContentSplitter'); 503 if (contentSplitter) 504 contentSplitter.setAttribute("collapsed", !shouldShow); 505 } 506 507 if (shouldShow && !this.positionInitialzed) 508 { 509 this.positionInitialzed = true; 510 if (Firebug.framePosition != "detached" && Firebug.framePosition != "bottom") 511 { 512 // null only updates frame position without side effects 513 this.setPosition(); 514 } 515 } 516 }, 517 518 onDetach: function() 519 { 520 if(!Firebug.currentContext) 521 Firebug.toggleBar(true); 522 else 523 Firebug.showBar(true); 524 }, 525 526 onUndetach: function() 527 { 528 Dom.collapse(Firebug.chrome.$('fbResumeBox'), true); 529 Dom.collapse(Firebug.chrome.$("fbContentBox"), false); 530 }, 531 532 // only called when detached 533 syncResumeBox: function(context) 534 { 535 var resumeBox = Firebug.chrome.$('fbResumeBox'); 536 537 // xxxHonza: Don't focus the Firebug window now. It would bring the detached Firebug window 538 // to the top every time the attached Firefox page is refreshed, which is annoying. 539 //this.focus(); // bring to users attention 540 541 if (context) 542 { 543 Firebug.chrome.toggleOpen(true); 544 Firebug.chrome.syncPanel(); 545 Dom.collapse(resumeBox, true); 546 } 547 else 548 { 549 Firebug.chrome.toggleOpen(false); 550 Dom.collapse(resumeBox, false); 551 552 Firebug.chrome.window.parent.document.title = 553 Locale.$STR("Firebug - inactive for current website"); 554 } 555 }, 556 557 reload: function(skipCache) 558 { 559 var reloadFlags = skipCache 560 ? LOAD_FLAGS_BYPASS_PROXY | LOAD_FLAGS_BYPASS_CACHE 561 : LOAD_FLAGS_NONE; 562 563 // Make sure the selected tab in the attached browser window is refreshed. 564 var browser = Firefox.getCurrentBrowser(); 565 browser.firebugReload = true; 566 browser.webNavigation.reload(reloadFlags); 567 568 if (FBTrace.DBG_WINDOWS) 569 FBTrace.sysout("chrome.reload; " + skipCache + ", " + browser.currentURI.spec); 570 }, 571 572 gotoPreviousTab: function() 573 { 574 if (Firebug.currentContext.previousPanelName) 575 this.selectPanel(Firebug.currentContext.previousPanelName); 576 }, 577 578 gotoSiblingTab : function(goRight) 579 { 580 if (FirebugChrome.$("fbContentBox").collapsed) 581 return; 582 var i, currentIndex = newIndex = -1, currentPanel = this.getSelectedPanel(), newPanel; 583 var panelTypes = Firebug.getMainPanelTypes(Firebug.currentContext); 584 585 // get the current panel's index (is there a simpler way for this?) 586 for (i = 0; i < panelTypes.length; i++) 587 { 588 if (panelTypes[i].prototype.name === currentPanel.name) 589 { 590 currentIndex = i; 591 break; 592 } 593 } 594 595 if (currentIndex != -1) 596 { 597 newIndex = goRight ? (currentIndex == panelTypes.length - 1 ? 598 0 : ++currentIndex) : (currentIndex == 0 ? panelTypes.length - 1 : --currentIndex); 599 600 newPanel = panelTypes[newIndex].prototype; 601 if (newPanel && newPanel.name) 602 { 603 this.selectPanel(newPanel.name); 604 } 605 } 606 }, 607 608 getNextObject: function(reverse) 609 { 610 var panel = Firebug.currentContext.getPanel(Firebug.currentContext.panelName); 611 if (panel) 612 { 613 var panelStatus = this.getElementById("fbPanelStatus"); 614 var item = panelStatus.getItemByObject(panel.selection); 615 if (item) 616 { 617 if (reverse) 618 item = item.previousSibling ? item.previousSibling.previousSibling : null; 619 else 620 item = item.nextSibling ? item.nextSibling.nextSibling : null; 621 622 if (item) 623 return item.repObject; 624 } 625 } 626 }, 627 628 gotoNextObject: function(reverse) 629 { 630 var nextObject = this.getNextObject(reverse); 631 if (nextObject) 632 this.select(nextObject); 633 else 634 System.beep(); 635 }, 636 637 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 638 // Panels 639 640 /** 641 * Set this.location on the current panel or one given by name. 642 * The location object should be known to the caller to be of the correct type for the panel, 643 * e.g. SourceFile for Script panel 644 * @param object location object, null selects default location 645 * @param panelName name of the panel to select, null means current panel 646 * @param sidePanelName name of the side panel to select 647 */ 648 navigate: function(object, panelName, sidePanelName) 649 { 650 var panel; 651 if (panelName || sidePanelName) 652 panel = this.selectPanel(panelName, sidePanelName); 653 else 654 panel = this.getSelectedPanel(); 655 656 if (panel) 657 panel.navigate(object); 658 }, 659 660 /** 661 * Set this.selection by object type analysis, passing the object to all panels to 662 * find the best match 663 * @param object new this.selection object 664 * @param panelName matching panel.name will be used, if its supportsObject returns true 665 * @param sidePanelName default side panel name used, if its supportsObject returns true 666 * @param forceUpdate if true, then (object === this.selection) is ignored and 667 * updateSelection is called 668 */ 669 select: function(object, panelName, sidePanelName, forceUpdate) 670 { 671 if (FBTrace.DBG_PANELS) 672 FBTrace.sysout("chrome.select object:"+object+" panelName:"+panelName+ 673 " sidePanelName:"+sidePanelName+" forceUpdate:"+forceUpdate+"\n"); 674 675 var bestPanelName = getBestPanelName(object, Firebug.currentContext, panelName); 676 677 // allow refresh if needed (last argument) 678 var panel = this.selectPanel(bestPanelName, sidePanelName/*, true*/); 679 if (panel) 680 panel.select(object, forceUpdate); 681 682 // issue 4778 683 this.syncLocationList(); 684 }, 685 686 selectPanel: function(panelName, sidePanelName, noRefresh) 687 { 688 if (panelName && sidePanelName) 689 Firebug.currentContext.sidePanelNames[panelName] = sidePanelName; 690 691 // cause panel visibility changes and events 692 return panelBar1.selectPanel(panelName, false, noRefresh); 693 }, 694 695 selectSidePanel: function(panelName) 696 { 697 return panelBar2.selectPanel(panelName); 698 }, 699 700 selectSupportingPanel: function(object, context, forceUpdate) 701 { 702 var bestPanelName = getBestPanelSupportingObject(object, context); 703 var panel = this.selectPanel(bestPanelName, false, true); 704 if (panel) 705 panel.select(object, forceUpdate); 706 }, 707 708 clearPanels: function() 709 { 710 panelBar1.hideSelectedPanel(); 711 panelBar1.selectedPanel = null; 712 panelBar2.selectedPanel = null; 713 }, 714 715 getSelectedPanel: function() 716 { 717 return panelBar1 ? panelBar1.selectedPanel : null; 718 }, 719 720 getSelectedSidePanel: function() 721 { 722 return panelBar2 ? panelBar2.selectedPanel : null; 723 }, 724 725 switchToPanel: function(context, switchToPanelName) 726 { 727 // Remember the previous panel and bar state so we can revert if the user cancels. 728 this.previousPanelName = context.panelName; 729 this.previousSidePanelName = context.sidePanelName; 730 this.previouslyCollapsed = FirebugChrome.$("fbContentBox").collapsed; 731 732 // TODO previouslyMinimized 733 this.previouslyFocused = Firebug.isDetached() && this.isFocused(); 734 735 var switchPanel = this.selectPanel(switchToPanelName); 736 if (switchPanel) 737 this.previousObject = switchPanel.selection; 738 739 return switchPanel; 740 }, 741 742 unswitchToPanel: function(context, switchToPanelName, canceled) 743 { 744 var switchToPanel = context.getPanel(switchToPanelName); 745 746 if (this.previouslyFocused) 747 this.focus(); 748 749 if (canceled && this.previousPanelName) 750 { 751 // revert 752 if (this.previouslyCollapsed) 753 Firebug.showBar(false); 754 755 if (this.previousPanelName == switchToPanelName) 756 switchToPanel.select(this.previousObject); 757 else 758 this.selectPanel(this.previousPanelName, this.previousSidePanelName); 759 } 760 else 761 { 762 // else stay on the switchToPanel 763 this.selectPanel(switchToPanelName); 764 if (switchToPanel.selection) 765 this.select(switchToPanel.selection); 766 this.getSelectedPanel().panelNode.focus(); 767 } 768 769 delete this.previousObject; 770 delete this.previousPanelName; 771 delete this.previousSidePanelName; 772 delete this.inspectingChrome; 773 774 return switchToPanel; 775 }, 776 777 getSelectedPanelURL: function() 778 { 779 var location; 780 if (Firebug.currentContext) 781 { 782 var panel = Firebug.chrome.getSelectedPanel(); 783 if (panel) 784 { 785 location = panel.location; 786 if (!location && panel.name == "html") 787 location = Firebug.currentContext.window.document.location; 788 789 if (location && (location instanceof Firebug.SourceFile || 790 location instanceof CSSStyleSheet)) 791 location = location.href; 792 } 793 } 794 795 if (!location) 796 { 797 var currentURI = Firefox.getCurrentURI(); 798 if (currentURI) 799 location = currentURI.asciiSpec; 800 } 801 802 if (!location) 803 return; 804 805 location = location.href || location.url || location.toString(); 806 if (Firebug.filterSystemURLs && Url.isSystemURL(location)) 807 return; 808 809 return location; 810 }, 811 812 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 813 // Location interface provider for binding.xml panelFileList 814 815 getLocationProvider: function() 816 { 817 // a function that returns an object with .getObjectDescription() and .getLocationList() 818 return function getSelectedPanelFromCurrentContext() 819 { 820 // panels provide location, use the selected panel 821 return Firebug.chrome.getSelectedPanel(); 822 } 823 }, 824 825 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 826 // UI Synchronization 827 828 setFirebugContext: function(context) 829 { 830 // This sets the global value of Firebug.currentContext in the window, that this 831 // chrome is compiled into. Note, that for firebug.xul the Firebug object is shared 832 // across windows, but not FirebugChrome and Firebug.currentContext. 833 Firebug.currentContext = context; 834 835 if (FBTrace.DBG_WINDOWS || FBTrace.DBG_DISPATCH || FBTrace.DBG_ACTIVATION) 836 FBTrace.sysout("setFirebugContext "+(Firebug.currentContext? 837 Firebug.currentContext.getName():" **> NULL <** ") + " in "+win.location); 838 }, 839 840 hidePanel: function() 841 { 842 if (panelBar1.selectedPanel) 843 panelBar1.hideSelectedPanel() 844 845 if (panelBar2.selectedPanel) 846 panelBar2.hideSelectedPanel() 847 }, 848 849 syncPanel: function(panelName) 850 { 851 var context = Firebug.currentContext; 852 853 if (FBTrace.DBG_PANELS) 854 FBTrace.sysout("chrome.syncPanel Firebug.currentContext=" + 855 (context ? context.getName() : "undefined")); 856 857 var panelStatus = this.getElementById("fbPanelStatus"); 858 panelStatus.clear(); 859 860 if (context) 861 { 862 if (!panelName) 863 panelName = context.panelName? context.panelName : Firebug.defaultPanelName; 864 865 // Make the HTML panel the default panel, which is displayed 866 // to the user the very first time. 867 if (!panelName || !Firebug.getPanelType(panelName)) 868 panelName = "html"; 869 870 this.syncMainPanels(); 871 panelBar1.selectPanel(panelName, true); 872 } 873 else 874 { 875 panelBar1.selectPanel(null, true); 876 } 877 878 if (Firebug.isDetached()) 879 this.syncTitle(); 880 }, 881 882 syncMainPanels: function() 883 { 884 if (Firebug.currentContext) 885 { 886 var panelTypes = Firebug.getMainPanelTypes(Firebug.currentContext); 887 panelBar1.updatePanels(panelTypes); 888 889 // Update also BON tab flag (orange background if BON is active) 890 // every time the user changes the current tab in Firefox. 891 Firebug.Breakpoint.updatePanelTabs(Firebug.currentContext); 892 } 893 }, 894 895 syncSidePanels: function() 896 { 897 if (FBTrace.DBG_PANELS) 898 { 899 FBTrace.sysout("chrome.syncSidePanels; main panel: " + 900 (panelBar1.selectedPanel ? panelBar1.selectedPanel.name : "no panel") + 901 ", side panel: " + 902 (panelBar2.selectedPanel ? panelBar2.selectedPanel.name : "no panel")); 903 } 904 905 if (!panelBar1.selectedPanel) 906 return; 907 908 var panelTypes; 909 if (Firebug.currentContext) 910 { 911 panelTypes = Firebug.getSidePanelTypes(Firebug.currentContext, 912 panelBar1.selectedPanel); 913 panelBar2.updatePanels(panelTypes); 914 } 915 916 if (Firebug.currentContext && Firebug.currentContext.sidePanelNames) 917 { 918 if (!panelBar2.selectedPanel || 919 (panelBar2.selectedPanel.parentPanel !== panelBar1.selectedPanel.name)) 920 { 921 var sidePanelName = Firebug.currentContext.sidePanelNames[ 922 Firebug.currentContext.panelName]; 923 sidePanelName = getBestSidePanelName(sidePanelName, panelTypes); 924 panelBar2.selectPanel(sidePanelName, true); 925 } 926 else 927 { 928 // If the context changes, we need to refresh the panel. 929 panelBar2.selectPanel(panelBar2.selectedPanel.name, true); 930 } 931 } 932 else 933 { 934 panelBar2.selectPanel(null); 935 } 936 937 if (FBTrace.DBG_PANELS) 938 FBTrace.sysout("chrome.syncSidePanels; selected side panel " + panelBar1.selectedPanel); 939 940 sidePanelDeck.selectedPanel = panelBar2; 941 942 Dom.collapse(sidePanelDeck, !panelBar2.selectedPanel); 943 Dom.collapse(panelSplitter, !panelBar2.selectedPanel); 944 }, 945 946 syncTitle: function() 947 { 948 if (Firebug.currentContext) 949 { 950 var title = Firebug.currentContext.getTitle(); 951 win.parent.document.title = Locale.$STRF("WindowTitle", [title]); 952 } 953 else 954 { 955 win.parent.document.title = Locale.$STR("Firebug"); 956 } 957 }, 958 959 focusLocationList: function() 960 { 961 var locationList = this.getElementById("fbLocationList"); 962 locationList.popup.showPopup(locationList, -1, -1, "popup", "bottomleft", "topleft"); 963 }, 964 965 syncLocationList: function() 966 { 967 var locationButtons = this.getElementById("fbLocationButtons"); 968 969 var panel = panelBar1.selectedPanel; 970 if (panel && panel.location) 971 { 972 var locationList = this.getElementById("fbLocationList"); 973 locationList.location = panel.location; 974 975 Dom.collapse(locationButtons, false); 976 } 977 else 978 { 979 Dom.collapse(locationButtons, true); 980 } 981 }, 982 983 clearStatusPath: function() 984 { 985 var panelStatus = this.getElementById("fbPanelStatus"); 986 panelStatus.clear(); 987 }, 988 989 syncStatusPath: function() 990 { 991 var panelStatus = this.getElementById("fbPanelStatus"); 992 var panelStatusSeparator = this.getElementById("fbStatusSeparator"); 993 var panel = panelBar1.selectedPanel; 994 995 if (!panel || (panel && !panel.selection)) 996 { 997 panelStatus.clear(); 998 } 999 else 1000 { 1001 var path = panel.getObjectPath(panel.selection); 1002 if (!path || !path.length) 1003 { 1004 Dom.hide(panelStatusSeparator, true); 1005 panelStatus.clear(); 1006 } 1007 else 1008 { 1009 // Update the visibility of the separator. The separator 1010 // is displayed only if there are some other buttons on the left side. 1011 // Before showing the status separator let's see whether there are any other 1012 // buttons on the left. 1013 var hide = true; 1014 var sibling = panelStatusSeparator.parentNode.previousSibling; 1015 while (sibling) 1016 { 1017 if (!Dom.isCollapsed(sibling)) 1018 { 1019 hide = false; 1020 break; 1021 } 1022 sibling = sibling.previousSibling; 1023 } 1024 Dom.hide(panelStatusSeparator, hide); 1025 1026 if (panel.name != panelStatus.lastPanelName) 1027 panelStatus.clear(); 1028 1029 panelStatus.lastPanelName = panel.name; 1030 1031 // If the object already exists in the list, just select it and keep the path. 1032 var selection = panel.selection; 1033 var existingItem = panelStatus.getItemByObject(panel.selection); 1034 if (existingItem) 1035 { 1036 // Update the labels of the status path elements, because it can be, 1037 // that the elements changed even when the selected element exists 1038 // inside the path (issue 4826) 1039 var statusItems = panelStatus.getItems(); 1040 for (var i = 0; i < statusItems.length; ++i) 1041 { 1042 var object = Firebug.getRepObject(statusItems[i]); 1043 var rep = Firebug.getRep(object, Firebug.currentContext); 1044 var objectTitle = rep.getTitle(object, Firebug.currentContext); 1045 var title = String.cropMultipleLines(objectTitle, statusCropSize); 1046 1047 statusItems[i].label = title; 1048 } 1049 panelStatus.selectItem(existingItem); 1050 } 1051 else 1052 { 1053 panelStatus.clear(); 1054 1055 for (var i = 0; i < path.length; ++i) 1056 { 1057 var object = path[i]; 1058 1059 var rep = Firebug.getRep(object, Firebug.currentContext); 1060 var objectTitle = rep.getTitle(object, Firebug.currentContext); 1061 1062 var title = String.cropMultipleLines(objectTitle, statusCropSize); 1063 panelStatus.addItem(title, object, rep, panel.statusSeparator); 1064 } 1065 1066 panelStatus.selectObject(panel.selection); 1067 if (FBTrace.DBG_PANELS) 1068 FBTrace.sysout("syncStatusPath "+path.length+" items ", path); 1069 } 1070 } 1071 } 1072 }, 1073 1074 toggleOrient: function(preferredValue) 1075 { 1076 var value = Options.get("viewPanelOrient"); 1077 if (value == preferredValue) 1078 return; 1079 1080 Options.togglePref("viewPanelOrient"); 1081 }, 1082 1083 updateOrient: function(value) 1084 { 1085 var panelPane = FirebugChrome.$("fbPanelPane"); 1086 if (!panelPane) 1087 return; 1088 1089 var newOrient = value ? "vertical" : "horizontal"; 1090 if (panelPane.orient == newOrient) 1091 return; 1092 1093 panelSplitter.orient = panelPane.orient = newOrient; 1094 }, 1095 1096 setPosition: function(pos) 1097 { 1098 if (Firebug.framePosition == pos) 1099 return; 1100 1101 if (pos) 1102 { 1103 if (Firebug.getSuspended()) 1104 Firebug.toggleBar(); 1105 } 1106 else 1107 { 1108 pos = Firebug.framePosition; 1109 } 1110 1111 if (pos == "detached") 1112 { 1113 Firebug.toggleDetachBar(true, true); 1114 return; 1115 } 1116 1117 if (Firebug.isDetached()) 1118 Firebug.toggleDetachBar(false, true); 1119 1120 pos && this.syncPositionPref(pos); 1121 1122 var vertical = pos == "top" || pos == "bottom"; 1123 var after = pos == "bottom" || pos == "right"; 1124 1125 var document = window.parent.document; 1126 var container = document.getElementById(vertical ? "appcontent" : "browser"); 1127 1128 var splitter = Firefox.getElementById("fbContentSplitter"); 1129 splitter.setAttribute("orient", vertical ? "vertical" : "horizontal"); 1130 splitter.setAttribute("dir", after ? "" : "reverse"); 1131 container.insertBefore(splitter, after ? null: container.firstChild); 1132 1133 var frame = document.getElementById("fbMainFrame"); 1134 1135 var newFrame = frame.cloneNode(true); 1136 var newBrowser = newFrame.querySelector("#fbMainContainer"); 1137 var oldBrowser = frame.querySelector("#fbMainContainer"); 1138 1139 newBrowser.removeAttribute("src"); 1140 container.insertBefore(newFrame, after ? null: container.firstChild); 1141 1142 this.swapBrowsers(oldBrowser, newBrowser); 1143 this.browser = newBrowser; 1144 1145 frame.parentNode.removeChild(frame); 1146 this.framePosition = pos; 1147 }, 1148 1149 syncPositionPref: function(pos) 1150 { 1151 if (!pos) 1152 { 1153 if (Firebug.isDetached()) 1154 pos = "detached"; 1155 else 1156 pos = this.framePosition || 'bottom'; 1157 } 1158 1159 Firebug.Options.set("framePosition", pos); 1160 return Firebug.framePosition = pos; 1161 }, 1162 1163 swapBrowsers: function(oldBrowser, newBrowser) 1164 { 1165 var oldDoc = oldBrowser.contentDocument 1166 // Panels remember the top window, for which they were first opened. 1167 // So we need to destroy their views. 1168 var styleSheet = oldDoc.styleSheets[0]; 1169 var rulePos = styleSheet.cssRules.length; 1170 styleSheet.insertRule( 1171 "panel{display:-moz-box!important; visibility:collapse!important;}", rulePos); 1172 1173 // We need to deal with inner frames first since swapFrameLoaders 1174 // doesn't work for type="chrome" browser containing type="content" browsers 1175 var frames = oldDoc.querySelectorAll("browser[type*=content], iframe[type*=content]"); 1176 var tmpFrames = [], placeholders = []; 1177 1178 var topDoc = oldBrowser.ownerDocument; 1179 var temp = topDoc.createElement("box"); 1180 topDoc.documentElement.appendChild(temp); 1181 1182 var swapDocShells = function(a, b) 1183 { 1184 // important! must touch browser.contentDocument to initialize it 1185 a.contentDocument == b.contentDocument; 1186 if (a.nodeName == "iframe") 1187 a.QueryInterface(Ci.nsIFrameLoaderOwner).swapFrameLoaders(b); 1188 else 1189 a.swapDocShells(b); 1190 } 1191 1192 for (var i = frames.length - 1; i >= 0; i--) 1193 { 1194 placeholders[i] = document.createElement("placeholder"); 1195 tmpFrames[i] = frames[i].cloneNode(true); 1196 tmpFrames[i].removeAttribute("src"); 1197 frames[i].removeAttribute("src"); 1198 temp.appendChild(tmpFrames[i]); 1199 } 1200 1201 for (var i = tmpFrames.length - 1; i >= 0; i--) 1202 { 1203 swapDocShells(tmpFrames[i], frames[i]); 1204 frames[i].parentNode.replaceChild(placeholders[i], frames[i]); 1205 } 1206 1207 swapDocShells(oldBrowser, newBrowser); 1208 1209 for (var i = placeholders.length - 1; i >= 0; i--) 1210 placeholders[i].parentNode.replaceChild(frames[i], placeholders[i]); 1211 1212 for (var i = frames.length - 1; i >= 0; i--) 1213 swapDocShells(tmpFrames[i], frames[i]); 1214 1215 temp.parentNode.removeChild(temp); 1216 1217 styleSheet.deleteRule(rulePos); 1218 }, 1219 1220 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 1221 // Global Attributes 1222 1223 getGlobalAttribute: function(id, name) 1224 { 1225 var elt = FirebugChrome.$(id); 1226 return elt.getAttribute(name); 1227 }, 1228 1229 setGlobalAttribute: function(id, name, value) 1230 { 1231 var elt = FirebugChrome.$(id); 1232 if (elt) 1233 { 1234 if (value == null) 1235 elt.removeAttribute(name); 1236 else 1237 elt.setAttribute(name, value); 1238 } 1239 1240 if (Firebug.externalChrome) 1241 Firebug.externalChrome.setGlobalAttribute(id, name, value); 1242 }, 1243 1244 setChromeDocumentAttribute: function(id, name, value) 1245 { 1246 // call as Firebug.chrome.setChromeDocumentAttribute() to set attributes 1247 // in another window 1248 var elt = FirebugChrome.$(id); 1249 if (elt) 1250 elt.setAttribute(name, value); 1251 }, 1252 1253 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 1254 1255 keyCodeListen: function(key, filter, listener, capture) 1256 { 1257 if (!filter) 1258 filter = Events.noKeyModifiers; 1259 1260 var keyCode = KeyEvent["DOM_VK_"+key]; 1261 1262 function fn(event) 1263 { 1264 if (event.keyCode == keyCode && (!filter || filter(event))) 1265 { 1266 listener(); 1267 Events.cancelEvent(event); 1268 } 1269 } 1270 1271 Events.addEventListener(win, "keypress", fn, capture); 1272 1273 return [fn, capture]; 1274 }, 1275 1276 keyListen: function(ch, filter, listener, capture) 1277 { 1278 if (!filter) 1279 filter = Events.noKeyModifiers; 1280 1281 var charCode = ch.charCodeAt(0); 1282 1283 function fn(event) 1284 { 1285 if (event.charCode == charCode && (!filter || filter(event))) 1286 { 1287 listener(); 1288 Events.cancelEvent(event); 1289 } 1290 } 1291 1292 Events.addEventListener(win, "keypress", fn, capture); 1293 1294 return [fn, capture]; 1295 }, 1296 1297 keyIgnore: function(listener) 1298 { 1299 Events.removeEventListener(win, "keypress", listener[0], listener[1]); 1300 }, 1301 1302 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 1303 1304 $: function(id) 1305 { 1306 return this.getElementById(id); 1307 }, 1308 1309 getElementById: function(id) 1310 { 1311 // The document we close over, not the global. 1312 return win.document.getElementById(id); 1313 }, 1314 1315 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 1316 1317 applyTextSize: function(value) 1318 { 1319 if (!panelBar1) 1320 return; 1321 1322 var zoom = Firebug.Options.getZoomByTextSize(value); 1323 var zoomString = (zoom * 100) + "%"; 1324 1325 // scale the aspect relative to 11pt Lucida Grande 1326 // xxxsz: The magic number 0.547 should be replaced some logic retrieving this value. 1327 var fontSizeAdjust = zoom * 0.547; 1328 var contentBox = Firebug.chrome.$("fbContentBox"); 1329 contentBox.style.fontSizeAdjust = fontSizeAdjust; 1330 1331 //panelBar1.browser.contentDocument.documentElement.style.fontSizeAdjust = fontSizeAdjust; 1332 //panelBar2.browser.contentDocument.documentElement.style.fontSizeAdjust = fontSizeAdjust; 1333 1334 panelBar1.browser.markupDocumentViewer.textZoom = zoom; 1335 panelBar2.browser.markupDocumentViewer.textZoom = zoom; 1336 1337 var cmdPopupBrowser = this.getElementById("fbCommandPopupBrowser"); 1338 cmdPopupBrowser.markupDocumentViewer.textZoom = zoom; 1339 1340 var box = Firebug.chrome.$("fbCommandBox"); 1341 box.style.fontSizeAdjust = fontSizeAdjust; 1342 if (Firebug.CommandLine) 1343 { 1344 Firebug.CommandLine.getSingleRowCommandLine().style.fontSizeAdjust = fontSizeAdjust; 1345 Firebug.chrome.$("fbCommandLineCompletion").style.fontSizeAdjust = fontSizeAdjust; 1346 Firebug.chrome.$("fbCommandLineCompletionList").style.fontSizeAdjust = fontSizeAdjust; 1347 1348 Firebug.CommandEditor.fontSizeAdjust(fontSizeAdjust); 1349 } 1350 1351 Firebug.dispatchToPanels("onTextSizeChange", [zoom, fontSizeAdjust]); 1352 }, 1353 1354 obeyOmitObjectPathStack: function(value) 1355 { 1356 var panelStatus = this.getElementById("fbPanelStatus"); 1357 Dom.hide(panelStatus, (value?true:false)); 1358 }, 1359 1360 getPanelStatusElements: function() 1361 { 1362 return this.getElementById("fbPanelStatus"); 1363 }, 1364 1365 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 1366 // UI Event Listeners uilisteners or "panelListeners" 1367 1368 onPanelNavigate: function(object, panel) 1369 { 1370 this.syncLocationList(); 1371 }, 1372 1373 onObjectSelected: function(object, panel) 1374 { 1375 if (panel == panelBar1.selectedPanel) 1376 { 1377 this.syncStatusPath(); 1378 1379 var sidePanel = panelBar2.selectedPanel; 1380 if (sidePanel) 1381 sidePanel.select(object); 1382 } 1383 }, 1384 1385 onObjectChanged: function(object, panel) 1386 { 1387 if (panel == panelBar1.selectedPanel) 1388 { 1389 this.syncStatusPath(); 1390 1391 var sidePanel = panelBar2.selectedPanel; 1392 if (sidePanel) 1393 sidePanel.refresh(); 1394 } 1395 }, 1396 1397 // called on setTimeout() after sourceBox viewport has been repainted 1398 onApplyDecorator: function(sourceBox) 1399 { 1400 }, 1401 1402 // called on scrollTo() passing in the selected line 1403 onViewportChange: function(sourceLink) 1404 { 1405 }, 1406 1407 // called when the Firebug UI comes up in browser 1408 showUI: function(browser, context) 1409 { 1410 }, 1411 1412 // called when the Firebug UI comes down; context may be null 1413 hideUI: function(browser, context) 1414 { 1415 }, 1416 1417 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 1418 1419 onMenuShowing: function(popup) 1420 { 1421 var detachFirebug = Dom.getElementsByAttribute(popup, "id", "menu_firebug_detachFirebug")[0]; 1422 if (detachFirebug) 1423 { 1424 detachFirebug.setAttribute("label", (Firebug.isDetached() ? 1425 Locale.$STR("firebug.AttachFirebug") : Locale.$STR("firebug.DetachFirebug"))); 1426 } 1427 1428 var toggleFirebug = Dom.getElementsByAttribute(popup, "id", "menu_firebug_toggleFirebug")[0]; 1429 if (toggleFirebug) 1430 { 1431 var fbContentBox = FirebugChrome.$("fbContentBox"); 1432 var collapsed = fbContentBox.getAttribute("collapsed"); 1433 if (collapsed == "true") 1434 { 1435 toggleFirebug.setAttribute("label", Locale.$STR("inBrowser")); 1436 toggleFirebug.setAttribute("tooltiptext", Locale.$STR("inBrowser")); 1437 } 1438 else 1439 { 1440 toggleFirebug.setAttribute("label", Locale.$STR("firebug.menu.Minimize_Firebug")); 1441 toggleFirebug.setAttribute("tooltiptext", Locale.$STR("firebug.menu.tip.Minimize_Firebug")); 1442 } 1443 1444 // If Firebug is detached, hide the menu. ('Open Firebug' shortcut doesn't hide 1445 // but just focuses the external window) 1446 if (Firebug.isDetached()) 1447 toggleFirebug.setAttribute("collapsed", (collapsed == "true" ? "false" : "true")); 1448 } 1449 }, 1450 1451 onOptionsShowing: function(popup) 1452 { 1453 for (var child = popup.firstChild; child; child = child.nextSibling) 1454 { 1455 if (child.localName == "menuitem") 1456 { 1457 var option = child.getAttribute("option"); 1458 if (option) 1459 { 1460 var checked = false; 1461 if (option == "profiling") 1462 checked = FBS.profiling; 1463 else 1464 checked = Firebug.Options.get(option); 1465 1466 child.setAttribute("checked", checked); 1467 } 1468 } 1469 } 1470 }, 1471 1472 onToggleOption: function(menuitem) 1473 { 1474 var option = menuitem.getAttribute("option"); 1475 var checked = menuitem.getAttribute("checked") == "true"; 1476 1477 Firebug.Options.set(option, checked); 1478 }, 1479 1480 onContextShowing: function(event) 1481 { 1482 // xxxHonza: This context menu support can be used even in a separate window, which 1483 // doesn't contain the Firebug UI (panels). 1484 //if (!panelBar1.selectedPanel) 1485 // return false; 1486 1487 var popup = event.target; 1488 if (popup.id != "fbContextMenu") 1489 return; 1490 1491 var target = win.document.popupNode; 1492 var panel = target ? Firebug.getElementPanel(target) : null; 1493 1494 // The event must be on our chrome not inside the panel. 1495 if (!panel) 1496 panel = panelBar1 ? panelBar1.selectedPanel : null; 1497 1498 Dom.eraseNode(popup); 1499 1500 // Make sure the Copy action is only available if there is actually something 1501 // selected in the panel. 1502 var sel = target.ownerDocument.defaultView.getSelection(); 1503 if (!this.contextMenuObject && 1504 !FirebugChrome.$("cmd_copy").getAttribute("disabled") && 1505 !sel.isCollapsed) 1506 { 1507 var menuitem = Menu.createMenuItem(popup, {label: "Copy"}); 1508 menuitem.setAttribute("command", "cmd_copy"); 1509 } 1510 1511 var object; 1512 if (this.contextMenuObject) 1513 object = this.contextMenuObject; 1514 else if (target && target.ownerDocument == document) 1515 object = Firebug.getRepObject(target); 1516 else if (target && panel) 1517 object = panel.getPopupObject(target); 1518 else if (target) 1519 // xxxHonza: What about a node from a different document? Is that OK? 1520 object = Firebug.getRepObject(target); 1521 1522 this.contextMenuObject = null; 1523 1524 var rep = Firebug.getRep(object, Firebug.currentContext); 1525 var realObject = rep ? rep.getRealObject(object, Firebug.currentContext) : null; 1526 var realRep = realObject ? Firebug.getRep(realObject, Firebug.currentContext) : null; 1527 1528 if (FBTrace.DBG_MENU) 1529 { 1530 FBTrace.sysout("chrome.onContextShowing object:"+object+", rep: "+rep+ 1531 ", realObject: "+realObject+", realRep:"+realRep); 1532 } 1533 1534 // 1. Add the custom menu items from the realRep 1535 if (realObject && realRep) 1536 { 1537 var items = realRep.getContextMenuItems(realObject, target, Firebug.currentContext); 1538 if (items) 1539 Menu.createMenuItems(popup, items); 1540 } 1541 1542 // 2. Add the custom menu items from the original rep 1543 if (object && rep && rep != realRep) 1544 { 1545 var items = rep.getContextMenuItems(object, target, Firebug.currentContext); 1546 if (items) 1547 Menu.createMenuItems(popup, items); 1548 } 1549 1550 // 3. Add the custom menu items from the panel 1551 if (panel) 1552 { 1553 var items = panel.getContextMenuItems(realObject, target); 1554 if (items) 1555 Menu.createMenuItems(popup, items); 1556 } 1557 1558 // 4. Add the inspect menu items 1559 if (realObject && rep && rep.inspectable) 1560 { 1561 var items = this.getInspectMenuItems(realObject); 1562 1563 // Separate existing menu items from 'inspect' menu items. 1564 if (popup.firstChild && items.length > 0) 1565 Menu.createMenuSeparator(popup); 1566 1567 Menu.createMenuItems(popup, items); 1568 } 1569 1570 // 5. Add menu items from uiListeners 1571 var items = []; 1572 Events.dispatch(Firebug.uiListeners, "onContextMenu", [items, object, target, 1573 Firebug.currentContext, panel, popup]); 1574 1575 if (items) 1576 Menu.createMenuItems(popup, items); 1577 1578 if (!popup.firstChild) 1579 return false; 1580 }, 1581 1582 getInspectMenuItems: function(object) 1583 { 1584 var items = []; 1585 1586 // Domplate (+ support for context menus) can be used even in separate 1587 // windows when Firebug.currentContext doesn't have to be defined. 1588 if (!Firebug.currentContext) 1589 return items; 1590 1591 for (var i = 0; i < Firebug.panelTypes.length; ++i) 1592 { 1593 var panelType = Firebug.panelTypes[i]; 1594 if (!panelType.prototype.parentPanel 1595 && panelType.prototype.name != Firebug.currentContext.panelName 1596 && panelSupportsObject(panelType, object, Firebug.currentContext)) 1597 { 1598 var panelName = panelType.prototype.name; 1599 1600 var title = Firebug.getPanelTitle(panelType); 1601 var label = Locale.$STRF("panel.Inspect_In_Panel", [title]); 1602 var tooltiptext = Locale.$STRF("panel.tip.Inspect_In_Panel", [title]); 1603 var id = "InspectIn" + panelName + "Panel"; 1604 1605 var command = Obj.bindFixed(this.select, this, object, panelName); 1606 items.push({label: label, tooltiptext: tooltiptext, command: command, nol10n: true, 1607 id: id}); 1608 } 1609 } 1610 1611 return items; 1612 }, 1613 1614 onTooltipShowing: function(event) 1615 { 1616 // xxxHonza: This tooltip support can be used even in a separate window, which 1617 // doesn't contain the Firebug UI (panels). 1618 //if (!panelBar1.selectedPanel) 1619 // return false; 1620 1621 var tooltip = FirebugChrome.$("fbTooltip"); 1622 var target = win.document.tooltipNode; 1623 1624 var panel = target ? Firebug.getElementPanel(target) : null; 1625 1626 var object; 1627 1628 /* XXXjjb: This causes the Script panel to show the function body over and over. 1629 * We need to clear it at least, but actually we need to understand why the tooltip 1630 * should show the context menu object at all. One thing the contextMenuObject supports 1631 * is peeking at function bodies when stopped at a breakpoint. 1632 * That case could be supported with clearing the contextMenuObject, but we don't 1633 * know if that breaks something else. So maybe a popupMenuObject should be set 1634 * on the context if that is what we want to support. 1635 * The other complication is that there seems to be another tooltip. 1636 if (this.contextMenuObject) 1637 { 1638 object = this.contextMenuObject; 1639 FBTrace.sysout("tooltip by contextMenuObject"); 1640 } 1641 else*/ 1642 1643 if (target && target.ownerDocument == document) 1644 object = Firebug.getRepObject(target); 1645 else if (panel) 1646 object = panel.getTooltipObject(target); 1647 1648 var rep = object ? Firebug.getRep(object, Firebug.currentContext) : null; 1649 object = rep ? rep.getRealObject(object, Firebug.currentContext) : null; 1650 rep = object ? Firebug.getRep(object) : null; 1651 1652 if (object && rep) 1653 { 1654 var label = rep.getTooltip(object, Firebug.currentContext); 1655 if (label) 1656 { 1657 tooltip.setAttribute("label", label); 1658 return true; 1659 } 1660 } 1661 1662 if (Css.hasClass(target, 'noteInToolTip')) 1663 Css.setClass(tooltip, 'noteInToolTip'); 1664 else 1665 Css.removeClass(tooltip, 'noteInToolTip'); 1666 1667 if (target && target.hasAttribute("title")) 1668 { 1669 tooltip.setAttribute("label", target.getAttribute("title")); 1670 return true; 1671 } 1672 1673 return false; 1674 }, 1675 1676 openAboutDialog: function() 1677 { 1678 if (FBTrace.DBG_WINDOWS) 1679 FBTrace.sysout("Firebug.openAboutDialog"); 1680 1681 try 1682 { 1683 // Firefox 4.0+ implements a new AddonManager. In case of Firefox 3.6 the module 1684 // is not available and there is an exception. 1685 Components.utils["import"]("resource://gre/modules/AddonManager.jsm"); 1686 } 1687 catch (err) 1688 { 1689 } 1690 1691 if (typeof(AddonManager) != "undefined") 1692 { 1693 AddonManager.getAddonByID("firebug@software.joehewitt.com", function(addon) 1694 { 1695 openDialog("chrome://mozapps/content/extensions/about.xul", "", 1696 "chrome,centerscreen,modal", addon); 1697 }); 1698 } 1699 else 1700 { 1701 var extensionManager = Cc["@mozilla.org/extensions/manager;1"].getService( 1702 Ci.nsIExtensionManager); 1703 1704 openDialog("chrome://mozapps/content/extensions/about.xul", "", 1705 "chrome,centerscreen,modal", "urn:mozilla:item:firebug@software.joehewitt.com", 1706 extensionManager.datasource); 1707 } 1708 }, 1709 1710 breakOnNext: function(context, event) 1711 { 1712 // avoid bubbling from associated options 1713 if (event.target.id != "cmd_firebug_toggleBreakOn") 1714 return; 1715 1716 if (!context) 1717 { 1718 if (FBTrace.DBG_BP) 1719 FBTrace.sysout("Firebug chrome: breakOnNext with no context??"); 1720 return; 1721 } 1722 1723 var panel = panelBar1.selectedPanel; 1724 1725 if (FBTrace.DBG_BP) 1726 FBTrace.sysout("Firebug chrome: breakOnNext for panel " + 1727 (panel ? panel.name : "NO panel"), panel); 1728 1729 if (panel && panel.breakable) 1730 Firebug.Breakpoint.toggleBreakOnNext(panel); 1731 }, 1732 1733 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 1734 1735 visitWebsite: function(which, arg) 1736 { 1737 var url = firebugURLs[which]; 1738 if (url) 1739 { 1740 if (arg) 1741 url += arg; 1742 1743 Win.openNewTab(url); 1744 } 1745 }, 1746 1747 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 1748 // Main Toolbar 1749 1750 appendToolbarButton: function(button, before) 1751 { 1752 var toolbar = FirebugChrome.$("fbPanelBar1-buttons"); 1753 var element = Toolbar.createToolbarButton(toolbar, button, before); 1754 element.repObject = button; 1755 }, 1756 1757 removeToolbarButton: function(button) 1758 { 1759 var toolbar = FirebugChrome.$("fbPanelBar1-buttons"); 1760 for (var child = toolbar.firstChild; child; child = child.nextSibling) 1761 { 1762 if (child.repObject == button) 1763 { 1764 toolbar.removeChild(child); 1765 break; 1766 } 1767 } 1768 } 1769 }; 1770 1771 // ********************************************************************************************* // 1772 // Local Helpers 1773 1774 function panelSupportsObject(panelType, object, context) 1775 { 1776 if (panelType) 1777 { 1778 try { 1779 // This tends to throw exceptions often because some objects are weird 1780 return panelType.prototype.supportsObject(object, typeof object, context) 1781 } catch (exc) {} 1782 } 1783 1784 return 0; 1785 } 1786 1787 function getBestPanelName(object, context, panelName) 1788 { 1789 if (!panelName && context) 1790 panelName = context.panelName; 1791 1792 // Check if the panel type of the suggested panel supports the object, and if so, go with it. 1793 if (panelName) 1794 { 1795 var panelType = Firebug.getPanelType(panelName); 1796 if (panelSupportsObject(panelType, object, context)) 1797 return panelType.prototype.name; 1798 } 1799 1800 // The suggested name didn't pan out, so search for the panel type with the 1801 // most specific level of support. 1802 return getBestPanelSupportingObject(object, context); 1803 } 1804 1805 function getBestPanelSupportingObject(object, context) 1806 { 1807 var bestLevel = 0; 1808 var bestPanel = null; 1809 1810 for (var i = 0; i < Firebug.panelTypes.length; ++i) 1811 { 1812 var panelType = Firebug.panelTypes[i]; 1813 if (!panelType.prototype.parentPanel) 1814 { 1815 var level = panelSupportsObject(panelType, object, context); 1816 if (!bestLevel || (level && (level > bestLevel) )) 1817 { 1818 bestLevel = level; 1819 bestPanel = panelType; 1820 } 1821 1822 if (FBTrace.DBG_PANELS) 1823 FBTrace.sysout("chrome.getBestPanelName panelType: " + panelType.prototype.name + 1824 " level: " + level + " bestPanel: " + 1825 (bestPanel ? bestPanel.prototype.name : "null") + 1826 " bestLevel: " + bestLevel); 1827 } 1828 } 1829 1830 return bestPanel ? bestPanel.prototype.name : null; 1831 } 1832 1833 function getBestSidePanelName(sidePanelName, panelTypes) 1834 { 1835 if (sidePanelName) 1836 { 1837 // Verify, that the suggested panel name is in the acceptable list. 1838 for (var i = 0; i < panelTypes.length; ++i) 1839 { 1840 if (panelTypes[i].prototype.name == sidePanelName) 1841 return sidePanelName; 1842 } 1843 } 1844 1845 // Default to the first panel type in the list. 1846 return panelTypes.length ? panelTypes[0].prototype.name : null; 1847 } 1848 1849 // ********************************************************************************************* // 1850 // Event listeners 1851 1852 function browser1Loaded() 1853 { 1854 if (FBTrace.DBG_INITIALIZE) 1855 FBTrace.sysout("browse1Loaded\n"); 1856 1857 var browser1 = panelBar1.browser; 1858 var browser2 = panelBar2.browser; 1859 Events.removeEventListener(browser1, "load", browser1Loaded, true); 1860 1861 browser1.contentDocument.title = "Firebug Main Panel"; 1862 browser1.complete = true; 1863 1864 if (browser1.complete && browser2.complete) 1865 { 1866 // initializeUI() is executed asynchronously (solves issue 3442) 1867 // The problem has been introduced (for an unknown reason) by revision R12210 1868 setTimeout(function() { 1869 // chrome bound into this scope 1870 FirebugChrome.initializeUI(); 1871 }); 1872 } 1873 1874 if (FBTrace.DBG_INITIALIZE) 1875 FBTrace.sysout("browse1Loaded complete\n"); 1876 } 1877 1878 function browser2Loaded() 1879 { 1880 if (FBTrace.DBG_INITIALIZE) 1881 FBTrace.sysout("browse2Loaded\n"); 1882 1883 var browser1 = panelBar1.browser; 1884 var browser2 = panelBar2.browser; 1885 Events.removeEventListener(browser2, "load", browser2Loaded, true); 1886 1887 browser2.contentDocument.title = "Firebug Side Panel"; 1888 browser2.complete = true; 1889 1890 if (browser1.complete && browser2.complete) 1891 { 1892 // See browser1Loaded for more info. 1893 setTimeout(function() { 1894 // chrome bound into this scope 1895 FirebugChrome.initializeUI(); 1896 }); 1897 } 1898 1899 if (FBTrace.DBG_INITIALIZE) 1900 FBTrace.sysout("browse2Loaded complete\n"); 1901 } 1902 1903 function onBlur(event) 1904 { 1905 // XXXjjb: this seems like a waste: called continuously to clear possible highlight I guess. 1906 // XXXhh: Is this really necessary? I disabled it for now as this was preventing me 1907 // to show highlights on focus 1908 //Firebug.Inspector.highlightObject(null, Firebug.currentContext); 1909 } 1910 1911 function onSelectLocation(event) 1912 { 1913 var locationList = FirebugChrome.getElementById("fbLocationList"); 1914 var location = locationList.repObject; 1915 1916 FirebugChrome.navigate(location); 1917 } 1918 1919 function onSelectingPanel(event) 1920 { 1921 var panel = panelBar1.selectedPanel; 1922 var panelName = panel ? panel.name : null; 1923 1924 if (FBTrace.DBG_PANELS) 1925 FBTrace.sysout("chrome.onSelectingPanel=" + panelName + " Firebug.currentContext=" + 1926 (Firebug.currentContext ? Firebug.currentContext.getName() : "undefined")); 1927 1928 if (Firebug.currentContext) 1929 { 1930 Firebug.currentContext.previousPanelName = Firebug.currentContext.panelName; 1931 Firebug.currentContext.panelName = panelName; 1932 1933 Firebug.currentContext.sidePanelName = 1934 Firebug.currentContext.sidePanelNames && 1935 panelName in Firebug.currentContext.sidePanelNames 1936 ? Firebug.currentContext.sidePanelNames[panelName] 1937 : null; 1938 } 1939 1940 if (panel) 1941 panel.navigate(panel.location); 1942 1943 // Hide all toolbars now. It's a responsibility of the new selected panel to show 1944 // those toolbars, that are necessary. This avoids the situation when a naughty panel 1945 // doesn't clean up its toolbars. This must be done before 'showPanel' is dispatched, 1946 // where the visibility of the BON buttons is managed. 1947 var toolbar = FirebugChrome.$("fbToolbarInner"); 1948 var child = toolbar.firstChild; 1949 while (child) 1950 { 1951 Dom.collapse(child, true); 1952 child = child.nextSibling; 1953 } 1954 1955 // Those extensions that don't use XUL overlays (i.e. bootstrapped extensions) 1956 // can provide toolbar buttons throug Firebug APIs. 1957 var panelToolbar = FirebugChrome.$("fbPanelToolbar"); 1958 Dom.eraseNode(panelToolbar); 1959 1960 if (panel) 1961 { 1962 // get buttons from current panel 1963 var buttons; 1964 if (panel.getPanelToolbarButtons) 1965 buttons = panel.getPanelToolbarButtons(); 1966 1967 if (!buttons) 1968 buttons = []; 1969 1970 Events.dispatch(Firebug.uiListeners, "onGetPanelToolbarButtons", [panel, buttons]); 1971 1972 for (var i=0; i<buttons.length; ++i) 1973 Toolbar.createToolbarButton(panelToolbar, buttons[i]); 1974 1975 Dom.collapse(panelToolbar, buttons.length == 0); 1976 } 1977 1978 // Calling Firebug.showPanel causes dispatching 'showPanel' to all modules. 1979 var browser = panel ? panel.context.browser : Firefox.getCurrentBrowser(); 1980 Firebug.showPanel(browser, panel); 1981 1982 // Synchronize UI around panels. Execute the sync after 'showPanel' so the logic 1983 // can decide whether to display separators or not. 1984 // xxxHonza: The command line should be synced here as well. 1985 Firebug.chrome.syncLocationList(); 1986 Firebug.chrome.syncStatusPath(); 1987 1988 //xxxjjb: unfortunately the Stack side panel depends on the status path (sync after.) 1989 Firebug.chrome.syncSidePanels(); 1990 } 1991 1992 function onMouseScroll(event) 1993 { 1994 if (Events.isControlAlt(event)) 1995 { 1996 Events.cancelEvent(event); 1997 Firebug.Options.changeTextSize(-event.detail); 1998 } 1999 } 2000 2001 function onSelectedSidePanel(event) 2002 { 2003 var sidePanel = panelBar2.selectedPanel; 2004 if (Firebug.currentContext) 2005 { 2006 var panelName = Firebug.currentContext.panelName; 2007 if (panelName) 2008 { 2009 var sidePanelName = sidePanel ? sidePanel.name : null; 2010 Firebug.currentContext.sidePanelNames[panelName] = sidePanelName; 2011 } 2012 } 2013 2014 if (FBTrace.DBG_PANELS) 2015 FBTrace.sysout("chrome.onSelectedSidePanel name=" + 2016 (sidePanel ? sidePanel.name : "undefined")); 2017 2018 var panel = panelBar1.selectedPanel; 2019 if (panel && sidePanel) 2020 sidePanel.select(panel.selection); 2021 2022 var browser = sidePanel ? sidePanel.context.browser : Firefox.getCurrentBrowser(); 2023 // dispatch to modules 2024 Firebug.showSidePanel(browser, sidePanel); 2025 } 2026 2027 function onPanelMouseOver(event) 2028 { 2029 var object = Firebug.getRepObject(event.target); 2030 if (!object) 2031 return; 2032 2033 var rep = Firebug.getRep(object, Firebug.currentContext); 2034 if (rep) 2035 rep.highlightObject(object, Firebug.currentContext, event.target); 2036 } 2037 2038 function onPanelMouseOut(event) 2039 { 2040 var object = Firebug.getRepObject(event.target); 2041 if (!object) 2042 return; 2043 2044 var rep = Firebug.getRep(object, Firebug.currentContext); 2045 if (rep) 2046 rep.unhighlightObject(object, Firebug.currentContext, event.target); 2047 } 2048 2049 function onPanelClick(event) 2050 { 2051 var repNode = Firebug.getRepNode(event.target); 2052 if (repNode) 2053 { 2054 var object = repNode.repObject; 2055 var rep = Firebug.getRep(object, Firebug.currentContext); 2056 var realObject = rep ? rep.getRealObject(object, Firebug.currentContext) : null; 2057 var realRep = realObject ? Firebug.getRep(realObject, Firebug.currentContext) : rep; 2058 if (!realObject) 2059 realObject = object; 2060 2061 if (Events.isLeftClick(event)) 2062 { 2063 if (Css.hasClass(repNode, "objectLink")) 2064 { 2065 if (realRep) 2066 { 2067 realRep.inspectObject(realObject, Firebug.currentContext); 2068 Events.cancelEvent(event); 2069 } 2070 } 2071 } 2072 } 2073 } 2074 2075 function onPanelMouseDown(event) 2076 { 2077 if (Events.isLeftClick(event)) 2078 { 2079 this.lastMouseDownPosition = {x: event.screenX, y: event.screenY}; 2080 } 2081 else if (Events.isMiddleClick(event, true) && Events.isControlAlt(event)) 2082 { 2083 Events.cancelEvent(event); 2084 Firebug.Options.setTextSize(0); 2085 } 2086 else if (Events.isMiddleClick(event) && Firebug.getRepNode(event.target)) 2087 { 2088 // Prevent auto-scroll when middle-clicking a rep object 2089 Events.cancelEvent(event); 2090 } 2091 } 2092 2093 function onPanelMouseUp(event) 2094 { 2095 if (Events.isLeftClick(event)) 2096 { 2097 var selection = event.target.ownerDocument.defaultView.getSelection(); 2098 var target = selection.focusNode || event.target; 2099 if (selection.focusNode === selection.anchorNode) 2100 { 2101 var editable = Dom.getAncestorByClass(target, "editable"); 2102 if (editable || Css.hasClass(event.target, "inlineExpander")) 2103 { 2104 var selectionData; 2105 var selFO = selection.focusOffset,selAO = selection.anchorOffset; 2106 2107 // selection is collapsed 2108 if (selFO == selAO) 2109 { 2110 var distance = Math.abs(event.screenX - this.lastMouseDownPosition.x) + 2111 Math.abs(event.screenY - this.lastMouseDownPosition.y); 2112 2113 // If mouse has moved far enough, set selection at that point 2114 if (distance > 3) 2115 selectionData = {start: selFO, end: selFO}; 2116 // otherwise leave selectionData undefined to select all text 2117 } 2118 else if (selFO < selAO) 2119 { 2120 selectionData = {start: selFO, end: selAO}; 2121 } 2122 else 2123 { 2124 selectionData = {start: selAO, end: selFO}; 2125 } 2126 2127 if (editable) 2128 { 2129 Firebug.Editor.startEditing(editable, null, null, selectionData); 2130 } 2131 else 2132 { 2133 Firebug.Editor.setSelection(selectionData || {start: selFO, end: selFO}); 2134 selection.removeAllRanges(); 2135 } 2136 2137 Events.cancelEvent(event); 2138 } 2139 } 2140 } 2141 else if (Events.isControlClick(event) || Events.isMiddleClick(event)) 2142 { 2143 var repNode = Firebug.getRepNode(event.target); 2144 if (!repNode) 2145 return; 2146 2147 var object = repNode.repObject; 2148 var rep = Firebug.getRep(object, Firebug.currentContext); 2149 var realObject = rep ? rep.getRealObject(object, Firebug.currentContext) : null; 2150 var realRep = realObject ? Firebug.getRep(realObject, Firebug.currentContext) : rep; 2151 if (!realObject) 2152 realObject = object; 2153 2154 if (!realRep || !realRep.browseObject(realObject, Firebug.currentContext)) 2155 { 2156 if (rep && !(rep != realRep && rep.browseObject(object, Firebug.currentContext))) 2157 { 2158 var panel = Firebug.getElementPanel(event.target); 2159 if (!panel || !panel.browseObject(realObject)) 2160 return; 2161 } 2162 } 2163 Events.cancelEvent(event); 2164 } 2165 } 2166 2167 function onMainTabBoxMouseDown(event) 2168 { 2169 if (Firebug.isInBrowser()) 2170 { 2171 var contentSplitter = FirebugChrome.$("fbContentSplitter"); 2172 // TODO: grab the splitter here. 2173 } 2174 } 2175 2176 function stopBubble(event) 2177 { 2178 event.stopPropagation(); 2179 } 2180 2181 function getRealObject(object) 2182 { 2183 var rep = Firebug.getRep(object, Firebug.currentContext); 2184 var realObject = rep ? rep.getRealObject(object, Firebug.currentContext) : null; 2185 return realObject ? realObject : object; 2186 } 2187 2188 function fatalError(summary, exc) 2189 { 2190 if (typeof(FBTrace) !== undefined) 2191 FBTrace.sysout.apply(FBTrace, arguments); 2192 2193 Components.utils.reportError(summary); 2194 2195 throw exc; 2196 } 2197 2198 return FirebugChrome; 2199 2200 } // end of createFirebugChrome(win) 2201 }; // end of var ChromeFactory object 2202 2203 // ********************************************************************************************* // 2204 2205 return ChromeFactory; 2206 2207 // ********************************************************************************************* // 2208 }); 2209