1 /* See license.txt for terms of usage */ 2 3 var Firebug = null; 4 var FirebugContext = null; 5 6 if(!fbXPCOMUtils) 7 throw "Failed to load FBL"; 8 9 (function() { with (fbXPCOMUtils) { 10 11 // ************************************************************************************************ 12 // Constants 13 14 const Cc = Components.classes; 15 const Ci = Components.interfaces; 16 const nsIWebNavigation = Ci.nsIWebNavigation; 17 18 const LOAD_FLAGS_BYPASS_PROXY = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY; 19 const LOAD_FLAGS_BYPASS_CACHE = nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; 20 const LOAD_FLAGS_NONE = nsIWebNavigation.LOAD_FLAGS_NONE; 21 22 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 23 24 const panelURL = "chrome://firebug/content/panel.html"; 25 26 const statusCropSize = 20; 27 28 const positiveZoomFactors = [1, 1.1, 1.2, 1.3, 1.5, 2, 3]; 29 const negativeZoomFactors = [1, 0.95, 0.8, 0.7, 0.5, 0.2, 0.1]; 30 31 // ************************************************************************************************ 32 // Globals 33 34 var panelBox, panelSplitter, sidePanelDeck, panelBar1, panelBar2, locationList, locationSeparator, 35 panelStatus, panelStatusSeparator; 36 37 var waitingPanelBarCount = 2; 38 39 var inDetachedScope = (window.location == "chrome://firebug/content/firebug.xul"); 40 41 var disabledHead = null; 42 var disabledCaption = null; 43 var enableSiteLink = null; 44 var enableSystemPagesLink = null; 45 var enableAlwaysLink = null; 46 // ************************************************************************************************ 47 48 top.FirebugChrome = 49 { 50 window: window, 51 52 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 53 // Initialization 54 55 panelBarReady: function(panelBar) 56 { 57 try 58 { 59 // Wait until all panelBar bindings are ready before initializing 60 if (--waitingPanelBarCount == 0) 61 this.initialize(); 62 else 63 return false; 64 } 65 catch (exc) 66 { 67 if (FBTrace.sysout) 68 FBTrace.sysout("chrome.panelBarReady FAILS: "+exc, exc); 69 return false; 70 } 71 return true; // the panel bar is ready 72 }, 73 74 initialize: function() 75 { 76 if (window.arguments) 77 var detachArgs = window.arguments[0]; 78 79 if (!detachArgs) 80 detachArgs = {}; 81 82 if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("chrome.initialize w/detachArgs=", detachArgs); 83 84 if (detachArgs.FBL) 85 top.FBL = detachArgs.FBL; 86 else 87 { 88 if (FBTrace.sysout && (!FBL || !FBL.initialize) ) 89 FBTrace.sysout("Firebug is broken, FBL incomplete, if the last function is QI, check lib.js:", FBL); 90 91 FBL.initialize(); 92 } 93 94 if (detachArgs.Firebug) 95 { 96 Firebug = detachArgs.Firebug; 97 FirebugContext = detachArgs.FirebugContext; 98 } 99 else 100 Firebug.initialize(); 101 102 Firebug.internationalizeUI(window.document); 103 104 panelBox = $("fbPanelBox"); 105 panelSplitter = $("fbPanelSplitter"); 106 sidePanelDeck = $("fbSidePanelDeck"); 107 panelBar1 = $("fbPanelBar1"); 108 panelBar2 = $("fbPanelBar2"); 109 locationList = $("fbLocationList"); 110 locationSeparator = $("fbLocationSeparator"); 111 panelStatus = $("fbPanelStatus"); 112 panelStatusSeparator = $("fbStatusSeparator"); 113 114 var browser1 = panelBar1.browser; 115 browser1.addEventListener("load", browser1Loaded, true); 116 117 var browser2 = panelBar2.browser; 118 browser2.addEventListener("load", browser2Loaded, true); 119 120 window.addEventListener("blur", onBlur, true); 121 122 // Initialize Firebug Tools & Firebug Icon menus. 123 var firebugMenuPopup = $("fbFirebugMenuPopup"); 124 this.initializeMenu($("menu_firebug"), firebugMenuPopup); 125 this.initializeMenu($("fbFirebugMenu"), firebugMenuPopup); 126 127 if (FBTrace.DBG_INITIALIZE) 128 FBTrace.sysout("chrome.initialized ", window); 129 }, 130 131 initializeMenu: function(parentMenu, popupMenu) 132 { 133 if (!parentMenu) 134 return; 135 136 if (parentMenu.getAttribute("initialized")) 137 return; 138 139 parentMenu.appendChild(popupMenu.cloneNode(true)); 140 parentMenu.setAttribute("initialized", "true"); 141 }, 142 143 /** 144 * Called when the UI is ready to be initialized, once the panel browsers are loaded. 145 */ 146 initializeUI: function() 147 { 148 // we listen for panel update 149 Firebug.registerUIListener(this); 150 151 try { 152 if (window.arguments) 153 var detachArgs = window.arguments[0]; 154 155 this.applyTextSize(Firebug.textSize); 156 157 var doc1 = panelBar1.browser.contentDocument; 158 doc1.addEventListener("mouseover", onPanelMouseOver, false); 159 doc1.addEventListener("mouseout", onPanelMouseOut, false); 160 doc1.addEventListener("mousedown", onPanelMouseDown, false); 161 doc1.addEventListener("click", onPanelClick, false); 162 panelBar1.addEventListener("selectingPanel", onSelectingPanel, false); 163 164 var doc2 = panelBar2.browser.contentDocument; 165 doc2.addEventListener("mouseover", onPanelMouseOver, false); 166 doc2.addEventListener("mouseout", onPanelMouseOut, false); 167 doc2.addEventListener("click", onPanelClick, false); 168 doc2.addEventListener("mousedown", onPanelMouseDown, false); 169 panelBar2.addEventListener("selectPanel", onSelectedSidePanel, false); 170 171 var mainTabBox = panelBar1.ownerDocument.getElementById("fbPanelBar1-tabBox"); 172 mainTabBox.addEventListener("mousedown", onMainTabBoxMouseDown, false); 173 174 // The side panel bar doesn't care about this event. It must, however, 175 // prevent it from bubbling now that we allow the side panel bar to be 176 // *inside* the main panel bar. 177 function stopBubble(event) { event.stopPropagation(); } 178 panelBar2.addEventListener("selectingPanel", stopBubble, false); 179 180 locationList.addEventListener("selectObject", onSelectLocation, false); 181 182 this.updatePanelBar1(Firebug.panelTypes); 183 184 if (inDetachedScope) 185 this.attachBrowser(FirebugContext); 186 else 187 Firebug.initializeUI(detachArgs); 188 189 } catch (exc) { 190 FBTrace.sysout("chrome.initializeUI fails "+exc, exc); 191 } 192 }, 193 194 shutdown: function() 195 { 196 if (FBTrace.DBG_INITIALIZE || !panelBar1) 197 FBTrace.sysout("chrome.shutdown entered for "+window.location+"\n"); 198 199 var doc1 = panelBar1.browser.contentDocument; 200 doc1.removeEventListener("mouseover", onPanelMouseOver, false); 201 doc1.removeEventListener("mouseout", onPanelMouseOut, false); 202 doc1.removeEventListener("mousedown", onPanelMouseDown, false); 203 doc1.removeEventListener("click", onPanelClick, false); 204 205 var doc2 = panelBar2.browser.contentDocument; 206 doc2.removeEventListener("mouseover", onPanelMouseOver, false); 207 doc2.removeEventListener("mouseout", onPanelMouseOut, false); 208 doc2.removeEventListener("mousedown", onPanelMouseDown, false); 209 doc2.removeEventListener("click", onPanelClick, false); 210 211 var mainTabBox = panelBar1.ownerDocument.getElementById("fbPanelBar1-tabBox"); 212 mainTabBox.removeEventListener("mousedown", onMainTabBoxMouseDown, false); 213 214 locationList.removeEventListener("selectObject", onSelectLocation, false); 215 216 window.removeEventListener("blur", onBlur, true); 217 218 Firebug.unregisterUIListener(this); 219 220 if (inDetachedScope) 221 this.undetach(); 222 else 223 Firebug.shutdown(); 224 }, 225 226 updateOption: function(name, value) 227 { 228 if (panelBar1.selectedPanel) 229 panelBar1.selectedPanel.updateOption(name, value); 230 if (panelBar2.selectedPanel) 231 panelBar2.selectedPanel.updateOption(name, value); 232 233 if (name == "textSize") 234 this.applyTextSize(value); 235 if (name =="omitObjectPathStack") 236 this.obeyOmitObjectPathStack(value); 237 }, 238 239 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 240 241 attachBrowser: function(context) // XXXjjb context == (FirebugContext || null) and inDetachedScope == true 242 { 243 if (FBTrace.DBG_ACTIVATION) 244 FBTrace.sysout("chrome.attachBrowser with inDetachedScope="+inDetachedScope+" context="+context 245 +" context==FirebugContext: "+(context==FirebugContext)+" in window: "+window.location); 246 247 if (inDetachedScope) // then we are initializing in external window 248 { 249 Firebug.setChrome(this, "detached"); // 1.4 250 251 var browser = context ? context.browser : this.getCurrentBrowser(); 252 Firebug.showContext(browser, context); 253 254 if (FBTrace.DBG_WINDOWS) 255 FBTrace.sysout("attachBrowser inDetachedScope in Firebug.chrome.window: "+Firebug.chrome.window.location); 256 } 257 258 }, 259 260 undetach: function() 261 { 262 var detachedChrome = Firebug.chrome; 263 Firebug.setChrome(Firebug.originalChrome, "minimized"); 264 265 Firebug.showBar(false); 266 Firebug.resetTooltip(); 267 268 // when we are done here the window.closed will be true so we don't want to hang on to the ref. 269 detachedChrome.window = "This is detached chrome!"; 270 }, 271 272 disableOff: function(collapse) 273 { 274 FBL.collapse($("fbCloseButton"), collapse); // disable/enable this button in the Firebug.chrome window. 275 }, 276 277 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 278 279 getBrowsers: function() 280 { 281 return Firebug.tabBrowser.browsers; 282 }, 283 284 getCurrentBrowser: function() 285 { 286 return Firebug.tabBrowser.selectedBrowser; 287 }, 288 289 getCurrentURI: function() 290 { 291 try 292 { 293 return Firebug.tabBrowser.currentURI; 294 } 295 catch (exc) 296 { 297 return null; 298 } 299 }, 300 301 getPanelDocument: function(panelType) 302 { 303 if (!panelType.prototype.parentPanel) 304 return panelBar1.browser.contentDocument; 305 else 306 return panelBar2.browser.contentDocument; 307 }, 308 309 getPanelBrowser: function(panel) 310 { 311 if (!panel.parentPanel) 312 return panelBar1.browser; 313 else 314 return panelBar2.browser; 315 }, 316 317 savePanels: function() 318 { 319 var path = this.writePanels(panelBar1.browser.contentDocument); 320 $("fbStatusText").setAttribute("value", path); 321 if (FBTrace.DBG_PANELS) 322 FBTrace.sysout("Wrote panels to "+path+"\n"); 323 }, 324 325 writePanels: function(doc) 326 { 327 var serializer = new XMLSerializer(); 328 var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"] 329 .createInstance(Components.interfaces.nsIFileOutputStream); 330 var file = Components.classes["@mozilla.org/file/directory_service;1"] 331 .getService(Components.interfaces.nsIProperties) 332 .get("TmpD", Components.interfaces.nsIFile); 333 file.append("firebug"); // extensions sub-directory 334 file.append("panelSave.html"); 335 file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); 336 foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate 337 serializer.serializeToStream(doc, foStream, ""); // rememeber, doc is the DOM tree 338 foStream.close(); 339 return file.path; 340 }, 341 342 updatePanelBar1: function(panelTypes) // part of initializeUI 343 { 344 var mainPanelTypes = []; 345 for (var i = 0; i < panelTypes.length; ++i) 346 { 347 var panelType = panelTypes[i]; 348 if (!panelType.prototype.parentPanel && !panelType.hidden) 349 mainPanelTypes.push(panelType); 350 } 351 panelBar1.updatePanels(mainPanelTypes); 352 }, 353 354 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 355 356 getName: function() 357 { 358 return window ? window.location.href : null; 359 }, 360 361 close: function() 362 { 363 if (FBTrace.DBG_INITIALIZE) 364 FBTrace.sysout("chrome.close closing window "+window.location); 365 window.close(); 366 }, 367 368 focus: function() 369 { 370 window.focus(); 371 panelBar1.browser.contentWindow.focus(); 372 }, 373 374 isFocused: function() 375 { 376 var winMediator = CCSV("@mozilla.org/appshell/window-mediator;1", "nsIWindowMediator"); 377 378 return winMediator.getMostRecentWindow(null) == window; 379 }, 380 381 isOpen: function() 382 { 383 return !($("fbContentBox").collapsed); 384 }, 385 386 reload: function(skipCache) 387 { 388 var reloadFlags = skipCache 389 ? LOAD_FLAGS_BYPASS_PROXY | LOAD_FLAGS_BYPASS_CACHE 390 : LOAD_FLAGS_NONE; 391 392 // Make sure the selected tab in the attached browser window is refreshed. 393 var browser = Firebug.chrome.getCurrentBrowser(); 394 browser.firebugReload = true; 395 browser.webNavigation.reload(reloadFlags); 396 397 if (FBTrace.DBG_WINDOWS) 398 FBTrace.sysout("chrome.reload; " + skipCache + ", " + browser.currentURI.spec); 399 }, 400 401 gotoPreviousTab: function() 402 { 403 if (FirebugContext.previousPanelName) 404 this.selectPanel(FirebugContext.previousPanelName); 405 }, 406 407 gotoSiblingTab : function(goRight) 408 { 409 if ($('fbContentBox').collapsed) 410 return; 411 var i, currentIndex = newIndex = -1, currentPanel = this.getSelectedPanel(), newPanel; 412 var panelTypes = Firebug.getMainPanelTypes(FirebugContext); 413 /*get current panel's index (is there a simpler way for this?*/ 414 for (i = 0; i < panelTypes.length; i++) 415 { 416 if (panelTypes[i].prototype.name === currentPanel.name) 417 { 418 currentIndex = i; 419 break; 420 } 421 } 422 if (currentIndex != -1) 423 { 424 newIndex = goRight ? (currentIndex == panelTypes.length - 1 ? 0 : ++currentIndex) : (currentIndex == 0 ? panelTypes.length - 1 : --currentIndex); 425 newPanel = panelTypes[newIndex].prototype; 426 if (newPanel && newPanel.name) 427 { 428 this.selectPanel(newPanel.name); 429 } 430 } 431 }, 432 433 getNextObject: function(reverse) 434 { 435 var panel = FirebugContext.getPanel(FirebugContext.panelName); 436 if (panel) 437 { 438 var item = panelStatus.getItemByObject(panel.selection); 439 if (item) 440 { 441 if (reverse) 442 item = item.previousSibling ? item.previousSibling.previousSibling : null; 443 else 444 item = item.nextSibling ? item.nextSibling.nextSibling : null; 445 446 if (item) 447 return item.repObject; 448 } 449 } 450 }, 451 452 gotoNextObject: function(reverse) 453 { 454 var nextObject = this.getNextObject(reverse); 455 if (nextObject) 456 this.select(nextObject); 457 else 458 beep(); 459 }, 460 461 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 462 // Panels 463 464 navigate: function(object, panelName, sidePanelName) 465 { 466 var panel; 467 if (panelName || sidePanelName) 468 panel = this.selectPanel(panelName, sidePanelName); 469 else 470 panel = this.getSelectedPanel(); 471 472 if (panel) 473 panel.navigate(object); 474 }, 475 476 select: function(object, panelName, sidePanelName, forceUpdate) 477 { 478 if (FBTrace.DBG_PANELS) 479 FBTrace.sysout("chrome.select object:"+object+" panelName:"+panelName+" sidePanelName:"+sidePanelName+" forceUpdate:"+forceUpdate+"\n"); 480 var bestPanelName = getBestPanelName(object, FirebugContext, panelName); 481 var panel = this.selectPanel(bestPanelName, sidePanelName, true); 482 if (panel) 483 panel.select(object, forceUpdate); 484 }, 485 486 selectPanel: function(panelName, sidePanelName, noRefresh) 487 { 488 if (panelName && sidePanelName) 489 FirebugContext.sidePanelNames[panelName] = sidePanelName; 490 491 return panelBar1.selectPanel(panelName, false, noRefresh); // cause panel visibility changes and events 492 }, 493 494 selectSidePanel: function(panelName) 495 { 496 return panelBar2.selectPanel(panelName); 497 }, 498 499 clearPanels: function() 500 { 501 panelBar1.hideSelectedPanel(); 502 panelBar1.selectedPanel = null; 503 panelBar2.selectedPanel = null; 504 }, 505 506 getSelectedPanel: function() 507 { 508 return panelBar1.selectedPanel; 509 }, 510 511 getSelectedSidePanel: function() 512 { 513 return panelBar2.selectedPanel; 514 }, 515 516 switchToPanel: function(context, switchToPanelName) 517 { 518 // Remember the previous panel and bar state so we can revert if the user cancels 519 this.previousPanelName = context.panelName; 520 this.previousSidePanelName = context.sidePanelName; 521 this.previouslyCollapsed = $("fbContentBox").collapsed; 522 this.previouslyFocused = Firebug.isDetached() && this.isFocused(); // TODO previouslyMinimized 523 524 var switchPanel = this.selectPanel(switchToPanelName); 525 if (switchPanel) 526 this.previousObject = switchPanel.selection; 527 528 return switchPanel; 529 }, 530 531 unswitchToPanel: function(context, switchToPanelName, cancelled) 532 { 533 var switchToPanel = context.getPanel(switchToPanelName); 534 535 if (this.previouslyFocused) 536 this.focus(); 537 538 if (cancelled && this.previousPanelName) // revert 539 { 540 if (this.previouslyCollapsed) 541 Firebug.showBar(false); 542 543 if (this.previousPanelName == switchToPanelName) 544 this.select(this.previousObject); 545 else 546 this.selectPanel(this.previousPanelName, this.previousSidePanelName); 547 } 548 else // else stay on the switchToPanel 549 { 550 this.selectPanel(switchToPanelName); 551 if (switchToPanel.selection) 552 this.select(switchToPanel.selection); 553 this.getSelectedPanel().panelNode.focus(); 554 } 555 556 delete this.previousObject; 557 delete this.previousPanelName; 558 delete this.previousSidePanelName; 559 delete this.inspectingChrome; 560 561 return switchToPanel; 562 }, 563 564 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 565 // Location interface provider for binding.xml panelFileList 566 567 getLocationProvider: function() 568 { 569 // a function that returns an object with .getObjectDescription() and .getLocationList() 570 return function getSelectedPanelFromCurrentContext() 571 { 572 return Firebug.chrome.getSelectedPanel(); // panels provide location, use the selected panel 573 } 574 }, 575 576 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 577 // UI Synchronization 578 579 setFirebugContext: function(context) 580 { 581 // This sets the global value of FirebugContext in the window that this chrome is compiled into. 582 // Note that for firebug.xul, the Firebug object is shared across windows, but not FirebugChrome and FirebugContext 583 FirebugContext = context; 584 585 if (FBTrace.DBG_WINDOWS || FBTrace.DBG_DISPATCH) 586 FBTrace.sysout("setFirebugContext "+(FirebugContext?FirebugContext.getName():" **> NULL <** ") + " in "+window.location+" has wrapped: "+(FirebugContext?FirebugContext.wrappedJSObject:"no")); 587 }, 588 589 hidePanel: function() 590 { 591 if (panelBar1.selectedPanel) 592 panelBar1.hideSelectedPanel() 593 594 if (panelBar2.selectedPanel) 595 panelBar2.hideSelectedPanel() 596 }, 597 598 syncPanel: function() 599 { 600 if (FBTrace.DBG_PANELS) FBTrace.sysout("chrome.syncPanel FirebugContext="+ 601 (FirebugContext ? FirebugContext.getName() : "undefined")+"\n"); 602 603 panelStatus.clear(); 604 605 if (FirebugContext) 606 { 607 var panelName = FirebugContext.panelName 608 ? FirebugContext.panelName 609 : Firebug.defaultPanelName; 610 611 // Make HTML panel the default panel, which is displayed 612 // to the user the very first time. 613 if (!panelName || !Firebug.getPanelType(panelName)) 614 panelName = "html"; 615 616 this.syncMainPanels(); 617 panelBar1.selectPanel(panelName, true); 618 } 619 else 620 { 621 panelBar1.selectPanel(null, true); 622 } 623 624 if (Firebug.isDetached()) 625 this.syncTitle(); 626 }, 627 628 syncMainPanels: function() 629 { 630 var panelTypes = Firebug.getMainPanelTypes(FirebugContext); 631 panelBar1.updatePanels(panelTypes); 632 }, 633 634 syncSidePanels: function() 635 { 636 var panelTypes = Firebug.getSidePanelTypes(FirebugContext, panelBar1.selectedPanel); 637 panelBar2.updatePanels(panelTypes); 638 639 if (FirebugContext && FirebugContext.sidePanelNames) 640 { 641 var sidePanelName = FirebugContext.sidePanelNames[FirebugContext.panelName]; 642 sidePanelName = getBestSidePanelName(sidePanelName, panelTypes); 643 panelBar2.selectPanel(sidePanelName, true); 644 } 645 else 646 panelBar2.selectPanel(null); 647 648 sidePanelDeck.selectedPanel = panelBar2; 649 FBL.collapse(sidePanelDeck, !panelBar2.selectedPanel); 650 FBL.collapse(panelSplitter, !panelBar2.selectedPanel); 651 }, 652 653 syncTitle: function() 654 { 655 if (FirebugContext) 656 { 657 var title = FirebugContext.getTitle(); 658 window.document.title = FBL.$STRF("WindowTitle", [title]); 659 } 660 else 661 window.document.title = FBL.$STR("Firebug"); 662 }, 663 664 focusLocationList: function() 665 { 666 locationList.popup.showPopup(locationList, -1, -1, "popup", "bottomleft", "topleft"); 667 }, 668 669 syncLocationList: function() 670 { 671 var panel = panelBar1.selectedPanel; 672 if (panel && panel.location) 673 { 674 locationList.location = panel.location; 675 FBL.collapse(locationSeparator, false); 676 FBL.collapse(locationList, false); 677 } 678 else 679 { 680 FBL.collapse(locationSeparator, true); 681 FBL.collapse(locationList, true); 682 } 683 }, 684 685 clearStatusPath: function() 686 { 687 panelStatus.clear(); 688 }, 689 690 syncStatusPath: function() 691 { 692 var panel = panelBar1.selectedPanel; 693 if (!panel || (panel && !panel.selection)) 694 { 695 panelStatus.clear(); 696 } 697 else 698 { 699 var path = panel.getObjectPath(panel.selection); 700 if (!path || !path.length) 701 { 702 FBL.hide(panelStatusSeparator, true); 703 panelStatus.clear(); 704 } 705 else 706 { 707 FBL.hide(panelStatusSeparator, false); 708 709 if (panel.name != panelStatus.lastPanelName) 710 panelStatus.clear(); 711 712 panelStatus.lastPanelName = panel.name; 713 714 // If the object already exists in the list, just select it and keep the path 715 var selection = panel.selection; 716 var existingItem = panelStatus.getItemByObject(panel.selection); 717 if (existingItem) 718 panelStatus.selectItem(existingItem); 719 else 720 { 721 panelStatus.clear(); 722 723 for (var i = 0; i < path.length; ++i) 724 { 725 var object = path[i]; 726 727 var rep = Firebug.getRep(object); 728 var objectTitle = rep.getTitle(object, FirebugContext); 729 730 var title = FBL.cropMultipleLines(objectTitle, statusCropSize); 731 panelStatus.addItem(title, object, rep, panel.statusSeparator); 732 } 733 734 panelStatus.selectObject(panel.selection); 735 } 736 } 737 } 738 }, 739 740 toggleOrient: function() 741 { 742 var panelPane = $("fbPanelPane"); 743 panelSplitter.orient = panelPane.orient 744 = panelPane.orient == "vertical" ? "horizontal" : "vertical"; 745 var option = $('menu_toggleOrient').getAttribute("option"); 746 Firebug.setPref(Firebug.prefDomain, option, panelPane.orient != "vertical"); 747 }, 748 749 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 750 751 addTab: function(context, url, title, parentPanel) 752 { 753 context.addPanelType(url, title, parentPanel); 754 if (context == FirebugContext) 755 { 756 if (parentPanel) 757 { 758 var currentPanel = this.getSelectedPanel(); 759 if (currentPanel && parentPanel == currentPanel.name) 760 this.syncSidePanels(); 761 } 762 else 763 { 764 this.syncMainPanels(); 765 } 766 } 767 }, 768 769 removeTab: function(context, url) 770 { 771 context.removePanelType(url); 772 }, 773 774 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 775 776 getGlobalAttribute: function(id, name) 777 { 778 var elt = $(id); 779 return elt.getAttribute(name); 780 }, 781 782 setGlobalAttribute: function(id, name, value) 783 { 784 var elt = $(id); 785 if (elt) 786 { 787 if (value == null) 788 elt.removeAttribute(name); 789 else 790 elt.setAttribute(name, value); 791 } 792 793 if (Firebug.externalChrome) 794 Firebug.externalChrome.setGlobalAttribute(id, name, value); 795 }, 796 797 798 setChromeDocumentAttribute: function(id, name, value) 799 { 800 // Call as Firebug.chrome.setChromeDocumentAttribute() to set attributes in another window. 801 var elt = $(id); 802 if (elt) 803 elt.setAttribute(name, value); 804 }, 805 806 keyCodeListen: function(key, filter, listener, capture) 807 { 808 if (!filter) 809 filter = FBL.noKeyModifiers; 810 811 var keyCode = KeyEvent["DOM_VK_"+key]; 812 813 function fn(event) 814 { 815 if (event.keyCode == keyCode && (!filter || filter(event))) 816 { 817 listener(); 818 FBL.cancelEvent(event); 819 } 820 } 821 822 window.addEventListener("keypress", fn, capture); 823 824 return [fn, capture]; 825 }, 826 827 keyListen: function(ch, filter, listener, capture) 828 { 829 if (!filter) 830 filter = FBL.noKeyModifiers; 831 832 var charCode = ch.charCodeAt(0); 833 834 function fn(event) 835 { 836 if (event.charCode == charCode && (!filter || filter(event))) 837 { 838 listener(); 839 FBL.cancelEvent(event); 840 } 841 } 842 843 window.addEventListener("keypress", fn, capture); 844 845 return [fn, capture]; 846 }, 847 848 keyIgnore: function(listener) 849 { 850 window.removeEventListener("keypress", listener[0], listener[1]); 851 }, 852 853 $: function(id) 854 { 855 return $(id); 856 }, 857 858 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 859 860 applyTextSize: function(value) 861 { 862 var zoom = value >= 0 ? positiveZoomFactors[value] : negativeZoomFactors[Math.abs(value)]; 863 864 panelBar1.browser.markupDocumentViewer.textZoom = zoom; 865 panelBar2.browser.markupDocumentViewer.textZoom = zoom; 866 }, 867 868 obeyOmitObjectPathStack: function(value) 869 { 870 FBL.hide(panelStatus, (value?true:false)); 871 }, 872 873 getPanelStatusElements: function() 874 { 875 return panelStatus; 876 }, 877 878 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 879 // UI Event Listeners uilisteners or "panelListeners" 880 881 onPanelNavigate: function(object, panel) 882 { 883 this.syncLocationList(); 884 }, 885 886 onObjectSelected: function(object, panel) 887 { 888 if (panel == panelBar1.selectedPanel) 889 { 890 this.syncStatusPath(); 891 892 var sidePanel = panelBar2.selectedPanel; 893 if (sidePanel) 894 sidePanel.select(object); 895 } 896 }, 897 898 onApplyDecorator: function(sourceBox) // called on setTimeout after sourceBox viewport has been repainted 899 { 900 }, 901 902 onViewportChange: function(sourceLink) // called on scrollTo, passing in the selected line 903 { 904 }, 905 906 showUI: function(browser, context) // called when the Firebug UI comes up in browser or detached 907 { 908 }, 909 910 hideUI: function(browser, context) // called when the Firebug UI comes down; context may be null 911 { 912 }, 913 914 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 915 916 onOptionsShowing: function(popup) 917 { 918 for (var child = popup.firstChild; child; child = child.nextSibling) 919 { 920 if (child.localName == "menuitem") 921 { 922 var option = child.getAttribute("option"); 923 if (option) 924 { 925 var checked = false; 926 if (option == "profiling") 927 checked = fbs.profiling; 928 else 929 checked = Firebug.getPref(Firebug.prefDomain, option); 930 931 child.setAttribute("checked", checked); 932 } 933 } 934 } 935 }, 936 937 onToggleOption: function(menuitem) 938 { 939 var option = menuitem.getAttribute("option"); 940 var checked = menuitem.getAttribute("checked") == "true"; 941 942 Firebug.setPref(Firebug.prefDomain, option, checked); 943 }, 944 945 onContextShowing: function(event) 946 { 947 // xxxHonza: This context-menu support can be used even in separate window, which 948 // doesn't contain the FBUI (panels). 949 //if (!panelBar1.selectedPanel) 950 // return false; 951 952 var popup = $("fbContextMenu"); 953 var target = document.popupNode; 954 var panel = target ? Firebug.getElementPanel(target) : null; 955 956 if (!panel) 957 panel = panelBar1 ? panelBar1.selectedPanel : null; // the event must be on our chrome not inside the panel 958 959 FBL.eraseNode(popup); 960 961 // Make sure the Copy action is only available if there is actually someting 962 // selected in the panel. 963 var sel = target.ownerDocument.defaultView.getSelection(); 964 if (!this.contextMenuObject && !$("cmd_copy").getAttribute("disabled") && !sel.isCollapsed) 965 { 966 var menuitem = FBL.createMenuItem(popup, {label: "Copy"}); 967 menuitem.setAttribute("command", "cmd_copy"); 968 } 969 970 var object; 971 if (this.contextMenuObject) 972 object = this.contextMenuObject; 973 else if (target && target.ownerDocument == document) 974 object = Firebug.getRepObject(target); 975 else if (target && panel) 976 object = panel.getPopupObject(target); 977 else if (target) 978 object = Firebug.getRepObject(target); // xxxHonza: What about a node from different document? Is that OK? 979 980 this.contextMenuObject = null; 981 982 var rep = Firebug.getRep(object); 983 var realObject = rep ? rep.getRealObject(object, FirebugContext) : null; 984 var realRep = realObject ? Firebug.getRep(realObject) : null; 985 986 if (FBTrace.DBG_OPTIONS) 987 FBTrace.sysout("chrome.onContextShowing object:"+object+" rep: "+rep+" realObject: "+realObject+" realRep:"+realRep+"\n"); 988 989 if (realObject && realRep) 990 { 991 // 1. Add the custom menu items from the realRep 992 var menu = realRep.getContextMenuItems(realObject, target, FirebugContext); 993 if (menu) 994 { 995 for (var i = 0; i < menu.length; ++i) 996 FBL.createMenuItem(popup, menu[i]); 997 } 998 } 999 1000 if (object && rep && rep != realRep) 1001 { 1002 // 1. Add the custom menu items from the original rep 1003 var items = rep.getContextMenuItems(object, target, FirebugContext); 1004 if (items) 1005 { 1006 for (var i = 0; i < items.length; ++i) 1007 FBL.createMenuItem(popup, items[i]); 1008 } 1009 } 1010 1011 // 1. Add the custom menu items from the panel 1012 if (panel) 1013 { 1014 var items = panel.getContextMenuItems(realObject, target); 1015 if (items) 1016 { 1017 for (var i = 0; i < items.length; ++i) 1018 FBL.createMenuItem(popup, items[i]); 1019 } 1020 } 1021 1022 // 2. Add the inspect menu items 1023 if (realObject && rep && rep.inspectable) 1024 { 1025 var separator = null; 1026 1027 var items = this.getInspectMenuItems(realObject); 1028 for (var i = 0; i < items.length; ++i) 1029 { 1030 if (popup.firstChild && !separator) 1031 separator = FBL.createMenuSeparator(popup); 1032 1033 FBL.createMenuItem(popup, items[i]); 1034 } 1035 } 1036 1037 if (!popup.firstChild) 1038 return false; 1039 }, 1040 1041 onEditorsShowing: function(popup) // TODO move to Firebug.Editors module in editors.js 1042 { 1043 var editors = Firebug.registeredEditors; 1044 if ( editors.length > 0 ) 1045 { 1046 var lastChild = popup.lastChild; 1047 FBL.eraseNode(popup); 1048 var disabled = (!FirebugContext); 1049 for( var i = 0; i < editors.length; ++i ) 1050 { 1051 if (editors[i] == "-") 1052 { 1053 FBL.createMenuItem(popup, "-"); 1054 continue; 1055 } 1056 var item = {label: editors[i].label, image: editors[i].image, 1057 nol10n: true, disabled: disabled }; 1058 var menuitem = FBL.createMenuItem(popup, item); 1059 menuitem.setAttribute("command", "cmd_openInEditor"); 1060 menuitem.value = editors[i].id; 1061 } 1062 FBL.createMenuItem(popup, "-"); 1063 popup.appendChild(lastChild); 1064 } 1065 }, 1066 1067 getInspectMenuItems: function(object) 1068 { 1069 var items = []; 1070 1071 // Domplate (+ support for context menus) can be used even in separate 1072 // windows when FirebugContext doesn't have to be defined. 1073 if (!FirebugContext) 1074 return items; 1075 1076 for (var i = 0; i < Firebug.panelTypes.length; ++i) 1077 { 1078 var panelType = Firebug.panelTypes[i]; 1079 if (!panelType.prototype.parentPanel 1080 && panelType.prototype.name != FirebugContext.panelName 1081 && panelSupportsObject(panelType, object)) 1082 { 1083 var panelName = panelType.prototype.name; 1084 1085 var title = Firebug.getPanelTitle(panelType); 1086 var label = FBL.$STRF("InspectInTab", [title]); 1087 1088 var command = bindFixed(this.select, this, object, panelName); 1089 items.push({label: label, command: command, nol10n: true}); 1090 } 1091 } 1092 1093 return items; 1094 }, 1095 1096 onTooltipShowing: function(event) 1097 { 1098 // xxxHonza: This tooltip support can be used even in separate window, which 1099 // doesn't contain the FBUI (panels). 1100 //if (!panelBar1.selectedPanel) 1101 // return false; 1102 1103 var tooltip = $("fbTooltip"); 1104 var target = document.tooltipNode; 1105 1106 var panel = target ? Firebug.getElementPanel(target) : null; 1107 1108 var object; 1109 /* XXXjjb This causes the Script panel to show the function body over and over. We need to clear it at least, 1110 * but really we need to understand why the tooltip should show the context menu object at all. 1111 * One thing the contextMenuObject supports is peeking at function bodies when stopped a breakpoint. 1112 * That case could be supported with clearing the contextMenuObject, but we don't know if that breaks 1113 * something else. So maybe a popupMenuObject should be set on the context if that is what we want to support 1114 * The other complication is that there seems to be another tooltip. 1115 if (this.contextMenuObject) 1116 { 1117 object = this.contextMenuObject; 1118 FBTrace.sysout("tooltip by contextMenuObject"); 1119 } 1120 else*/ 1121 if (target && target.ownerDocument == document) 1122 object = Firebug.getRepObject(target); 1123 else if (panel) 1124 object = panel.getTooltipObject(target); 1125 1126 var rep = object ? Firebug.getRep(object) : null; 1127 object = rep ? rep.getRealObject(object, FirebugContext) : null; 1128 rep = object ? Firebug.getRep(object) : null; 1129 1130 if (object && rep) 1131 { 1132 var label = rep.getTooltip(object, FirebugContext); 1133 if (label) 1134 { 1135 tooltip.setAttribute("label", label); 1136 return true; 1137 } 1138 } 1139 1140 if (FBL.hasClass(target, 'noteInToolTip')) 1141 FBL.setClass(tooltip, 'noteInToolTip'); 1142 else 1143 FBL.removeClass(tooltip, 'noteInToolTip'); 1144 1145 if (target.hasAttribute("title")) 1146 { 1147 tooltip.setAttribute("label", target.getAttribute("title")); 1148 return true; 1149 } 1150 1151 return false; 1152 }, 1153 1154 openAboutDialog: function() 1155 { 1156 var extensionManager = CCSV("@mozilla.org/extensions/manager;1", "nsIExtensionManager"); 1157 openDialog("chrome://mozapps/content/extensions/about.xul", "", 1158 "chrome,centerscreen,modal", "urn:mozilla:item:firebug@software.joehewitt.com", extensionManager.datasource); 1159 }, 1160 1161 breakOnNext: function(context, event) 1162 { 1163 // Avoid bubbling from associated options. 1164 if (event.target.id != "cmd_breakOnNext") 1165 return; 1166 1167 if (!context) 1168 { 1169 if (FBTrace.DBG_BP) 1170 FBTrace.sysout("Firebug chrome: breakOnNext with no context??"); 1171 return; 1172 } 1173 1174 var panel = panelBar1.selectedPanel; 1175 1176 if (FBTrace.DBG_BP) 1177 FBTrace.sysout("Firebug chrome: breakOnNext for panel " + 1178 (panel ? panel.name : "NO panel"), panel); 1179 1180 if (panel && panel.breakable) 1181 Firebug.Breakpoint.toggleBreakOnNext(panel); 1182 }, 1183 }; 1184 1185 // ************************************************************************************************ 1186 // Local Helpers 1187 1188 function panelSupportsObject(panelType, object) 1189 { 1190 if (panelType) 1191 { 1192 try { 1193 // This tends to throw exceptions often because some objects are weird 1194 return panelType.prototype.supportsObject(object) 1195 } catch (exc) {} 1196 } 1197 1198 return 0; 1199 } 1200 1201 function getBestPanelName(object, context, panelName) 1202 { 1203 if (!panelName) 1204 panelName = context.panelName; 1205 1206 // Check if the suggested panel name supports the object, and if so, go with it 1207 if (panelName) 1208 { 1209 panelType = Firebug.getPanelType(panelName); 1210 if (panelSupportsObject(panelType, object)) 1211 return panelType.prototype.name; 1212 } 1213 1214 // The suggested name didn't pan out, so search for the panel type with the 1215 // most specific level of support 1216 1217 var bestLevel = 0; 1218 var bestPanel = null; 1219 1220 for (var i = 0; i < Firebug.panelTypes.length; ++i) 1221 { 1222 var panelType = Firebug.panelTypes[i]; 1223 if (!panelType.prototype.parentPanel) 1224 { 1225 var level = panelSupportsObject(panelType, object); 1226 if (!bestLevel || (level && (level > bestLevel) )) 1227 { 1228 bestLevel = level; 1229 bestPanel = panelType; 1230 } 1231 if (FBTrace.DBG_PANELS) 1232 FBTrace.sysout("chrome.getBestPanelName panelType: "+panelType.prototype.name+" level: "+level+" bestPanel: "+ (bestPanel ? bestPanel.prototype.name : "null")+" bestLevel: "+bestLevel+"\n"); 1233 } 1234 } 1235 1236 return bestPanel ? bestPanel.prototype.name : null; 1237 } 1238 1239 function getBestSidePanelName(sidePanelName, panelTypes) 1240 { 1241 if (sidePanelName) 1242 { 1243 // Verify that the suggested panel name is in the acceptable list 1244 for (var i = 0; i < panelTypes.length; ++i) 1245 { 1246 if (panelTypes[i].prototype.name == sidePanelName) 1247 return sidePanelName; 1248 } 1249 } 1250 1251 // Default to the first panel type in the list 1252 return panelTypes.length ? panelTypes[0].prototype.name : null; 1253 } 1254 1255 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1256 // Event listeners 1257 1258 function browser1Loaded() 1259 { 1260 if (FBTrace.DBG_INITIALIZE) 1261 FBTrace.sysout("browse1Loaded\n"); 1262 var browser1 = panelBar1.browser; 1263 browser1.removeEventListener("load", browser1Loaded, true); 1264 1265 browser1.contentDocument.title = "Firebug Main Panel"; 1266 browser1Loaded.complete = true; 1267 1268 if (browser1Loaded.complete && browser2Loaded.complete) 1269 FirebugChrome.initializeUI(); 1270 } 1271 1272 function browser2Loaded() 1273 { 1274 if (FBTrace.DBG_INITIALIZE) 1275 FBTrace.sysout("browse2Loaded\n"); 1276 var browser2 = panelBar2.browser; 1277 browser2.removeEventListener("load", browser2Loaded, true); 1278 1279 browser2.contentDocument.title = "Firebug Side Panel"; 1280 browser2Loaded.complete = true; 1281 1282 if (browser1Loaded.complete && browser2Loaded.complete) 1283 FirebugChrome.initializeUI(); // the chrome bound into this scope 1284 1285 if (FBTrace.DBG_INITIALIZE) 1286 FBTrace.sysout("browse2Loaded complete\n"); 1287 } 1288 1289 function onBlur(event) 1290 { 1291 // XXXjjb this seems like a waste: called continuously to clear possible highlight I guess. 1292 // XXXhh Is this really necessary? I disabled it for now as this was preventing me to show highlights on focus 1293 //Firebug.Inspector.highlightObject(null, FirebugContext); 1294 } 1295 1296 function onSelectLocation(event) 1297 { 1298 var location = locationList.repObject; 1299 FirebugChrome.navigate(location); 1300 } 1301 1302 function onSelectingPanel(event) 1303 { 1304 var panel = panelBar1.selectedPanel; 1305 var panelName = panel ? panel.name : null; 1306 if (FBTrace.DBG_PANELS) 1307 FBTrace.sysout("chrome.onSelectingPanel="+panelName+" FirebugContext="+(FirebugContext?FirebugContext.getName():"undefined")+"\n"); 1308 1309 if (FirebugContext) 1310 { 1311 FirebugContext.previousPanelName = FirebugContext.panelName; 1312 FirebugContext.panelName = panelName; 1313 1314 FirebugContext.sidePanelName = 1315 FirebugContext.sidePanelNames && panelName in FirebugContext.sidePanelNames 1316 ? FirebugContext.sidePanelNames[panelName] 1317 : null; 1318 } 1319 1320 if (panel) 1321 { 1322 panel.navigate(panel.location); 1323 Firebug.chrome.syncLocationList(); 1324 Firebug.chrome.syncSidePanels(); 1325 Firebug.chrome.syncStatusPath(); 1326 1327 Firebug.showPanel(panel.context.browser, panel); 1328 } 1329 else 1330 { 1331 var browser = FirebugChrome.getCurrentBrowser(); 1332 Firebug.showPanel(browser, null); 1333 } 1334 } 1335 1336 function onSelectedSidePanel(event) 1337 { 1338 var sidePanel = panelBar2.selectedPanel; 1339 if (FirebugContext) 1340 { 1341 var panelName = FirebugContext.panelName; 1342 if (panelName) 1343 { 1344 var sidePanelName = sidePanel ? sidePanel.name : null; 1345 FirebugContext.sidePanelNames[panelName] = sidePanelName; 1346 } 1347 else 1348 { 1349 if (FBTrace.DBG_ERRORS) 1350 FBTrace.sysout("onSelectedSidePanel FirebugContext has no panelName: ",FirebugContext); 1351 } 1352 } 1353 if (FBTrace.DBG_PANELS) FBTrace.sysout("chrome.onSelectedSidePanel name="+(sidePanel?sidePanel.name:"undefined")+"\n"); 1354 1355 var panel = panelBar1.selectedPanel; 1356 if (panel && sidePanel) 1357 sidePanel.select(panel.selection); 1358 1359 var browser = sidePanel ? sidePanel.context.browser : FirebugChrome.getCurrentBrowser(); 1360 Firebug.showSidePanel(browser, sidePanel); // dispatch to modules 1361 } 1362 1363 function onPanelMouseOver(event) 1364 { 1365 var object = Firebug.getRepObject(event.target); 1366 if (object) 1367 { 1368 var realObject = getRealObject(object); 1369 if (realObject) 1370 Firebug.Inspector.highlightObject(realObject, FirebugContext); 1371 } 1372 } 1373 1374 function onPanelMouseOut(event) 1375 { 1376 Firebug.Inspector.highlightObject(null); 1377 } 1378 1379 function onPanelClick(event) 1380 { 1381 var repNode = Firebug.getRepNode(event.target); 1382 if (repNode) 1383 { 1384 var object = repNode.repObject; 1385 var rep = Firebug.getRep(object); 1386 var realObject = rep ? rep.getRealObject(object, FirebugContext) : null; 1387 var realRep = realObject ? Firebug.getRep(realObject) : rep; 1388 if (!realObject) 1389 realObject = object; 1390 1391 if (FBL.isLeftClick(event)) 1392 { 1393 if (FBL.hasClass(repNode, "objectLink")) 1394 { 1395 if (realRep) 1396 { 1397 realRep.inspectObject(realObject, FirebugContext); 1398 FBL.cancelEvent(event); 1399 } 1400 } 1401 } 1402 else if (FBL.isControlClick(event) || FBL.isMiddleClick(event)) 1403 { 1404 if (!realRep || !realRep.browseObject(realObject, FirebugContext)) 1405 { 1406 if (rep && !(rep != realRep && rep.browseObject(object, FirebugContext))) 1407 { 1408 var panel = Firebug.getElementPanel(event.target); 1409 if (!panel || !panel.browseObject(realObject)) 1410 return; 1411 } 1412 } 1413 FBL.cancelEvent(event); 1414 } 1415 } 1416 } 1417 1418 function onPanelMouseDown(event) 1419 { 1420 if (FBL.isLeftClick(event)) 1421 { 1422 var editable = FBL.getAncestorByClass(event.target, "editable"); 1423 if (editable) 1424 { 1425 Firebug.Editor.startEditing(editable); 1426 FBL.cancelEvent(event); 1427 } 1428 } 1429 else if (FBL.isMiddleClick(event) && Firebug.getRepNode(event.target)) 1430 { 1431 // Prevent auto-scroll when middle-clicking a rep object 1432 FBL.cancelEvent(event); 1433 } 1434 } 1435 1436 function onMainTabBoxMouseDown(event) 1437 { 1438 if (Firebug.isInBrowser()) 1439 { 1440 var contentSplitter = Firebug.chrome.$("fbContentSplitter"); 1441 if (FBTrace.DBG_ERRORS) 1442 FBTrace.sysout("onMainTabBoxMouseDown ", event); 1443 // TODO: grab the splitter here. 1444 } 1445 } 1446 1447 function getRealObject(object) 1448 { 1449 var rep = Firebug.getRep(object); 1450 var realObject = rep ? rep.getRealObject(object, FirebugContext) : null; 1451 return realObject ? realObject : object; 1452 } 1453 1454 1455 // ************************************************************************************************ 1456 // Utils (duplicated from lib.js) 1457 1458 function $(id, doc) 1459 { 1460 if (doc) 1461 return doc.getElementById(id); 1462 else 1463 return document.getElementById(id); 1464 } 1465 1466 function cloneArray(array, fn) 1467 { 1468 var newArray = []; 1469 1470 for (var i = 0; i < array.length; ++i) 1471 newArray.push(array[i]); 1472 1473 return newArray; 1474 } 1475 1476 function bindFixed() 1477 { 1478 var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); 1479 return function() { return fn.apply(object, args); } 1480 } 1481 1482 }})(); 1483 1484 // ************************************************************************************************ 1485 1486 // XXXjoe This horrible hack works around a focus bug in Firefox which is caused when 1487 // the HTML Validator extension and Firebug are installed. It causes the keyboard to 1488 // behave erratically when typing, and the only solution I've found is to delay 1489 // the initialization of HTML Validator by overriding this function with a timeout. 1490 // XXXrobc Do we still need this? Does this extension even exist anymore? 1491 if (top.hasOwnProperty('TidyBrowser')) 1492 { 1493 var prev = TidyBrowser.prototype.updateStatusBar; 1494 TidyBrowser.prototype.updateStatusBar = function() 1495 { 1496 var self = this, args = arguments; 1497 setTimeout(function() 1498 { 1499 prev.apply(self, args); 1500 }); 1501 } 1502 } 1503 1504 // ************************************************************************************************ 1505 1506 function dddx() 1507 { 1508 Firebug.Console.logFormatted(arguments); 1509 } 1510 1511 1512 1513