home *** CD-ROM | disk | FTP | other *** search
/ PC World 2003 May / PCWorld_2003-05_cd.bin / Komunik / phoenix / chrome / browser.jar / content / browser / browser.js < prev    next >
Text File  |  2002-12-07  |  143KB  |  4,229 lines

  1.  
  2. const NS_ERROR_MODULE_NETWORK = 2152398848;
  3. const NS_NET_STATUS_READ_FROM = NS_ERROR_MODULE_NETWORK + 8;
  4. const NS_NET_STATUS_WROTE_TO  = NS_ERROR_MODULE_NETWORK + 9;
  5.  
  6. const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
  7.  
  8. const MAX_HISTORY_MENU_ITEMS = 15;
  9. var gRDF = null;
  10. var gGlobalHistory = null;
  11. var gURIFixup = null;
  12. var gReportButton = null;
  13. var gCharsetMenu = null;
  14. var gLastBrowserCharset = null;
  15. var gPrevCharset = null;
  16. var gURLBar = null;
  17. var gProxyButton = null;
  18. var gProxyFavIcon = null;
  19. var gProxyDeck = null;
  20. var gNavigatorBundle = null;
  21. var gIsLoadingBlank = false;
  22. var gLastValidURLStr = "";
  23. var gLastValidURL = null;
  24. var gHaveUpdatedToolbarState = false;
  25. var gClickSelectsAll = true;
  26. var gIgnoreFocus = false;
  27. var gIgnoreClick = false;
  28. var gToolbarMode = "icons";
  29. var gIconSize = "";
  30. var gMustLoadSidebar = false;
  31. var gProgressMeterPanel = null;
  32. var gProgressCollapseTimer = null;
  33. var gPrefService = null;
  34. var appCore = null;
  35. var gBrowser = null;
  36.  
  37. // Global variable that holds the nsContextMenu instance.
  38. var gContextMenu = null;
  39.  
  40. var gPrintSettingsAreGlobal = true;
  41. var gSavePrintSettings = true;
  42. var gPrintSettings = null;
  43. var gChromeState = null; // chrome state before we went into print preview
  44. var gOldCloseHandler = null; // close handler before we went into print preview
  45. var gInPrintPreviewMode = false;
  46. var gWebProgress = null;
  47. var gFormHistory = null;
  48.  
  49. const dlObserver = {
  50.   observe: function(subject, topic, state) {  
  51.     if (topic != "dl-start") return;
  52.     var open = gPrefService.getBoolPref("browser.download.openSidebar");
  53.     if (open) {
  54.       var sidebar = document.getElementById("sidebar-box");
  55.       if (sidebar.hidden || (sidebar.getAttribute("sidebarcommand") != "viewDownloadsSidebar"))
  56.         toggleSidebar("viewDownloadsSidebar");
  57.     }
  58.   }
  59. };
  60.   
  61. /**
  62. * We can avoid adding multiple load event listeners and save some time by adding
  63. * one listener that calls all real handlers.
  64. */
  65.  
  66. function loadEventHandlers(event)
  67. {
  68.   // Filter out events that are not about the document load we are interested in
  69.   if (event.originalTarget == _content.document) {
  70.     UpdateBookmarksLastVisitedDate(event);
  71.     checkForDirectoryListing();
  72.     charsetLoadListener(event);
  73.   }
  74. }
  75.  
  76. /**
  77.  * Determine whether or not the content area is displaying a page with frames,
  78.  * and if so, toggle the display of the 'save frame as' menu item.
  79.  **/
  80. function getContentAreaFrameCount()
  81. {
  82.   var saveFrameItem = document.getElementById("menu_saveFrame");
  83.   if (!content || !_content.frames.length || !isDocumentFrame(document.commandDispatcher.focusedWindow))
  84.     saveFrameItem.setAttribute("hidden", "true");
  85.   else
  86.     saveFrameItem.removeAttribute("hidden");
  87. }
  88.  
  89. //////////////////////////////// BOOKMARKS ////////////////////////////////////
  90.  
  91. function UpdateBookmarksLastVisitedDate(event)
  92. {
  93.   var url = getWebNavigation().currentURI.spec;
  94.   if (url) {
  95.     // if the URL is bookmarked, update its "Last Visited" date
  96.     BMSVC.updateLastVisitedDate(url, _content.document.characterSet);
  97.   }
  98. }
  99.  
  100. function HandleBookmarkIcon(iconURL, addFlag)
  101. {
  102.   var url = getWebNavigation().currentURI.spec
  103.   if (url) {
  104.     // update URL with new icon reference
  105.     if (addFlag)
  106.       BMSVC.updateBookmarkIcon(url, iconURL);
  107.     else
  108.       BMSVC.removeBookmarkIcon(url, iconURL);
  109.   }
  110. }
  111.  
  112. function getHomePage()
  113. {
  114.   var url;
  115.   try {
  116.     url = gPrefService.getComplexValue("browser.startup.homepage",
  117.                                Components.interfaces.nsIPrefLocalizedString).data;
  118.   } catch (e) {
  119.   }
  120.  
  121.   // use this if we can't find the pref
  122.   if (!url) {
  123.     var navigatorRegionBundle = document.getElementById("bundle_browser_region");
  124.     url = navigatorRegionBundle.getString("homePageDefault");
  125.   }
  126.  
  127.   return url;
  128. }
  129.  
  130. function UpdateBackForwardButtons()
  131. {
  132.   var backBroadcaster = document.getElementById("Browser:Back");
  133.   var forwardBroadcaster = document.getElementById("Browser:Forward");
  134.   
  135.   var webNavigation = gBrowser.webNavigation;
  136.  
  137.   // Avoid setting attributes on broadcasters if the value hasn't changed!
  138.   // Remember, guys, setting attributes on elements is expensive!  They
  139.   // get inherited into anonymous content, broadcast to other widgets, etc.!
  140.   // Don't do it if the value hasn't changed! - dwh
  141.  
  142.   var backDisabled = backBroadcaster.hasAttribute("disabled");
  143.   var forwardDisabled = forwardBroadcaster.hasAttribute("disabled");
  144.   if (backDisabled == webNavigation.canGoBack) {
  145.     if (backDisabled)
  146.       backBroadcaster.removeAttribute("disabled");
  147.     else
  148.       backBroadcaster.setAttribute("disabled", true);
  149.   }
  150.   
  151.   if (forwardDisabled == webNavigation.canGoForward) {
  152.     if (forwardDisabled)
  153.       forwardBroadcaster.removeAttribute("disabled");
  154.     else
  155.       forwardBroadcaster.setAttribute("disabled", true);
  156.   }
  157. }
  158.  
  159. function UpdatePageReport(event)
  160. {
  161.   if (!gReportButton)
  162.     gReportButton = document.getElementById("page-report-button");
  163.  
  164.   if (gBrowser.mCurrentBrowser.pageReport) {
  165.     gReportButton.setAttribute("blocked", "true");
  166.     if (gPrefService && gPrefService.getBoolPref("privacy.popups.firstTime")) {
  167.       displayPageReportFirstTime();
  168.  
  169.       // Now set the pref.
  170.       gPrefService.setBoolPref("privacy.popups.firstTime", "false");
  171.     }
  172.   }
  173.   else
  174.     gReportButton.removeAttribute("blocked");
  175. }
  176.  
  177. function Startup()
  178. {
  179.   gBrowser = document.getElementById("content");
  180.  
  181.   var uriToLoad = null;
  182.   // Check for window.arguments[0]. If present, use that for uriToLoad.
  183.   if ("arguments" in window && window.arguments.length >= 1 && window.arguments[0])
  184.     uriToLoad = window.arguments[0];
  185.   gIsLoadingBlank = uriToLoad == "about:blank";
  186.  
  187.   if (!gIsLoadingBlank) {
  188.     prepareForStartup();
  189.   }
  190.  
  191.   // only load url passed in when we're not page cycling
  192.  
  193.   if (uriToLoad && !gIsLoadingBlank) {
  194.     if ("arguments" in window && window.arguments.length >= 3)
  195.       loadURI(uriToLoad, window.arguments[2]);
  196.     else
  197.       loadOneOrMoreURIs(uriToLoad);
  198.   }
  199.  
  200.   if (window.opener) {
  201.     var openerSidebarBox = window.opener.document.getElementById("sidebar-box");
  202.     if (!openerSidebarBox.hidden) {
  203.       var sidebarBox = document.getElementById("sidebar-box");
  204.       var sidebarTitle = document.getElementById("sidebar-title");
  205.       sidebarTitle.setAttribute("value", window.opener.document.getElementById("sidebar-title").getAttribute("value"));
  206.       sidebarBox.setAttribute("width", openerSidebarBox.boxObject.width);
  207.       var sidebarCmd = openerSidebarBox.getAttribute("sidebarcommand");
  208.       sidebarBox.setAttribute("sidebarcommand", sidebarCmd);
  209.       sidebarBox.setAttribute("src", window.opener.document.getElementById("sidebar").getAttribute("src"));
  210.       gMustLoadSidebar = true;
  211.       sidebarBox.hidden = false;
  212.       var sidebarSplitter = document.getElementById("sidebar-splitter");
  213.       sidebarSplitter.hidden = false;
  214.       document.getElementById(sidebarCmd).setAttribute("checked", "true");
  215.     }
  216.   }
  217.   else {
  218.     var box = document.getElementById("sidebar-box");
  219.     if (box.hasAttribute("sidebarcommand")) { 
  220.       var cmd = box.getAttribute("sidebarcommand");
  221.       if (cmd != "") {
  222.         gMustLoadSidebar = true;
  223.         box.hidden = false;
  224.         var sidebarSplitter = document.getElementById("sidebar-splitter");
  225.         sidebarSplitter.hidden = false;
  226.         document.getElementById(cmd).setAttribute("checked", "true");
  227.       }
  228.     }
  229.   }
  230.  
  231.   setTimeout(delayedStartup, 0);
  232. }
  233.  
  234. function prepareForStartup()
  235. {
  236.   gURLBar = document.getElementById("urlbar");  
  237.   gNavigatorBundle = document.getElementById("bundle_browser");
  238.   gProgressMeterPanel = document.getElementById("statusbar-progresspanel");
  239.   gBrowser.addEventListener("DOMUpdatePageReport", UpdatePageReport, false);
  240.  
  241.   var webNavigation;
  242.   try {
  243.     // Create the browser instance component.
  244.     appCore = Components.classes["@mozilla.org/appshell/component/browser/instance;1"]
  245.                         .createInstance(Components.interfaces.nsIBrowserInstance);
  246.     if (!appCore)
  247.       throw "couldn't create a browser instance";
  248.  
  249.     webNavigation = getWebNavigation();
  250.     if (!webNavigation)
  251.       throw "no XBL binding for browser";
  252.   } catch (e) {
  253.     alert("Error launching browser window:" + e);
  254.     window.close(); // Give up.
  255.     return;
  256.   }
  257.  
  258.   // initialize observers and listeners
  259.   window.XULBrowserWindow = new nsBrowserStatusHandler();
  260.   window.browserContentListener =
  261.     new nsBrowserContentListener(window, gBrowser);
  262.  
  263.   // set default character set if provided
  264.   if ("arguments" in window && window.arguments.length > 1 && window.arguments[1]) {
  265.     if (window.arguments[1].indexOf("charset=") != -1) {
  266.       var arrayArgComponents = window.arguments[1].split("=");
  267.       if (arrayArgComponents) {
  268.         //we should "inherit" the charset menu setting in a new window
  269.         getMarkupDocumentViewer().defaultCharacterSet = arrayArgComponents[1];
  270.       }
  271.     }
  272.   }
  273.  
  274.   // Initialize browser instance..
  275.   appCore.setWebShellWindow(window);
  276.  
  277.   // Wire up session and global history before any possible
  278.   // progress notifications for back/forward button updating
  279.   webNavigation.sessionHistory = Components.classes["@mozilla.org/browser/shistory;1"]
  280.                                            .createInstance(Components.interfaces.nsISHistory);
  281.  
  282.   // wire up global history.  the same applies here.
  283.   var globalHistory = Components.classes["@mozilla.org/browser/global-history;1"]
  284.                                 .getService(Components.interfaces.nsIGlobalHistory);
  285.   gBrowser.docShell.QueryInterface(Components.interfaces.nsIDocShellHistory).globalHistory = globalHistory;
  286.  
  287.   const selectedBrowser = gBrowser.selectedBrowser;
  288.   if (selectedBrowser.securityUI)
  289.     selectedBrowser.securityUI.init(selectedBrowser.contentWindow);
  290.  
  291.   // hook up UI through progress listener
  292.   gBrowser.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
  293. }
  294.  
  295. function delayedStartup()
  296. {
  297.   if (gIsLoadingBlank)
  298.     prepareForStartup();
  299.  
  300.   // loads the services
  301.   initServices();
  302.   initBMService();
  303.   
  304.   gBrowser.addEventListener("load", function(evt) { setTimeout(loadEventHandlers, 0, evt); }, true);
  305.  
  306.   window.addEventListener("keypress", ctrlNumberTabSelection, true);
  307.  
  308.   if (gMustLoadSidebar) {
  309.     var sidebar = document.getElementById("sidebar");
  310.     var sidebarBox = document.getElementById("sidebar-box");
  311.     sidebar.setAttribute("src", sidebarBox.getAttribute("src"));
  312.   }
  313.  
  314.   // Perform default browser checking (after window opens).
  315.   try {
  316.     var dialogShown = Components.classes["@mozilla.org/winhooks;1"]
  317.                     .getService(Components.interfaces.nsIWindowsHooks)
  318.                     .checkSettings(window);
  319.   } catch(e) {
  320.   }
  321.  
  322.   // now load bookmarks after a delay
  323.   BMSVC.ReadBookmarks();
  324.   var bt = document.getElementById("bookmarks-toolbar");
  325.   if (bt && "toolbar" in bt)
  326.     bt.toolbar.builder.rebuild();       
  327.  
  328.   // called when we go into full screen, even if it is 
  329.   // initiated by a web page script
  330.   window.addEventListener("fullscreen", onFullScreen, false);
  331.  
  332.   var element;
  333.   if (gIsLoadingBlank && gURLBar && !gURLBar.hidden && !gURLBar.parentNode.parentNode.collapsed)
  334.     element = gURLBar;
  335.   else
  336.     element = _content;
  337.  
  338.   // This is a redo of the fix for jag bug 91884
  339.   var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  340.                      .getService(Components.interfaces.nsIWindowWatcher);
  341.   if (window == ww.activeWindow) {
  342.     element.focus();
  343.   } else {
  344.     // set the element in command dispatcher so focus will restore properly
  345.     // when the window does become active
  346.     if (element instanceof Components.interfaces.nsIDOMElement)
  347.       document.commandDispatcher.focusedElement = element;
  348.     else if (element instanceof Components.interfaces.nsIDOMWindow)
  349.       document.commandDispatcher.focusedWindow = element;
  350.   }
  351.  
  352.   SetPageProxyState("invalid", null);
  353.  
  354.   var toolbox = document.getElementById("navigator-toolbox");
  355.   toolbox.customizeDone = BrowserToolboxCustomizeDone;
  356.  
  357.   gPrefService = Components.classes["@mozilla.org/preferences-service;1"]
  358.                               .getService(Components.interfaces.nsIPrefService);
  359.   gPrefService = gPrefService.getBranch(null);
  360.  
  361.   var observerService = Components.classes["@mozilla.org/observer-service;1"]
  362.                                   .getService(Components.interfaces.nsIObserverService);
  363.   observerService.addObserver(dlObserver, "dl-start", false);
  364.  
  365.   updateHomeTooltip();
  366. }
  367.  
  368. function Shutdown()
  369. {
  370.   try {
  371.     gBrowser.removeProgressListener(window.XULBrowserWindow);
  372.   } catch (ex) {
  373.   }
  374.  
  375.   var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
  376.   var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
  377.   var enumerator = windowManagerInterface.getEnumerator(null);
  378.   enumerator.getNext();
  379.   if (!enumerator.hasMoreElements()) {
  380.     document.persist("sidebar-box", "sidebarcommand");
  381.     document.persist("sidebar-box", "width");
  382.     document.persist("sidebar-box", "src");
  383.     document.persist("sidebar-title", "value");
  384.   }
  385.  
  386.   var service = Components.classes["@mozilla.org/observer-service;1"]
  387.                             .getService(Components.interfaces.nsIObserverService);
  388.   service.removeObserver(dlObserver, "dl-start");
  389.   service = null;
  390.  
  391.   window.XULBrowserWindow.destroy();
  392.   window.XULBrowserWindow = null;
  393.  
  394.   window.browserContentListener.close();
  395.   // Close the app core.
  396.   if (appCore)
  397.     appCore.close();
  398. }
  399.  
  400. function ctrlNumberTabSelection(event)
  401. {
  402.   if (event.altKey && event.keyCode == KeyEvent.DOM_VK_RETURN) {
  403.     // Don't let winxp beep on ALT+ENTER, since the URL bar uses it.
  404.     event.preventDefault();
  405.     return;
  406.   } 
  407.  
  408.   if (!event.ctrlKey)
  409.     return;
  410.  
  411.   var index = event.charCode - 49;
  412.   if (index < 0 || index > 8)
  413.     return;
  414.  
  415.   if (index >= gBrowser.mTabContainer.childNodes.length)
  416.     return;
  417.  
  418.   var oldTab = gBrowser.selectedTab;
  419.   var newTab = gBrowser.mTabContainer.childNodes[index];
  420.   if (newTab != oldTab) {
  421.     oldTab.selected = false;
  422.     gBrowser.selectedTab = newTab;
  423.   }
  424.  
  425.   event.preventDefault();
  426.   event.preventBubble();
  427.   event.preventCapture();
  428.   event.stopPropagation();
  429. }
  430.  
  431. function gotoHistoryIndex(aEvent)
  432. {
  433.   var index = aEvent.target.getAttribute("index");
  434.   if (!index)
  435.     return false;
  436.   try {
  437.     getWebNavigation().gotoIndex(index);
  438.   }
  439.   catch(ex) {
  440.     return false;
  441.   }
  442.   return true;
  443.  
  444. }
  445.  
  446. function BrowserBack()
  447. {
  448.   try {
  449.     getWebNavigation().goBack();
  450.   }
  451.   catch(ex) {
  452.   }
  453. }
  454.  
  455. function BrowserForward()
  456. {
  457.   try {
  458.     getWebNavigation().goForward();
  459.   }
  460.   catch(ex) {
  461.   }
  462. }
  463.  
  464. function BrowserBackMenu(event)
  465. {
  466.   return FillHistoryMenu(event.target, "back");
  467. }
  468.  
  469. function BrowserForwardMenu(event)
  470. {
  471.   return FillHistoryMenu(event.target, "forward");
  472. }
  473.  
  474. function BrowserStop()
  475. {
  476.   try {
  477.     const stopFlags = nsIWebNavigation.STOP_ALL;
  478.     getWebNavigation().stop(stopFlags);
  479.   }
  480.   catch(ex) {
  481.   }
  482. }
  483.  
  484. function BrowserReload()
  485. {
  486.   const reloadFlags = nsIWebNavigation.LOAD_FLAGS_NONE;
  487.   return BrowserReloadWithFlags(reloadFlags);
  488. }
  489.  
  490. function BrowserReloadSkipCache()
  491. {
  492.   // Bypass proxy and cache.
  493.   const reloadFlags = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
  494.   return BrowserReloadWithFlags(reloadFlags);
  495. }
  496.  
  497. function BrowserHome()
  498. {
  499.   var homePage = getHomePage();
  500.   loadOneOrMoreURIs(homePage);
  501. }
  502.  
  503. function loadOneOrMoreURIs(aURIString)
  504. {
  505.   if (aURIString.indexOf("|") != -1) {
  506.     var urls = aURIString.split("|");
  507.     loadURI(urls[0]);
  508.     for (var i = 1; i < urls.length; ++i)
  509.       gBrowser.addTab(urls[i]);
  510.   }
  511.   else
  512.     loadURI(aURIString);
  513. }
  514.  
  515. function constructGoMenuItem(goMenu, beforeItem, url, title)
  516. {
  517.   const kXULNS = 
  518.     "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  519.  
  520.   var menuitem = document.createElementNS(kXULNS, "menuitem");
  521.   menuitem.setAttribute("url", url);
  522.   menuitem.setAttribute("label", title);
  523.   goMenu.insertBefore(menuitem, beforeItem);
  524.   return menuitem;
  525. }
  526.  
  527. function onGoMenuHidden()
  528. {
  529.   setTimeout("destroyGoMenuItems(document.getElementById('goPopup'));", 0);
  530. }
  531.  
  532. function destroyGoMenuItems(goMenu) {
  533.   var startSeparator = document.getElementById("startHistorySeparator");
  534.   var endSeparator = document.getElementById("endHistorySeparator");
  535.   endSeparator.hidden = true;
  536.  
  537.   // Destroy the items.
  538.   var destroy = false;
  539.   for (var i = 0; i < goMenu.childNodes.length; i++) {
  540.     var item = goMenu.childNodes[i];
  541.     if (item == endSeparator)
  542.       break;
  543.  
  544.     if (destroy) {
  545.       i--;
  546.       goMenu.removeChild(item);
  547.     }
  548.  
  549.     if (item == startSeparator)
  550.       destroy = true;
  551.   }
  552. }
  553.  
  554. function updateGoMenu(goMenu)
  555. {
  556.   // In case the timer didn't fire.
  557.   destroyGoMenuItems(goMenu);
  558.  
  559.   var history = document.getElementById("hiddenHistoryTree");
  560.   
  561.   if (history.hidden) {
  562.     history.hidden = false;
  563.     var globalHistory = Components.classes["@mozilla.org/browser/global-history;1"]
  564.                                   .getService(Components.interfaces.nsIGlobalHistory);
  565.     var dataSource = globalHistory.QueryInterface(Components.interfaces.nsIRDFDataSource);
  566.     history.database.AddDataSource(dataSource);
  567.   }
  568.  
  569.   if (!history.ref)
  570.     history.ref = "NC:HistoryRoot";
  571.   
  572.   var count = history.treeBoxObject.view.rowCount;
  573.   if (count > 10)
  574.     count = 10;
  575.  
  576.   if (count == 0)
  577.     return;
  578.  
  579.   const NC_NS     = "http://home.netscape.com/NC-rdf#";
  580.  
  581.   if (!gRDF)
  582.      gRDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  583.                       .getService(Components.interfaces.nsIRDFService);
  584.  
  585.   var builder = history.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder);
  586.   
  587.   var beforeItem = document.getElementById("endHistorySeparator");
  588.   
  589.   var nameResource = gRDF.GetResource(NC_NS + "Name");
  590.  
  591.   var endSep = beforeItem;
  592.   var showSep = false;
  593.  
  594.   for (var i = count-1; i >= 0; i--) {
  595.     var res = builder.getResourceAtIndex(i);
  596.     var url = res.Value;
  597.     var titleRes = history.database.GetTarget(res, nameResource, true);
  598.     if (!titleRes)
  599.       continue;
  600.  
  601.     showSep = true;
  602.     var titleLiteral = titleRes.QueryInterface(Components.interfaces.nsIRDFLiteral);
  603.     beforeItem = constructGoMenuItem(goMenu, beforeItem, url, titleLiteral.Value);
  604.   }
  605.  
  606.   if (showSep)
  607.     endSep.hidden = false;
  608. }
  609.  
  610. function addGroupmarkAs()
  611. {
  612.   BookmarksUtils.addBookmarkForTabBrowser(gBrowser, true);
  613. }
  614.  
  615. function addBookmarkAs(aBrowser)
  616. {
  617.   const browsers = aBrowser.browsers;
  618.   if (browsers.length > 1)
  619.     BookmarksUtils.addBookmarkForTabBrowser(aBrowser);
  620.   else
  621.     BookmarksUtils.addBookmarkForBrowser(aBrowser.webNavigation, true);
  622. }
  623.  
  624. function openLocation()
  625. {
  626.   if (gURLBar && !gURLBar.parentNode.parentNode.collapsed) {
  627.     gURLBar.focus();
  628.     gURLBar.select();
  629.   }
  630.   else {
  631.     openDialog("chrome://browser/content/openLocation.xul", "_blank", "chrome,modal,titlebar", window);
  632.   }
  633. }
  634.  
  635. function BrowserOpenTab()
  636. {
  637.   if (!gInPrintPreviewMode) {
  638.     gBrowser.selectedTab = gBrowser.addTab('about:blank');
  639.     if (gURLBar)
  640.       setTimeout("gURLBar.focus();", 0); 
  641.   }
  642. }
  643.  
  644. /* Called from the openLocation dialog. This allows that dialog to instruct
  645.    its opener to open a new window and then step completely out of the way.
  646.    Anything less byzantine is causing horrible crashes, rather believably,
  647.    though oddly only on Linux. */
  648. function delayedOpenWindow(chrome,flags,url)
  649. {
  650.   setTimeout("openDialog('"+chrome+"','_blank','"+flags+"','"+url+"')", 10);
  651. }
  652.  
  653. /* Required because the tab needs time to set up its content viewers and get the load of
  654.    the URI kicked off before becoming the active content area. */
  655. function delayedOpenTab(url)
  656. {
  657.   setTimeout(function(aTabElt) { gBrowser.selectedTab = aTabElt; }, 0, gBrowser.addTab(url));
  658. }
  659.  
  660. function BrowserOpenFileWindow()
  661. {
  662.   // Get filepicker component.
  663.   try {
  664.     const nsIFilePicker = Components.interfaces.nsIFilePicker;
  665.     var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  666.     fp.init(window, gNavigatorBundle.getString("openFile"), nsIFilePicker.modeOpen);
  667.     fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText | nsIFilePicker.filterImages |
  668.                      nsIFilePicker.filterXML | nsIFilePicker.filterHTML);
  669.  
  670.     if (fp.show() == nsIFilePicker.returnOK)
  671.       openTopWin(fp.fileURL.spec);
  672.   } catch (ex) {
  673.   }
  674. }
  675.  
  676. function BrowserCloseTabOrWindow()
  677. {
  678.   if (gBrowser.localName == 'tabbrowser' && gBrowser.mTabContainer.childNodes.length > 1) {
  679.     // Just close up a tab.
  680.     gBrowser.removeCurrentTab();
  681.     return;
  682.   }
  683.  
  684.   BrowserCloseWindow();
  685. }
  686.  
  687. function BrowserCloseWindow() 
  688. {
  689.   // This code replicates stuff in Shutdown().  It is here because
  690.   // window.screenX and window.screenY have real values.  We need
  691.   // to fix this eventually but by replicating the code here, we
  692.   // provide a means of saving position (it just requires that the
  693.   // user close the window via File->Close (vs. close box).
  694.   
  695.   // Get the current window position/size.
  696.   var x = window.screenX;
  697.   var y = window.screenY;
  698.   var h = window.outerHeight;
  699.   var w = window.outerWidth;
  700.  
  701.   // Store these into the window attributes (for persistence).
  702.   var win = document.getElementById( "main-window" );
  703.   win.setAttribute( "x", x );
  704.   win.setAttribute( "y", y );
  705.   win.setAttribute( "height", h );
  706.   win.setAttribute( "width", w );
  707.  
  708.   window.close();
  709. }
  710.  
  711. function loadURI(uri, referrer)
  712. {
  713.   try {
  714.     getWebNavigation().loadURI(uri, nsIWebNavigation.LOAD_FLAGS_NONE, referrer, null, null);
  715.   } catch (e) {
  716.   }
  717. }
  718.  
  719. function BrowserLoadURL(aTriggeringEvent)
  720. {
  721.   var url = gURLBar.value;
  722.   if (url.match(/^view-source:/)) {
  723.     BrowserViewSourceOfURL(url.replace(/^view-source:/, ""), null, null);
  724.   } else {
  725.     if (gBrowser.localName == "tabbrowser" &&
  726.         aTriggeringEvent && 'altKey' in aTriggeringEvent &&
  727.         aTriggeringEvent.altKey) {
  728.       _content.focus();
  729.       var t = gBrowser.addTab(url); // open link in new tab
  730.       gBrowser.selectedTab = t;
  731.       gURLBar.value = url;
  732.       event.preventDefault();
  733.       event.preventBubble();
  734.       event.preventCapture();
  735.       event.stopPropagation();
  736.     }
  737.     else  
  738.       loadURI(url);
  739.     _content.focus();
  740.   }
  741. }
  742.  
  743. function getShortcutOrURI(url)
  744. {
  745.   // rjc: added support for URL shortcuts (3/30/1999)
  746.   try {
  747.     var shortcutURL = BMSVC.resolveKeyword(url);
  748.     if (!shortcutURL) {
  749.       // rjc: add support for string substitution with shortcuts (4/4/2000)
  750.       //      (see bug # 29871 for details)
  751.       var aOffset = url.indexOf(" ");
  752.       if (aOffset > 0) {
  753.         var cmd = url.substr(0, aOffset);
  754.         var text = url.substr(aOffset+1);
  755.         shortcutURL = BMSVC.resolveKeyword(cmd);
  756.         if (shortcutURL && text) {
  757.           aOffset = shortcutURL.indexOf("%s");
  758.           if (aOffset >= 0)
  759.             shortcutURL = shortcutURL.substr(0, aOffset) + text + shortcutURL.substr(aOffset+2);
  760.           else
  761.             shortcutURL = null;
  762.         }
  763.       }
  764.     }
  765.  
  766.     if (shortcutURL)
  767.       url = shortcutURL;
  768.  
  769.   } catch (ex) {
  770.   }
  771.   return url;
  772. }
  773.  
  774. function readFromClipboard()
  775. {
  776.   var url;
  777.  
  778.   try {
  779.     // Get clipboard.
  780.     var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
  781.                               .getService(Components.interfaces.nsIClipboard);
  782.  
  783.     // Create tranferable that will transfer the text.
  784.     var trans = Components.classes["@mozilla.org/widget/transferable;1"]
  785.                           .createInstance(Components.interfaces.nsITransferable);
  786.  
  787.     trans.addDataFlavor("text/unicode");
  788.     clipboard.getData(trans, clipboard.kSelectionClipboard);
  789.  
  790.     var data = {};
  791.     var dataLen = {};
  792.     trans.getTransferData("text/unicode", data, dataLen);
  793.  
  794.     if (data) {
  795.       data = data.value.QueryInterface(Components.interfaces.nsISupportsString);
  796.       url = data.data.substring(0, dataLen.value / 2);
  797.     }
  798.   } catch (ex) {
  799.   }
  800.  
  801.   return url;
  802. }
  803.  
  804. function BrowserViewSourceOfDocument(aDocument)
  805. {
  806.   var docCharset;
  807.   var pageCookie;
  808.   var webNav;
  809.  
  810.   // Get the document charset
  811.   docCharset = "charset=" + aDocument.characterSet;
  812.  
  813.   // Get the nsIWebNavigation associated with the document
  814.   try {
  815.       var win;
  816.       var ifRequestor;
  817.  
  818.       // Get the DOMWindow for the requested document.  If the DOMWindow
  819.       // cannot be found, then just use the _content window...
  820.       //
  821.       // XXX:  This is a bit of a hack...
  822.       win = aDocument.defaultView;
  823.       if (win == window) {
  824.         win = _content;
  825.       }
  826.       ifRequestor = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  827.  
  828.       webNav = ifRequestor.getInterface(nsIWebNavigation);
  829.   } catch(err) {
  830.       // If nsIWebNavigation cannot be found, just get the one for the whole
  831.       // window...
  832.       webNav = getWebNavigation();
  833.   }
  834.   //
  835.   // Get the 'PageDescriptor' for the current document. This allows the
  836.   // view-source to access the cached copy of the content rather than
  837.   // refetching it from the network...
  838.   //
  839.   try{
  840.     var PageLoader = webNav.QueryInterface(Components.interfaces.nsIWebPageDescriptor);
  841.  
  842.     pageCookie = PageLoader.currentDescriptor;
  843.   } catch(err) {
  844.     // If no page descriptor is available, just use the view-source URL...
  845.   }
  846.  
  847.   BrowserViewSourceOfURL(webNav.currentURI.spec, docCharset, pageCookie);
  848. }
  849.  
  850. function BrowserViewSourceOfURL(url, charset, pageCookie)
  851. {
  852.   // try to open a view-source window while inheriting the charset (if any)
  853.   openDialog("chrome://browser/content/viewSource.xul",
  854.              "_blank",
  855.              "scrollbars,resizable,chrome,dialog=no",
  856.              url, charset, pageCookie);
  857. }
  858.  
  859. // doc=null for regular page info, doc=owner document for frame info.
  860. function BrowserPageInfo(doc)
  861. {
  862.   window.openDialog("chrome://navigator/content/pageInfo.xul",
  863.                     "_blank",
  864.                     "chrome,dialog=no",
  865.                     doc);
  866. }
  867.  
  868.  
  869. function checkForDirectoryListing()
  870. {
  871.   if ( "HTTPIndex" in _content &&
  872.        _content.HTTPIndex instanceof Components.interfaces.nsIHTTPIndex ) {
  873.     _content.defaultCharacterset = getMarkupDocumentViewer().defaultCharacterSet;
  874.   }
  875. }
  876.  
  877. /**
  878.  * Use Stylesheet functions.
  879.  *     Written by Tim Hill (bug 6782)
  880.  *     Frameset handling by Neil Rashbrook <neil@parkwaycc.co.uk>
  881.  **/
  882. function getStyleSheetArray(frame)
  883. {
  884.   var styleSheets = frame.document.styleSheets;
  885.   var styleSheetsArray = new Array(styleSheets.length);
  886.   for (var i = 0; i < styleSheets.length; i++) {
  887.     styleSheetsArray[i] = styleSheets[i];
  888.   }
  889.   return styleSheetsArray;
  890. }
  891.  
  892. function getAllStyleSheets(frameset)
  893. {
  894.   var styleSheetsArray = getStyleSheetArray(frameset);
  895.   for (var i = 0; i < frameset.frames.length; i++) {
  896.     var frameSheets = getAllStyleSheets(frameset.frames[i]);
  897.     styleSheetsArray = styleSheetsArray.concat(frameSheets);
  898.   }
  899.   return styleSheetsArray;
  900. }
  901.  
  902. function stylesheetFillPopup(menuPopup)
  903. {
  904.   var itemNoOptStyles = menuPopup.firstChild;
  905.   while (itemNoOptStyles.nextSibling)
  906.     menuPopup.removeChild(itemNoOptStyles.nextSibling);
  907.  
  908.   var noOptionalStyles = true;
  909.   var styleSheets = getAllStyleSheets(window._content);
  910.   var currentStyleSheets = [];
  911.  
  912.   for (var i = 0; i < styleSheets.length; ++i) {
  913.     var currentStyleSheet = styleSheets[i];
  914.  
  915.     if (currentStyleSheet.title) {
  916.       if (!currentStyleSheet.disabled)
  917.         noOptionalStyles = false;
  918.  
  919.       var lastWithSameTitle = null;
  920.       if (currentStyleSheet.title in currentStyleSheets)
  921.         lastWithSameTitle = currentStyleSheets[currentStyleSheet.title];
  922.  
  923.       if (!lastWithSameTitle) {
  924.         var menuItem = document.createElement("menuitem");
  925.         menuItem.setAttribute("type", "radio");
  926.         menuItem.setAttribute("label", currentStyleSheet.title);
  927.         menuItem.setAttribute("data", currentStyleSheet.title);
  928.         menuItem.setAttribute("checked", !currentStyleSheet.disabled);
  929.         menuPopup.appendChild(menuItem);
  930.         currentStyleSheets[currentStyleSheet.title] = menuItem;
  931.       } else {
  932.         if (currentStyleSheet.disabled)
  933.           lastWithSameTitle.removeAttribute("checked");
  934.       }
  935.     }
  936.   }
  937.   itemNoOptStyles.setAttribute("checked", noOptionalStyles);
  938. }
  939.  
  940. function stylesheetInFrame(frame, title) {
  941.   var docStyleSheets = frame.document.styleSheets;
  942.  
  943.   for (var i = 0; i < docStyleSheets.length; ++i) {
  944.     if (docStyleSheets[i].title == title)
  945.       return true;
  946.   }
  947.   return false;
  948. }
  949.  
  950. function stylesheetSwitchFrame(frame, title) {
  951.   var docStyleSheets = frame.document.styleSheets;
  952.  
  953.   for (var i = 0; i < docStyleSheets.length; ++i) {
  954.     var docStyleSheet = docStyleSheets[i];
  955.  
  956.     if (docStyleSheet.title)
  957.       docStyleSheet.disabled = (docStyleSheet.title != title);
  958.     else if (docStyleSheet.disabled)
  959.       docStyleSheet.disabled = false;
  960.   }
  961. }
  962.  
  963. function stylesheetSwitchAll(frameset, title) {
  964.   if (!title || stylesheetInFrame(frameset, title)) {
  965.     stylesheetSwitchFrame(frameset, title);
  966.   }
  967.   for (var i = 0; i < frameset.frames.length; i++) {
  968.     stylesheetSwitchAll(frameset.frames[i], title);
  969.   }
  970. }
  971.  
  972. function URLBarFocusHandler(aEvent, aElt)
  973. {
  974.   if (gIgnoreFocus)
  975.     gIgnoreFocus = false;
  976.   else if (gClickSelectsAll)
  977.     aElt.select();
  978. }
  979.  
  980. function URLBarMouseDownHandler(aEvent, aElt)
  981. {
  982.   if (aElt.hasAttribute("focused")) {
  983.     gIgnoreClick = true;
  984.   } else {
  985.     gIgnoreFocus = true;
  986.     gIgnoreClick = false;
  987.     aElt.setSelectionRange(0, 0);
  988.   }
  989. }
  990.  
  991. function URLBarClickHandler(aEvent, aElt)
  992. {
  993.   if (!gIgnoreClick && gClickSelectsAll && aElt.selectionStart == aElt.selectionEnd)
  994.     aElt.select();
  995. }
  996.  
  997. // If "ESC" is pressed in the url bar, we replace the urlbar's value with the url of the page
  998. // and highlight it, unless it is about:blank, where we reset it to "".
  999. function handleURLBarRevert()
  1000. {
  1001.   var url = getWebNavigation().currentURI.spec;
  1002.   var throbberElement = document.getElementById("navigator-throbber");
  1003.  
  1004.   var isScrolling = gURLBar.popupOpen;
  1005.   
  1006.   // don't revert to last valid url unless page is NOT loading
  1007.   // and user is NOT key-scrolling through autocomplete list
  1008.   if ((!throbberElement || !throbberElement.hasAttribute("busy")) && !isScrolling) {
  1009.     if (url != "about:blank") { 
  1010.       gURLBar.value = url;
  1011.       gURLBar.select();
  1012.       SetPageProxyState("valid", null); // XXX Build a URI and pass it in here.
  1013.     } else { //if about:blank, urlbar becomes ""
  1014.       gURLBar.value = "";
  1015.     }
  1016.   }
  1017.  
  1018.   // tell widget to revert to last typed text only if the user
  1019.   // was scrolling when they hit escape
  1020.   return !isScrolling; 
  1021. }
  1022.  
  1023. function handleURLBarCommand(aTriggeringEvent)
  1024. {
  1025.   canonizeUrl(aTriggeringEvent);
  1026.  
  1027.   try { 
  1028.     addToUrlbarHistory();
  1029.   } catch (ex) {
  1030.     // Things may go wrong when adding url to session history,
  1031.     // but don't let that interfere with the loading of the url.
  1032.   }
  1033.   
  1034.   BrowserLoadURL(aTriggeringEvent); 
  1035. }
  1036.  
  1037. function canonizeUrl(aTriggeringEvent)
  1038. {
  1039.   if (!gURLBar)
  1040.     return;
  1041.   
  1042.   var url = gURLBar.value;
  1043.   if (aTriggeringEvent && 'ctrlKey' in aTriggeringEvent &&
  1044.       aTriggeringEvent.ctrlKey && 'shiftKey' in aTriggeringEvent &&
  1045.       aTriggeringEvent.shiftKey)
  1046.     // Tack http://www. and .org on.
  1047.     url = "http://www." + url + ".org/";
  1048.   else if (aTriggeringEvent && 'ctrlKey' in aTriggeringEvent &&
  1049.       aTriggeringEvent.ctrlKey)
  1050.     // Tack www. and .com on.
  1051.     url = "http://www." + url + ".com/";
  1052.   else if (aTriggeringEvent && 'shiftKey' in aTriggeringEvent &&
  1053.       aTriggeringEvent.shiftKey)
  1054.     // Tack www. and .org on.
  1055.     url = "http://www." + url + ".net/";
  1056.  
  1057.   gURLBar.value = getShortcutOrURI(url);
  1058. }
  1059.  
  1060. function UpdatePageProxyState()
  1061. {
  1062.   if (gURLBar && gURLBar.value != gLastValidURLStr)
  1063.     SetPageProxyState("invalid", null);
  1064. }
  1065.  
  1066. function SetPageProxyState(aState, aURI)
  1067. {
  1068.   if (!gURLBar)
  1069.     return;
  1070.  
  1071.   if (!gProxyButton)
  1072.     gProxyButton = document.getElementById("page-proxy-button");
  1073.   if (!gProxyFavIcon)
  1074.     gProxyFavIcon = document.getElementById("page-proxy-favicon");
  1075.   if (!gProxyDeck)
  1076.     gProxyDeck = document.getElementById("page-proxy-deck");
  1077.  
  1078.   gProxyButton.setAttribute("pageproxystate", aState);
  1079.  
  1080.   if (aState == "valid") {
  1081.     gLastValidURLStr = gURLBar.value;
  1082.     gURLBar.addEventListener("input", UpdatePageProxyState, false);
  1083.     if (gBrowser.shouldLoadFavIcon(aURI)) {
  1084.       var favStr = gBrowser.buildFavIconString(aURI);
  1085.       if (favStr != gProxyFavIcon.src) {
  1086.         gBrowser.loadFavIcon(aURI, "src", gProxyFavIcon);
  1087.         gProxyDeck.selectedIndex = 0;
  1088.       }
  1089.       else gProxyDeck.selectedIndex = 1;
  1090.     }
  1091.     else {
  1092.       gProxyDeck.selectedIndex = 0;
  1093.       gProxyFavIcon.removeAttribute("src");
  1094.     }
  1095.   } else if (aState == "invalid") {
  1096.     gURLBar.removeEventListener("input", UpdatePageProxyState, false);
  1097.     gProxyDeck.selectedIndex = 0;
  1098.   }
  1099. }
  1100.  
  1101. function PageProxyDragGesture(aEvent)
  1102. {
  1103.   if (gProxyButton.getAttribute("pageproxystate") == "valid") {
  1104.     nsDragAndDrop.startDrag(aEvent, proxyIconDNDObserver);
  1105.     return true;
  1106.   }
  1107.   return false;
  1108. }
  1109.  
  1110. function SearchBarPopupShowing(aEvent)
  1111. {
  1112.   var searchBar = document.getElementById("search-bar");
  1113.   var searchMode = searchBar.searchMode;
  1114.  
  1115.   var popup = document.getElementById("SearchBarPopup");
  1116.   var node = popup.firstChild;
  1117.   while (node) {
  1118.     node.setAttribute("checked", node.id == searchMode);
  1119.     node = node.nextSibling;
  1120.   }
  1121.  
  1122.   var findItem = document.getElementById("miSearchModeFind");
  1123.   findItem.setAttribute("checked", !searchMode);
  1124. }
  1125.  
  1126. function SearchBarPopupCommand(aEvent)
  1127. {
  1128.   var searchBar = document.getElementById("search-bar");
  1129.  
  1130.   if (aEvent.target.id == "miSearchModeFind") {
  1131.     searchBar.removeAttribute("searchmode");
  1132.     searchBar.setAttribute("autocompletesearchparam", "__PhoenixFindInPage");
  1133.     gPrefService.setCharPref("browser.search.defaultengine", "");
  1134.  
  1135.     // Clear out the search engine icon
  1136.     searchBar.firstChild.removeAttribute("src");
  1137.   } else {
  1138.     searchBar.setAttribute("searchmode", aEvent.target.id);
  1139.     searchBar.setAttribute("autocompletesearchparam", "q");
  1140.     gPrefService.setCharPref("browser.search.defaultengine", aEvent.target.id);
  1141.   }
  1142.   
  1143.   searchBar.detachController();
  1144.   focusSearchBar();
  1145. }
  1146.  
  1147. function handleSearchBarCommand(aEvent)
  1148. {
  1149.   var searchBar = document.getElementById("search-bar");
  1150.  
  1151.   // Save the current value in the form history
  1152.   if (!gFormHistory)
  1153.     gFormHistory = Components.classes["@mozilla.org/satchel/form-history;1"]
  1154.                              .getService(Components.interfaces.nsIFormHistory);
  1155.   gFormHistory.addEntry(searchBar.getAttribute("autocompletesearchparam"), searchBar.value);
  1156.  
  1157.   if (searchBar.hasAttribute("searchmode")) {
  1158.     gURLBar.value = searchBar.searchValue;
  1159.     BrowserLoadURL(aEvent);
  1160.   } else {
  1161.     quickFindInPage(searchBar.value);
  1162.   }
  1163. }
  1164.  
  1165. function quickFindInPage(aValue)
  1166. {
  1167.   var focusedWindow = document.commandDispatcher.focusedWindow;
  1168.   if (!focusedWindow || focusedWindow == window)
  1169.     focusedWindow = window._content;
  1170.       
  1171.   var findInst = gBrowser.webBrowserFind;
  1172.   var findInFrames = findInst.QueryInterface(Components.interfaces.nsIWebBrowserFindInFrames);
  1173.   findInFrames.rootSearchFrame = _content;
  1174.   findInFrames.currentSearchFrame = focusedWindow;
  1175.  
  1176.   var findService = Components.classes["@mozilla.org/find/find_service;1"]
  1177.                           .getService(Components.interfaces.nsIFindService);
  1178.   findInst.searchString  = aValue;
  1179.   findInst.matchCase     = findService.matchCase;
  1180.   findInst.wrapFind      = true;
  1181.   findInst.entireWord    = findService.entireWord;
  1182.   findInst.findBackwards = false;
  1183.  
  1184.   findInst.findNext();
  1185. }
  1186.  
  1187. function updateToolbarStates(toolbarMenuElt)
  1188. {
  1189.   if (!gHaveUpdatedToolbarState) {
  1190.     var mainWindow = document.getElementById("main-window");
  1191.     if (mainWindow.hasAttribute("chromehidden")) {
  1192.       gHaveUpdatedToolbarState = true;
  1193.       var i;
  1194.       for (i = 0; i < toolbarMenuElt.childNodes.length; ++i)
  1195.         document.getElementById(toolbarMenuElt.childNodes[i].getAttribute("observes")).removeAttribute("checked");
  1196.       var toolbars = document.getElementsByTagName("toolbar");
  1197.       
  1198.       // Start i at 1, since we skip the menubar.
  1199.       for (i = 1; i < toolbars.length; ++i) {
  1200.         if (toolbars[i].getAttribute("class").indexOf("chromeclass") != -1)
  1201.           toolbars[i].setAttribute("hidden", "true");
  1202.       }
  1203.       var statusbars = document.getElementsByTagName("statusbar");
  1204.       for (i = 1; i < statusbars.length; ++i) {
  1205.         if (statusbars[i].getAttribute("class").indexOf("chromeclass") != -1)
  1206.           statusbars[i].setAttribute("hidden", "true");
  1207.       }
  1208.       mainWindow.removeAttribute("chromehidden");
  1209.     }
  1210.   }
  1211. }
  1212.  
  1213. // Fill in tooltips for personal toolbar
  1214. function FillInPTTooltip(tipElement)
  1215. {
  1216.  
  1217.   var title = tipElement.label;
  1218.   var url = tipElement.statusText;
  1219.  
  1220.   if (!title && !url) {
  1221.     // bail out early if there is nothing to show
  1222.     return false;
  1223.   }
  1224.  
  1225.   var tooltipTitle = document.getElementById("ptTitleText");
  1226.   var tooltipUrl = document.getElementById("ptUrlText"); 
  1227.  
  1228.   if (title && title != url) {
  1229.     tooltipTitle.removeAttribute("hidden");
  1230.     tooltipTitle.setAttribute("value", title);
  1231.   } else  {
  1232.     tooltipTitle.setAttribute("hidden", "true");
  1233.   }
  1234.  
  1235.   if (url) {
  1236.     tooltipUrl.removeAttribute("hidden");
  1237.     tooltipUrl.setAttribute("value", url);
  1238.   } else {
  1239.     tooltipUrl.setAttribute("hidden", "true");
  1240.   }
  1241.  
  1242.   return true; // show tooltip
  1243. }
  1244.  
  1245. function BrowserFullScreen()
  1246. {
  1247.   window.fullScreen = !window.fullScreen;
  1248. }
  1249.  
  1250. function onFullScreen()
  1251. {
  1252.   FullScreen.toggle();
  1253.   
  1254. }
  1255.  
  1256. function getWebNavigation()
  1257. {
  1258.   try {
  1259.     return gBrowser.webNavigation;
  1260.   } catch (e) {
  1261.     return null;
  1262.   }
  1263. }
  1264.  
  1265. function BrowserReloadWithFlags(reloadFlags)
  1266. {
  1267.   /* First, we'll try to use the session history object to reload so 
  1268.    * that framesets are handled properly. If we're in a special 
  1269.    * window (such as view-source) that has no session history, fall 
  1270.    * back on using the web navigation's reload method.
  1271.    */
  1272.  
  1273.   var webNav = getWebNavigation();
  1274.   try {
  1275.     var sh = webNav.sessionHistory;
  1276.     if (sh)
  1277.       webNav = sh.QueryInterface(nsIWebNavigation);
  1278.   } catch (e) {
  1279.   }
  1280.  
  1281.   try {
  1282.     webNav.reload(reloadFlags);
  1283.   } catch (e) {
  1284.   }
  1285. }
  1286.  
  1287. function toggleAffectedChrome(aHide)
  1288. {
  1289.   // chrome to toggle includes:
  1290.   //   (*) menubar
  1291.   //   (*) navigation bar
  1292.   //   (*) bookmarks toolbar
  1293.   //   (*) tab browser ``strip''
  1294.   //   (*) sidebar
  1295.  
  1296.   if (!gChromeState)
  1297.     gChromeState = new Object;
  1298.   var navToolbox = document.getElementById("navigator-toolbox");
  1299.   navToolbox.hidden = aHide;
  1300.   if (aHide)
  1301.   {
  1302.     // going into print preview mode
  1303.     //deal with tab browser
  1304.     gChromeState.hadTabStrip = gBrowser.getStripVisibility();
  1305.     gBrowser.setStripVisibilityTo(false);
  1306.     
  1307.     var sidebar = document.getElementById("sidebar-box");
  1308.     gChromeState.sidebarOpen = !sidebar.hidden;
  1309.     if (gChromeState.sidebarOpen) {
  1310.       toggleSidebar();
  1311.     }
  1312.   }
  1313.   else
  1314.   {
  1315.     // restoring normal mode (i.e., leaving print preview mode)
  1316.     //restore tab browser
  1317.     gBrowser.setStripVisibilityTo(gChromeState.hadTabStrip);
  1318.     if (gChromeState.sidebarOpen) {
  1319.       toggleSidebar();
  1320.     }
  1321.   }
  1322. }
  1323.  
  1324. function showPrintPreviewToolbar()
  1325. {
  1326.   toggleAffectedChrome(true);
  1327.   const kXULNS = 
  1328.     "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  1329.  
  1330.   var printPreviewTB = document.createElementNS(kXULNS, "toolbar");
  1331.   printPreviewTB.setAttribute("printpreview", true);
  1332.   printPreviewTB.setAttribute("id", "print-preview-toolbar");
  1333.  
  1334.   var navToolbox = document.getElementById("navigator-toolbox");
  1335.   navToolbox.parentNode.insertBefore(printPreviewTB, navToolbox);
  1336. }
  1337.  
  1338. function BrowserExitPrintPreview()
  1339. {
  1340.   gInPrintPreviewMode = false;
  1341.  
  1342.   gBrowser.setAttribute("handleCtrlPageUpDown", "true");
  1343.  
  1344.   // exit print preview galley mode in content area
  1345.   var ifreq = _content.QueryInterface(
  1346.     Components.interfaces.nsIInterfaceRequestor);
  1347.   var webBrowserPrint = ifreq.getInterface(
  1348.     Components.interfaces.nsIWebBrowserPrint);     
  1349.   webBrowserPrint.exitPrintPreview(); 
  1350.   _content.focus();
  1351.  
  1352.   // remove the print preview toolbar
  1353.   var navToolbox = document.getElementById("navigator-toolbox");
  1354.   var printPreviewTB = document.getElementById("print-preview-toolbar");
  1355.   navToolbox.parentNode.removeChild(printPreviewTB);
  1356.  
  1357.   // restore chrome to original state
  1358.   toggleAffectedChrome(false);
  1359.  
  1360.   // restore old onclose handler if we found one before previewing
  1361.   var mainWin = document.getElementById("main-window");
  1362.   mainWin.setAttribute("onclose", gOldCloseHandler);
  1363. }
  1364.  
  1365. function GetPrintSettings()
  1366. {
  1367.   var prevPS = gPrintSettings;
  1368.  
  1369.   try {
  1370.     if (gPrintSettings == null) {
  1371.       gPrintSettingsAreGlobal = gPrefService.getBoolPref("print.use_global_printsettings", false);
  1372.       gSavePrintSettings = gPrefService.getBoolPref("print.save_print_settings", false);
  1373.  
  1374.       var psService = Components.classes["@mozilla.org/gfx/printsettings-service;1"]
  1375.                                         .getService(Components.interfaces.nsIPrintSettingsService);
  1376.       if (gPrintSettingsAreGlobal) {
  1377.         gPrintSettings = psService.globalPrintSettings;        
  1378.         if (gSavePrintSettings) {
  1379.           psService.initPrintSettingsFromPrefs(gPrintSettings, false, gPrintSettings.kInitSaveNativeData);
  1380.         }
  1381.       } else {
  1382.         gPrintSettings = psService.newPrintSettings;
  1383.       }
  1384.     }
  1385.   } catch (e) {
  1386.     dump("GetPrintSettings "+e);
  1387.   }
  1388.  
  1389.   return gPrintSettings;
  1390. }
  1391.  
  1392. // This observer is called once the progress dialog has been "opened"
  1393. var gPrintPreviewObs = {
  1394.     observe: function(aSubject, aTopic, aData)
  1395.     {
  1396.       setTimeout(FinishPrintPreview, 0);
  1397.     },
  1398.  
  1399.     QueryInterface : function(iid)
  1400.     {
  1401.      if (iid.equals(Components.interfaces.nsIObserver) || iid.equals(Components.interfaces.nsISupportsWeakReference))
  1402.       return this;
  1403.      
  1404.      throw Components.results.NS_NOINTERFACE;
  1405.     }
  1406. };
  1407.  
  1408. function BrowserPrintPreview()
  1409. {
  1410.   var ifreq;
  1411.   var webBrowserPrint;  
  1412.   try {
  1413.     ifreq = _content.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  1414.     webBrowserPrint = ifreq.getInterface(Components.interfaces.nsIWebBrowserPrint);     
  1415.     gPrintSettings = GetPrintSettings();
  1416.  
  1417.   } catch (e) {
  1418.     // Pressing cancel is expressed as an NS_ERROR_ABORT return value,
  1419.     // causing an exception to be thrown which we catch here.
  1420.     // Unfortunately this will also consume helpful failures, so add a
  1421.     // dump(e); // if you need to debug
  1422.   }
  1423.  
  1424.   // Here we get the PrintingPromptService tso we can display the PP Progress from script
  1425.   // For the browser implemented via XUL with the PP toolbar we cannot let it be
  1426.   // automatically opened from the print engine because the XUL scrollbars in the PP window
  1427.   // will layout before the content window and a crash will occur.
  1428.   //
  1429.   // Doing it all from script, means it lays out before hand and we can let printing do it's own thing
  1430.   gWebProgress = new Object();
  1431.  
  1432.   var printPreviewParams    = new Object();
  1433.   var notifyOnOpen          = new Object();
  1434.   var printingPromptService = Components.classes["@mozilla.org/embedcomp/printingprompt-service;1"]
  1435.                                   .getService(Components.interfaces.nsIPrintingPromptService);
  1436.   if (printingPromptService) {
  1437.     // just in case we are already printing, 
  1438.     // an error code could be returned if the Prgress Dialog is already displayed
  1439.     try {
  1440.       printingPromptService.showProgress(this, webBrowserPrint, gPrintSettings, gPrintPreviewObs, false, gWebProgress, 
  1441.                                          printPreviewParams, notifyOnOpen);
  1442.       if (printPreviewParams.value) {
  1443.         var webNav = getWebNavigation();
  1444.         printPreviewParams.value.docTitle = webNav.document.title;
  1445.         printPreviewParams.value.docURL   = webNav.currentURI.spec;
  1446.       }
  1447.  
  1448.       // this tells us whether we should continue on with PP or 
  1449.       // wait for the callback via the observer
  1450.       if (!notifyOnOpen.value.valueOf() || gWebProgress.value == null) {
  1451.         FinishPrintPreview();
  1452.       }
  1453.     } catch (e) {
  1454.       FinishPrintPreview();
  1455.     }
  1456.   }
  1457. }
  1458.  
  1459. function FinishPrintPreview()
  1460. {
  1461.   try {
  1462.     var ifreq = _content.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  1463.     var webBrowserPrint = ifreq.getInterface(Components.interfaces.nsIWebBrowserPrint);     
  1464.     if (webBrowserPrint) {
  1465.       gPrintSettings = GetPrintSettings();
  1466.       webBrowserPrint.printPreview(gPrintSettings, null, gWebProgress.value);
  1467.     }
  1468.  
  1469.     gBrowser.setAttribute("handleCtrlPageUpDown", "false");
  1470.  
  1471.     var mainWin = document.getElementById("main-window");
  1472.  
  1473.     // save previous close handler to restoreon exiting print preview mode
  1474.     if (mainWin.hasAttribute("onclose"))
  1475.       gOldCloseHandler = mainWin.getAttribute("onclose");
  1476.     else
  1477.       gOldCloseHandler = null;
  1478.     mainWin.setAttribute("onclose", "BrowserExitPrintPreview(); return false;");
  1479.  
  1480.     // show the toolbar after we go into print preview mode so
  1481.     // that we can initialize the toolbar with total num pages
  1482.     showPrintPreviewToolbar();
  1483.  
  1484.     _content.focus();
  1485.   } catch (e) {
  1486.     // Pressing cancel is expressed as an NS_ERROR_ABORT return value,
  1487.     // causing an exception to be thrown which we catch here.
  1488.     // Unfortunately this will also consume helpful failures, so add a
  1489.     // dump(e); // if you need to debug
  1490.   }
  1491.   gInPrintPreviewMode = true;
  1492. }
  1493.  
  1494. function BrowserPrintSetup()
  1495. {
  1496.   var didOK = false;
  1497.   try {
  1498.     var ifreq = _content.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  1499.     var webBrowserPrint = ifreq.getInterface(Components.interfaces.nsIWebBrowserPrint);     
  1500.     if (webBrowserPrint) {
  1501.       gPrintSettings = GetPrintSettings();
  1502.     }
  1503.  
  1504.     didOK = goPageSetup(window, gPrintSettings);  // from utilityOverlay.js
  1505.     if (didOK) {  // from utilityOverlay.js
  1506.  
  1507.       if (webBrowserPrint) {
  1508.         if (gPrintSettingsAreGlobal && gSavePrintSettings) {
  1509.           var psService = Components.classes["@mozilla.org/gfx/printsettings-service;1"]
  1510.                                             .getService(Components.interfaces.nsIPrintSettingsService);
  1511.           psService.savePrintSettingsToPrefs(gPrintSettings, false, gPrintSettings.kInitSaveNativeData);
  1512.         }
  1513.       }
  1514.     }
  1515.   } catch (e) {
  1516.     dump("BrowserPrintSetup "+e);
  1517.   }
  1518.   return didOK;
  1519. }
  1520.  
  1521. function BrowserPrint()
  1522. {
  1523.   try {
  1524.     var ifreq = _content.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  1525.     var webBrowserPrint = ifreq.getInterface(Components.interfaces.nsIWebBrowserPrint);     
  1526.     if (webBrowserPrint) {
  1527.       gPrintSettings = GetPrintSettings();
  1528.       webBrowserPrint.print(gPrintSettings, null);
  1529.     }
  1530.   } catch (e) {
  1531.     // Pressing cancel is expressed as an NS_ERROR_ABORT return value,
  1532.     // causing an exception to be thrown which we catch here.
  1533.     // Unfortunately this will also consume helpful failures, so add a
  1534.     // dump(e); // if you need to debug
  1535.   }
  1536. }
  1537.  
  1538. function BrowserFind()
  1539. {
  1540.   var focusedWindow = document.commandDispatcher.focusedWindow;
  1541.   if (!focusedWindow || focusedWindow == window)
  1542.     focusedWindow = window._content;
  1543.  
  1544.   findInPage(gBrowser, window._content, focusedWindow)
  1545. }
  1546.  
  1547. function BrowserFindAgain(reverse)
  1548. {
  1549.     var focusedWindow = document.commandDispatcher.focusedWindow;
  1550.     if (!focusedWindow || focusedWindow == window)
  1551.       focusedWindow = window._content;
  1552.  
  1553.   findAgainInPage(gBrowser, window._content, focusedWindow, reverse)
  1554. }
  1555.  
  1556. function BrowserCanFindAgain()
  1557. {
  1558.   return canFindAgainInPage();
  1559. }
  1560.  
  1561. function getMarkupDocumentViewer()
  1562. {
  1563.   return gBrowser.markupDocumentViewer;
  1564. }
  1565.  
  1566. /**
  1567.  * Content area tooltip.
  1568.  * XXX - this must move into XBL binding/equiv! Do not want to pollute
  1569.  *       browser.js with functionality that can be encapsulated into
  1570.  *       browser widget. TEMPORARY!
  1571.  *
  1572.  * NOTE: Any changes to this routine need to be mirrored in ChromeListener::FindTitleText()
  1573.  *       (located in mozilla/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp)
  1574.  *       which performs the same function, but for embedded clients that
  1575.  *       don't use a XUL/JS layer. It is important that the logic of
  1576.  *       these two routines be kept more or less in sync.
  1577.  *       (pinkerton)
  1578.  **/
  1579. function FillInHTMLTooltip(tipElement)
  1580. {
  1581.   var retVal = false;
  1582.   if (tipElement.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")
  1583.     return retVal;
  1584.  
  1585.   const XLinkNS = "http://www.w3.org/1999/xlink";
  1586.  
  1587.  
  1588.   var titleText = null;
  1589.   var XLinkTitleText = null;
  1590.   
  1591.   while (!titleText && !XLinkTitleText && tipElement) {
  1592.     if (tipElement.nodeType == Node.ELEMENT_NODE) {
  1593.       titleText = tipElement.getAttribute("title");
  1594.       XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title");
  1595.     }
  1596.     tipElement = tipElement.parentNode;
  1597.   }
  1598.  
  1599.   var texts = [titleText, XLinkTitleText];
  1600.   var tipNode = document.getElementById("aHTMLTooltip");
  1601.  
  1602.   for (var i = 0; i < texts.length; ++i) {
  1603.     var t = texts[i];
  1604.     if (t && t.search(/\S/) >= 0) {
  1605.       tipNode.setAttribute("label", t);
  1606.       retVal = true;
  1607.     }
  1608.   }
  1609.  
  1610.   return retVal;
  1611. }
  1612.  
  1613. var proxyIconDNDObserver = {
  1614.   onDragStart: function (aEvent, aXferData, aDragAction)
  1615.     {
  1616.       var value = gURLBar.value;
  1617.       // XXX - do we want to allow the user to set a blank page to their homepage?
  1618.       //       if so then we want to modify this a little to set about:blank as
  1619.       //       the homepage in the event of an empty urlbar.
  1620.       if (!value) return;
  1621.  
  1622.       var urlString = value + "\n" + window._content.document.title;
  1623.       var htmlString = "<a href=\"" + value + "\">" + value + "</a>";
  1624.  
  1625.       aXferData.data = new TransferData();
  1626.       aXferData.data.addDataForFlavour("text/x-moz-url", urlString);
  1627.       aXferData.data.addDataForFlavour("text/unicode", value);
  1628.       aXferData.data.addDataForFlavour("text/html", htmlString);
  1629.     }
  1630. }
  1631.  
  1632. var homeButtonObserver = {
  1633.   onDrop: function (aEvent, aXferData, aDragSession)
  1634.     {
  1635.       var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
  1636.       setTimeout(openHomeDialog, 0, url);
  1637.     },
  1638.  
  1639.   onDragOver: function (aEvent, aFlavour, aDragSession)
  1640.     {
  1641.       var statusTextFld = document.getElementById("statusbar-display");
  1642.       statusTextFld.label = gNavigatorBundle.getString("droponhomebutton");
  1643.       aDragSession.dragAction = Components.interfaces.nsIDragService.DRAGDROP_ACTION_LINK;
  1644.     },
  1645.  
  1646.   onDragExit: function (aEvent, aDragSession)
  1647.     {
  1648.       var statusTextFld = document.getElementById("statusbar-display");
  1649.       statusTextFld.label = "";
  1650.     },
  1651.  
  1652.   getSupportedFlavours: function ()
  1653.     {
  1654.       var flavourSet = new FlavourSet();
  1655.       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  1656.       flavourSet.appendFlavour("text/x-moz-url");
  1657.       flavourSet.appendFlavour("text/unicode");
  1658.       return flavourSet;
  1659.     }
  1660. }
  1661.  
  1662. function openHomeDialog(aURL)
  1663. {
  1664.   var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  1665.   var promptTitle = gNavigatorBundle.getString("droponhometitle");
  1666.   var promptMsg   = gNavigatorBundle.getString("droponhomemsg");
  1667.   var okButton    = gNavigatorBundle.getString("droponhomeokbutton");
  1668.   var pressedVal  = promptService.confirmEx(window, promptTitle, promptMsg,
  1669.                           (promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0) +
  1670.                           (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1),
  1671.                           okButton, null, null, null, {value:0});
  1672.  
  1673.   if (pressedVal == 0) {
  1674.     try {
  1675.       var str = Components.classes["@mozilla.org/supports-string;1"]
  1676.                           .createInstance(Components.interfaces.nsISupportsString);
  1677.       str.data = aURL;
  1678.       gPrefService.setComplexValue("browser.startup.homepage",
  1679.                                    Components.interfaces.nsISupportsString, str);
  1680.       var homeButton = document.getElementById("home-button");
  1681.       homeButton.setAttribute("tooltiptext", aURL);
  1682.     } catch (ex) {
  1683.       dump("Failed to set the home page.\n"+ex+"\n");
  1684.     }
  1685.   }
  1686. }
  1687.  
  1688. var goButtonObserver = {
  1689.   onDragOver: function(aEvent, aFlavour, aDragSession)
  1690.     {
  1691.       aEvent.target.setAttribute("dragover", "true");
  1692.       return true;
  1693.     },
  1694.   onDragExit: function (aEvent, aDragSession)
  1695.     {
  1696.       aEvent.target.removeAttribute("dragover");
  1697.     },
  1698.   onDrop: function (aEvent, aXferData, aDragSession)
  1699.     {
  1700.       var xferData = aXferData.data.split("\n");
  1701.       var uri = xferData[0] ? xferData[0] : xferData[1];
  1702.       if (uri)
  1703.         loadURI(uri);
  1704.     },
  1705.   getSupportedFlavours: function ()
  1706.     {
  1707.       var flavourSet = new FlavourSet();
  1708.       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  1709.       flavourSet.appendFlavour("text/x-moz-url");
  1710.       flavourSet.appendFlavour("text/unicode");
  1711.       return flavourSet;
  1712.     }
  1713. }
  1714.  
  1715. function ensureDefaultEnginePrefs(aRDF,aDS) 
  1716. {
  1717.   var mPrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  1718.   var defaultName = mPrefs.getComplexValue("browser.search.defaultenginename", Components.interfaces.nsIPrefLocalizedString).data;
  1719.   var kNC_Root = aRDF.GetResource("NC:SearchEngineRoot");
  1720.   var kNC_child = aRDF.GetResource("http://home.netscape.com/NC-rdf#child");
  1721.   var kNC_Name = aRDF.GetResource("http://home.netscape.com/NC-rdf#Name");
  1722.           
  1723.   var arcs = aDS.GetTargets(kNC_Root, kNC_child, true);
  1724.   while (arcs.hasMoreElements()) {
  1725.     var engineRes = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource);       
  1726.     var name = readRDFString(aDS, engineRes, kNC_Name);
  1727.     if (name == defaultName)
  1728.       mPrefs.setCharPref("browser.search.defaultengine", engineRes.Value);
  1729.   }
  1730. }
  1731.  
  1732. function readRDFString(aDS,aRes,aProp)
  1733. {
  1734.   var n = aDS.GetTarget(aRes, aProp, true);
  1735.   return n ? n.QueryInterface(Components.interfaces.nsIRDFLiteral).Value : "";
  1736. }
  1737.  
  1738. function ensureSearchPref()
  1739. {
  1740.   var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
  1741.   var ds = rdf.GetDataSource("rdf:internetsearch");
  1742.   var mPrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  1743.   var kNC_Name = rdf.GetResource("http://home.netscape.com/NC-rdf#Name");
  1744.   var defaultEngine;
  1745.   try {
  1746.     defaultEngine = mPrefs.getCharPref("browser.search.defaultengine");
  1747.   } catch(ex) {
  1748.     ensureDefaultEnginePrefs(rdf, ds);
  1749.     defaultEngine = mPrefs.getCharPref("browser.search.defaultengine");
  1750.   }
  1751. }
  1752.  
  1753. function OpenSearch(tabName, searchStr, newWindowFlag)
  1754. {
  1755.   //This function needs to be split up someday.
  1756.  
  1757.   var defaultSearchURL = null;
  1758.   var navigatorRegionBundle = document.getElementById("bundle_browser_region");
  1759.   var fallbackDefaultSearchURL = navigatorRegionBundle.getString("fallbackDefaultSearchURL");
  1760.   ensureSearchPref()
  1761.   //Check to see if search string contains "://" or "ftp." or white space.
  1762.   //If it does treat as url and match for pattern
  1763.   
  1764.   var urlmatch= /(:\/\/|^ftp\.)[^ \S]+$/ 
  1765.   var forceAsURL = urlmatch.test(searchStr);
  1766.  
  1767.   try {
  1768.     defaultSearchURL = gPrefService.getComplexValue("browser.search.defaulturl",
  1769.                                             Components.interfaces.nsIPrefLocalizedString).data;
  1770.   } catch (ex) {
  1771.   }
  1772.  
  1773.   // Fallback to a default url (one that we can get sidebar search results for)
  1774.   if (!defaultSearchURL)
  1775.     defaultSearchURL = fallbackDefaultSearchURL;
  1776.  
  1777.   if (!searchStr) {
  1778.     BrowserSearchInternet();
  1779.   } else {
  1780.  
  1781.     //Check to see if location bar field is a url
  1782.     //If it is a url go to URL.  A Url is "://" or "." as commented above
  1783.     //Otherwise search on entry
  1784.     if (forceAsURL) {
  1785.        BrowserLoadURL()
  1786.     } else {
  1787.       if (searchStr) {
  1788.         var escapedSearchStr = escape(searchStr);
  1789.         defaultSearchURL += escapedSearchStr;
  1790.         var searchDS = Components.classes["@mozilla.org/rdf/datasource;1?name=internetsearch"]
  1791.                                  .getService(Components.interfaces.nsIInternetSearchService);
  1792.  
  1793.         searchDS.RememberLastSearchText(escapedSearchStr);
  1794.         try {
  1795.           var searchEngineURI = gPrefService.getCharPref("browser.search.defaultengine");
  1796.           if (searchEngineURI) {          
  1797.             var searchURL = getSearchUrl("actionButton");
  1798.             if (searchURL) {
  1799.               defaultSearchURL = searchURL + escapedSearchStr; 
  1800.             } else {
  1801.               searchURL = searchDS.GetInternetSearchURL(searchEngineURI, escapedSearchStr, 0, 0, {value:0});
  1802.               if (searchURL)
  1803.                 defaultSearchURL = searchURL;
  1804.             }
  1805.           }
  1806.         } catch (ex) {
  1807.         }
  1808.  
  1809.         if (!newWindowFlag)
  1810.           loadURI(defaultSearchURL);
  1811.         else
  1812.           window.open(defaultSearchURL, "_blank");
  1813.       }
  1814.     }
  1815.   }
  1816. }
  1817.  
  1818. var personalToolbarDNDObserver = {
  1819.  
  1820.   ////////////////////
  1821.   // Public methods //
  1822.   ////////////////////
  1823.  
  1824.   onDragStart: function (aEvent, aXferData, aDragAction)
  1825.     {
  1826.       var target = aEvent.originalTarget;
  1827.  
  1828.       // Prevent dragging from an invalid region
  1829.       if (!this.canDrop(aEvent))
  1830.         return;
  1831.  
  1832.       // Prevent dragging out of menupopups on non Win32 platforms. 
  1833.       // a) on Mac drag from menus is generally regarded as being satanic
  1834.       // b) on Linux, this causes an X-server crash, (bug 151336)
  1835.       // c) on Windows, there is no hang or crash associated with this, so we'll leave 
  1836.       // the functionality there. 
  1837.       if (navigator.platform != "Win32" && target.localName != "toolbarbutton")
  1838.         return;
  1839.  
  1840.       // bail if dragging from the empty area of the bookmarks toolbar
  1841.       if (target.localName == "hbox")
  1842.         return
  1843.  
  1844.       // a drag start is fired when leaving an open toolbarbutton(type=menu) 
  1845.       // (see bug 143031)
  1846.       if (this.isContainer(target) && 
  1847.           target.getAttribute("group") != "true") {
  1848.         if (this.isPlatformNotSupported) 
  1849.           return;
  1850.         if (!aEvent.shiftKey && !aEvent.altKey && !aEvent.ctrlKey)
  1851.           return;
  1852.         // menus open on mouse down
  1853.         target.firstChild.hidePopup();
  1854.       }
  1855.       var bt = document.getElementById("bookmarks-toolbar");
  1856.       var selection  = bt.getBTSelection(target);
  1857.       aXferData.data = BookmarksUtils.getXferDataFromSelection(selection);
  1858.     },
  1859.  
  1860.   onDragOver: function(aEvent, aFlavour, aDragSession) 
  1861.   {
  1862.     var bt = document.getElementById("bookmarks-toolbar");
  1863.     var orientation = bt.getBTOrientation(aEvent)
  1864.     if (aDragSession.canDrop)
  1865.       this.onDragSetFeedBack(aEvent.originalTarget, orientation);
  1866.     if (orientation != this.mCurrentDropPosition) {
  1867.       // emulating onDragExit and onDragEnter events since the drop region
  1868.       // has changed on the target.
  1869.       this.onDragExit(aEvent, aDragSession);
  1870.       this.onDragEnter(aEvent, aDragSession);
  1871.     }
  1872.     if (this.isPlatformNotSupported)
  1873.       return;
  1874.     if (this.isTimerSupported)
  1875.       return;
  1876.     this.onDragOverCheckTimers();
  1877.   },
  1878.  
  1879.   onDragEnter: function (aEvent, aDragSession)
  1880.   {
  1881.     var target = aEvent.originalTarget;
  1882.     var bt = document.getElementById("bookmarks-toolbar");
  1883.     var orientation = bt.getBTOrientation(aEvent);
  1884.     if (target.localName == "menupopup" || target.localName == "hbox")
  1885.       target = target.parentNode;
  1886.     if (aDragSession.canDrop) {
  1887.       this.onDragSetFeedBack(target, orientation);
  1888.       this.onDragEnterSetTimer(target, aDragSession);
  1889.     }
  1890.     this.mCurrentDragOverTarget = target;
  1891.     this.mCurrentDropPosition   = orientation;
  1892.   },
  1893.  
  1894.   onDragExit: function (aEvent, aDragSession)
  1895.   {
  1896.     var target = aEvent.originalTarget;
  1897.     if (target.localName == "menupopup" || target.localName == "hbox")
  1898.       target = target.parentNode;
  1899.     this.onDragRemoveFeedBack(target);
  1900.     this.onDragExitSetTimer(target, aDragSession);
  1901.     this.mCurrentDragOverTarget = null;
  1902.     this.mCurrentDropPosition = null;
  1903.   },
  1904.  
  1905.   onDrop: function (aEvent, aXferData, aDragSession)
  1906.   {
  1907.     var target = aEvent.originalTarget;
  1908.     this.onDragRemoveFeedBack(target);
  1909.  
  1910.     var bt        = document.getElementById("bookmarks-toolbar");
  1911.     var selection = BookmarksUtils.getSelectionFromXferData(aDragSession);
  1912.  
  1913.     // if the personal toolbar does not exist, recreate it
  1914.     if (target == "bookmarks-toolbar") {
  1915.       //BookmarksUtils.recreatePersonalToolbarFolder(transactionSet);
  1916.       //target = { parent: "NC:PersonalToolbarFolder", index: 1 };
  1917.     } else {
  1918.       var orientation = bt.getBTOrientation(aEvent);
  1919.       var selTarget   = bt.getBTTarget(target, orientation);
  1920.     }
  1921.  
  1922.     const kDSIID      = Components.interfaces.nsIDragService;
  1923.     const kCopyAction = kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_LINK;
  1924.  
  1925.     // hide the 'open in tab' menuseparator because bookmarks
  1926.     // can be inserted after it if they are dropped after the last bookmark
  1927.     // a more comprehensive fix would be in the menupopup template builder
  1928.     var menuTarget = (target.localName == "toolbarbutton" ||
  1929.                       target.localName == "menu")         && 
  1930.                      orientation == BookmarksUtils.DROP_ON?
  1931.                      target.lastChild:target.parentNode;
  1932.     if (menuTarget.hasChildNodes() &&
  1933.         menuTarget.lastChild.id == "openintabs-menuitem") {
  1934.       menuTarget.removeChild(menuTarget.lastChild.previousSibling);
  1935.     }
  1936.  
  1937.     if (aDragSession.dragAction & kCopyAction)
  1938.       BookmarksUtils.insertSelection("drag", selection, selTarget, true);
  1939.     else
  1940.       BookmarksUtils.moveSelection("drag", selection, selTarget);
  1941.  
  1942.     // show again the menuseparator
  1943.     if (menuTarget.hasChildNodes() &&
  1944.         menuTarget.lastChild.id == "openintabs-menuitem") {
  1945.       var element = document.createElementNS(XUL_NS, "menuseparator");
  1946.       menuTarget.insertBefore(element, menuTarget.lastChild);
  1947.     }
  1948.  
  1949.   },
  1950.  
  1951.   canDrop: function (aEvent, aDragSession)
  1952.   {
  1953.     var target = aEvent.originalTarget;
  1954.     var bt = document.getElementById("bookmarks-toolbar");
  1955.     return bt.isBTBookmark(target.id)                  && 
  1956.            target.id != "NC:SystemBookmarksStaticRoot" &&
  1957.            target.id.substring(0,5) != "find:"         ||
  1958.            target.id == "bookmarks-menu"               ||
  1959.            target.getAttribute("class") == "chevron"   ||
  1960.            target.localName == "hbox";
  1961.   },
  1962.  
  1963.   canHandleMultipleItems: true,
  1964.  
  1965.   getSupportedFlavours: function () 
  1966.   {
  1967.     var flavourSet = new FlavourSet();
  1968.     flavourSet.appendFlavour("moz/rdfitem");
  1969.     flavourSet.appendFlavour("text/x-moz-url");
  1970.     flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  1971.     flavourSet.appendFlavour("text/unicode");
  1972.     return flavourSet;
  1973.   }, 
  1974.   
  1975.  
  1976.   ////////////////////////////////////
  1977.   // Private methods and properties //
  1978.   ////////////////////////////////////
  1979.  
  1980.   springLoadedMenuDelay: 350, // milliseconds
  1981.   isPlatformNotSupported: navigator.platform.indexOf("Mac") != -1, // see bug 136524
  1982.   isTimerSupported: navigator.platform.indexOf("Win") == -1,
  1983.  
  1984.   mCurrentDragOverTarget: null,
  1985.   mCurrentDropPosition: null,
  1986.   loadTimer  : null,
  1987.   closeTimer : null,
  1988.   loadTarget : null,
  1989.   closeTarget: null,
  1990.  
  1991.   _observers : null,
  1992.   get mObservers ()
  1993.   {
  1994.     if (!this._observers) {
  1995.       var bt = document.getElementById("bookmarks-toolbar");
  1996.       this._observers = [
  1997.         document.getAnonymousElementByAttribute(bt , "anonid", "bookmarks-ptf"),
  1998.         document.getElementById("bookmarks-menu").parentNode,
  1999.         document.getAnonymousElementByAttribute(bt , "class", "chevron").parentNode
  2000.       ]
  2001.     }
  2002.     return this._observers;
  2003.   },
  2004.  
  2005.   getObserverForNode: function (aNode)
  2006.   {
  2007.     if (!aNode)
  2008.       return null;
  2009.     var node = aNode;
  2010.     var observer;
  2011.     do {
  2012.       for (var i=0; i < this.mObservers.length; i++) {
  2013.         observer = this.mObservers[i];
  2014.         if (observer == node)
  2015.           return observer;
  2016.       }
  2017.       node = node.parentNode;
  2018.     } while (node != document)
  2019.     return null;
  2020.   },
  2021.  
  2022.   onDragCloseMenu: function (aNode)
  2023.   {
  2024.     var children = aNode.childNodes;
  2025.     for (var i = 0; i < children.length; i++) {
  2026.       if (this.isContainer(children[i]) && 
  2027.           children[i].getAttribute("open") == "true") {
  2028.         this.onDragCloseMenu(children[i].lastChild);
  2029.         if (children[i] != this.mCurrentDragOverTarget || this.mCurrentDropPosition != BookmarksUtils.DROP_ON)
  2030.           children[i].lastChild.hidePopup();
  2031.       }
  2032.     } 
  2033.   },
  2034.  
  2035.   onDragCloseTarget: function ()
  2036.   {
  2037.     var currentObserver = this.getObserverForNode(this.mCurrentDragOverTarget);
  2038.     // close all the menus not hovered by the mouse
  2039.     for (var i=0; i < this.mObservers.length; i++) {
  2040.       if (currentObserver != this.mObservers[i])
  2041.         this.onDragCloseMenu(this.mObservers[i]);
  2042.       else
  2043.         this.onDragCloseMenu(this.mCurrentDragOverTarget.parentNode);
  2044.     }
  2045.   },
  2046.  
  2047.   onDragLoadTarget: function (aTarget) 
  2048.   {
  2049.     if (!this.mCurrentDragOverTarget)
  2050.       return;
  2051.     // Load the current menu
  2052.     if (this.mCurrentDropPosition == BookmarksUtils.DROP_ON && 
  2053.         this.isContainer(aTarget)             && 
  2054.         aTarget.getAttribute("group") != "true")
  2055.       aTarget.lastChild.showPopup(aTarget);
  2056.   },
  2057.  
  2058.   onDragOverCheckTimers: function ()
  2059.   {
  2060.     var now = new Date().getTime();
  2061.     if (this.closeTimer && now-this.springLoadedMenuDelay>this.closeTimer) {
  2062.       this.onDragCloseTarget();
  2063.       this.closeTimer = null;
  2064.     }
  2065.     if (this.loadTimer && (now-this.springLoadedMenuDelay>this.loadTimer)) {
  2066.       this.onDragLoadTarget(this.loadTarget);
  2067.       this.loadTimer = null;
  2068.     }
  2069.   },
  2070.  
  2071.   onDragEnterSetTimer: function (aTarget, aDragSession)
  2072.   {
  2073.     if (this.isPlatformNotSupported)
  2074.       return;
  2075.     if (this.isTimerSupported) {
  2076.       var targetToBeLoaded = aTarget;
  2077.       clearTimeout(this.loadTimer);
  2078.       if (aTarget == aDragSession.sourceNode)
  2079.         return;
  2080.       //XXX Hack: see bug 139645
  2081.       var thisHack = this;
  2082.       this.loadTimer=setTimeout(function () {thisHack.onDragLoadTarget(targetToBeLoaded)}, this.springLoadedMenuDelay);
  2083.     } else {
  2084.       var now = new Date().getTime();
  2085.       this.loadTimer  = now;
  2086.       this.loadTarget = aTarget;
  2087.     }
  2088.   },
  2089.  
  2090.   onDragExitSetTimer: function (aTarget, aDragSession)
  2091.   {
  2092.     if (this.isPlatformNotSupported)
  2093.       return;
  2094.     var thisHack = this;
  2095.     if (this.isTimerSupported) {
  2096.       clearTimeout(this.closeTimer)
  2097.       this.closeTimer=setTimeout(function () {thisHack.onDragCloseTarget()}, this.springLoadedMenuDelay);
  2098.     } else {
  2099.       var now = new Date().getTime();
  2100.       this.closeTimer  = now;
  2101.       this.closeTarget = aTarget;
  2102.       this.loadTimer = null;
  2103.  
  2104.       // If user isn't rearranging within the menu, close it
  2105.       // To do so, we exploit a Mac bug: timeout set during
  2106.       // drag and drop on Windows and Mac are fired only after that the drop is released.
  2107.       // timeouts will pile up, we may have a better approach but for the moment, this one
  2108.       // correctly close the menus after a drop/cancel outside the personal toolbar.
  2109.       // The if statement in the function has been introduced to deal with rare but reproducible
  2110.       // missing Exit events.
  2111.       if (aDragSession.sourceNode.localName != "menuitem" && aDragSession.sourceNode.localName != "menu")
  2112.         setTimeout(function () { if (thisHack.mCurrentDragOverTarget) {thisHack.onDragRemoveFeedBack(thisHack.mCurrentDragOverTarget); thisHack.mCurrentDragOverTarget=null} thisHack.loadTimer=null; thisHack.onDragCloseTarget() }, 0);
  2113.     }
  2114.   },
  2115.  
  2116.   onDragSetFeedBack: function (aTarget, aOrientation)
  2117.   {
  2118.    switch (aTarget.localName) {
  2119.       case "toolbarseparator":
  2120.       case "toolbarbutton":
  2121.         switch (aOrientation) {
  2122.           case BookmarksUtils.DROP_BEFORE: 
  2123.             aTarget.setAttribute("dragover-left", "true");
  2124.             break;
  2125.           case BookmarksUtils.DROP_AFTER:
  2126.             aTarget.setAttribute("dragover-right", "true");
  2127.             break;
  2128.           case BookmarksUtils.DROP_ON:
  2129.             aTarget.setAttribute("dragover-top"   , "true");
  2130.             aTarget.setAttribute("dragover-bottom", "true");
  2131.             aTarget.setAttribute("dragover-left"  , "true");
  2132.             aTarget.setAttribute("dragover-right" , "true");
  2133.             break;
  2134.         }
  2135.         break;
  2136.       case "menuseparator": 
  2137.       case "menu":
  2138.       case "menuitem":
  2139.         switch (aOrientation) {
  2140.           case BookmarksUtils.DROP_BEFORE: 
  2141.             aTarget.setAttribute("dragover-top", "true");
  2142.             break;
  2143.           case BookmarksUtils.DROP_AFTER:
  2144.             aTarget.setAttribute("dragover-bottom", "true");
  2145.             break;
  2146.           case BookmarksUtils.DROP_ON:
  2147.             break;
  2148.         }
  2149.         break;
  2150.       case "hbox"     : 
  2151.         // hit between the last visible bookmark and the chevron
  2152.         var bt = document.getElementById("bookmarks-toolbar");
  2153.         var newTarget = bt.getLastVisibleBookmark();
  2154.         if (newTarget)
  2155.           newTarget.setAttribute("dragover-right", "true");
  2156.         break;
  2157.       case "stack"    :
  2158.       case "menupopup": break; 
  2159.      default: dump("No feedback for: "+aTarget.localName+"\n");
  2160.     }
  2161.   },
  2162.  
  2163.   onDragRemoveFeedBack: function (aTarget)
  2164.   { 
  2165.     var newTarget;
  2166.     var bt;
  2167.     if (aTarget.localName == "hbox") { 
  2168.       // hit when dropping in the bt or between the last visible bookmark 
  2169.       // and the chevron
  2170.       bt = document.getElementById("bookmarks-toolbar");
  2171.       newTarget = bt.getLastVisibleBookmark();
  2172.       if (newTarget)
  2173.         newTarget.removeAttribute("dragover-right");
  2174.     } else if (aTarget.localName == "stack") {
  2175.       bt = document.getElementById("bookmarks-toolbar");
  2176.       newTarget = bt.getLastVisibleBookmark();
  2177.       newTarget.removeAttribute("dragover-right");
  2178.     } else {
  2179.       aTarget.removeAttribute("dragover-left");
  2180.       aTarget.removeAttribute("dragover-right");
  2181.       aTarget.removeAttribute("dragover-top");
  2182.       aTarget.removeAttribute("dragover-bottom");
  2183.     }
  2184.   },
  2185.  
  2186.   onDropSetFeedBack: function (aTarget)
  2187.   {
  2188.     //XXX Not yet...
  2189.   },
  2190.  
  2191.   isContainer: function (aTarget)
  2192.   {
  2193.     return aTarget.localName == "menu"          || 
  2194.            aTarget.localName == "toolbarbutton" &&
  2195.            aTarget.getAttribute("type") == "menu";
  2196.   }
  2197. }
  2198.  
  2199. function FillHistoryMenu(aParent, aMenu)
  2200.   {
  2201.     // Remove old entries if any
  2202.     deleteHistoryItems(aParent);
  2203.  
  2204.     var sessionHistory = getWebNavigation().sessionHistory;
  2205.  
  2206.     var count = sessionHistory.count;
  2207.     var index = sessionHistory.index;
  2208.     var end;
  2209.     var j;
  2210.     var entry;
  2211.  
  2212.     switch (aMenu)
  2213.       {
  2214.         case "back":
  2215.           end = (index > MAX_HISTORY_MENU_ITEMS) ? index - MAX_HISTORY_MENU_ITEMS : 0;
  2216.           if ((index - 1) < end) return false;
  2217.           for (j = index - 1; j >= end; j--)
  2218.             {
  2219.               entry = sessionHistory.getEntryAtIndex(j, false);
  2220.               if (entry)
  2221.                 createMenuItem(aParent, j, entry.title);
  2222.             }
  2223.           break;
  2224.         case "forward":
  2225.           end  = ((count-index) > MAX_HISTORY_MENU_ITEMS) ? index + MAX_HISTORY_MENU_ITEMS : count;
  2226.           if ((index + 1) >= end) return false;
  2227.           for (j = index + 1; j < end; j++)
  2228.             {
  2229.               entry = sessionHistory.getEntryAtIndex(j, false);
  2230.               if (entry)
  2231.                 createMenuItem(aParent, j, entry.title);
  2232.             }
  2233.           break;
  2234.         case "go":
  2235.           aParent.lastChild.hidden = (count == 0);
  2236.           end = count > MAX_HISTORY_MENU_ITEMS ? count - MAX_HISTORY_MENU_ITEMS : 0;
  2237.           for (j = count - 1; j >= end; j--)
  2238.             {
  2239.               entry = sessionHistory.getEntryAtIndex(j, false);
  2240.               if (entry)
  2241.                 createRadioMenuItem(aParent, j, entry.title, j==index);
  2242.             }
  2243.           break;
  2244.       }
  2245.     return true;
  2246.   }
  2247.  
  2248. function addToUrlbarHistory()
  2249. {
  2250.   var urlToAdd = gURLBar.value;
  2251.   if (!urlToAdd)
  2252.      return;
  2253.   if (urlToAdd.search(/[\x00-\x1F]/) != -1) // don't store bad URLs
  2254.      return;
  2255.  
  2256.   if (!gGlobalHistory)
  2257.     gGlobalHistory = Components.classes["@mozilla.org/browser/global-history;1"]
  2258.                                .getService(Components.interfaces.nsIBrowserHistory);
  2259.   
  2260.   if (!gURIFixup)
  2261.     gURIFixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
  2262.                           .getService(Components.interfaces.nsIURIFixup);
  2263.    try {
  2264.      if (urlToAdd.indexOf(" ") == -1) {
  2265.        var fixedUpURI = gURIFixup.createFixupURI(urlToAdd, 0);
  2266.        gGlobalHistory.markPageAsTyped(fixedUpURI.spec);
  2267.      }
  2268.    }
  2269.    catch(ex) {
  2270.    }
  2271. }
  2272.  
  2273. function createMenuItem( aParent, aIndex, aLabel)
  2274.   {
  2275.     var menuitem = document.createElement( "menuitem" );
  2276.     menuitem.setAttribute( "label", aLabel );
  2277.     menuitem.setAttribute( "index", aIndex );
  2278.     aParent.appendChild( menuitem );
  2279.   }
  2280.  
  2281. function createRadioMenuItem( aParent, aIndex, aLabel, aChecked)
  2282.   {
  2283.     var menuitem = document.createElement( "menuitem" );
  2284.     menuitem.setAttribute( "type", "radio" );
  2285.     menuitem.setAttribute( "label", aLabel );
  2286.     menuitem.setAttribute( "index", aIndex );
  2287.     if (aChecked==true)
  2288.       menuitem.setAttribute( "checked", "true" );
  2289.     aParent.appendChild( menuitem );
  2290.   }
  2291.  
  2292. function deleteHistoryItems(aParent)
  2293. {
  2294.   var children = aParent.childNodes;
  2295.   for (var i = 0; i < children.length; i++)
  2296.     {
  2297.       var index = children[i].getAttribute("index");
  2298.       if (index)
  2299.         aParent.removeChild(children[i]);
  2300.     }
  2301. }
  2302.  
  2303. function toJavaScriptConsole()
  2304. {
  2305.   toOpenWindowByType("global:console", "chrome://browser/content/console/console.xul");
  2306. }
  2307.  
  2308. function toOpenWindowByType(inType, uri)
  2309. {
  2310.   var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
  2311.   var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
  2312.   var topWindow = windowManagerInterface.getMostRecentWindow(inType);
  2313.   
  2314.   if ( topWindow )
  2315.     topWindow.focus();
  2316.   else
  2317.     window.open(uri, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
  2318. }
  2319.  
  2320.  
  2321. function OpenBrowserWindow()
  2322. {
  2323.   var charsetArg = new String();
  2324.   var handler = Components.classes['@mozilla.org/commandlinehandler/general-startup;1?type=browser'];
  2325.   handler = handler.getService();
  2326.   handler = handler.QueryInterface(Components.interfaces.nsICmdLineHandler);
  2327.   var startpage = handler.defaultArgs;
  2328.   var url = handler.chromeUrlForTask;
  2329.   var wintype = document.firstChild.getAttribute('windowtype');
  2330.  
  2331.   // if and only if the current window is a browser window and it has a document with a character
  2332.   // set, then extract the current charset menu setting from the current document and use it to
  2333.   // initialize the new browser window...
  2334.   if (window && (wintype == "navigator:browser") && window._content && window._content.document)
  2335.   {
  2336.     var DocCharset = window._content.document.characterSet;
  2337.     charsetArg = "charset="+DocCharset;
  2338.  
  2339.     //we should "inherit" the charset menu setting in a new window
  2340.     window.openDialog(url, "_blank", "chrome,all,dialog=no", startpage, charsetArg);
  2341.   }
  2342.   else // forget about the charset information.
  2343.   {
  2344.     window.openDialog(url, "_blank", "chrome,all,dialog=no", startpage);
  2345.   }
  2346. }
  2347.  
  2348. function openAboutDialog()
  2349. {
  2350.   window.openDialog("chrome://browser/content/aboutDialog.xul", "About", "modal,centerscreen,chrome,resizable=no");
  2351. }
  2352.  
  2353. function BrowserCustomizeToolbar()
  2354. {
  2355.   // Disable the toolbar context menu items
  2356.   var menubar = document.getElementById("main-menubar");
  2357.   for (var i = 0; i < menubar.childNodes.length; ++i)
  2358.     menubar.childNodes[i].setAttribute("disabled", true);
  2359.     
  2360.   var cmd = document.getElementById("cmd_CustomizeToolbars");
  2361.   cmd.setAttribute("disabled", "true");
  2362.   
  2363.   window.openDialog("chrome://global/content/customizeToolbar.xul", "CustomizeToolbar",
  2364.                     "chrome,all,dependent", document.getElementById("navigator-toolbox"));
  2365. }
  2366.  
  2367. function BrowserToolboxCustomizeDone(aToolboxChanged)
  2368. {
  2369.   // Update global UI elements that may have been added or removed
  2370.   if (aToolboxChanged) {
  2371.     gURLBar = document.getElementById("urlbar");
  2372.     gProxyButton = document.getElementById("page-proxy-button");
  2373.     gProxyFavIcon = document.getElementById("page-proxy-favicon");
  2374.     gProxyDeck = document.getElementById("page-proxy-deck");
  2375.     updateHomeTooltip();
  2376.     window.XULBrowserWindow.init();
  2377.   }
  2378.  
  2379.   // Update the urlbar
  2380.   var url = getWebNavigation().currentURI.spec;
  2381.   if (gURLBar) {
  2382.     gURLBar.value = url;
  2383.     var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  2384.                         .createInstance(Components.interfaces.nsIURI);
  2385.     uri.spec = url;
  2386.     SetPageProxyState("valid", uri);
  2387.   }
  2388.  
  2389.   // Re-enable parts of the UI we disabled during the dialog
  2390.   var menubar = document.getElementById("main-menubar");
  2391.   for (var i = 0; i < menubar.childNodes.length; ++i)
  2392.     menubar.childNodes[i].setAttribute("disabled", false);
  2393.   var cmd = document.getElementById("cmd_CustomizeToolbars");
  2394.   cmd.removeAttribute("disabled");
  2395.  
  2396.   // XXX Shouldn't have to do this, but I do
  2397.   window.focus();
  2398. }
  2399.  
  2400. var FullScreen = 
  2401. {
  2402.   toggle: function()
  2403.   {
  2404.     // show/hide all menubars, toolbars, and statusbars (except the full screen toolbar)
  2405.     this.showXULChrome("menubar", window.fullScreen);
  2406.     this.showXULChrome("toolbar", window.fullScreen);
  2407.     this.showXULChrome("statusbar", window.fullScreen);
  2408.   },
  2409.   
  2410.   showXULChrome: function(aTag, aShow)
  2411.   {
  2412.     var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  2413.     var els = document.getElementsByTagNameNS(XULNS, aTag);
  2414.     
  2415.     var i;
  2416.     for (i = 0; i < els.length; ++i) {
  2417.       // XXX don't interfere with previously collapsed toolbars
  2418.       if (els[i].getAttribute("fullscreentoolbar") == "true") {
  2419.         if (!aShow) {
  2420.           gToolbarMode = els[i].getAttribute("mode");
  2421.           gIconSize = els[i].getAttribute("iconsize");
  2422.           els[i].setAttribute("mode", "icons");
  2423.           els[i].setAttribute("iconsize", "small");
  2424.         }
  2425.         else {
  2426.           els[i].setAttribute("mode", gToolbarMode);
  2427.           els[i].setAttribute("iconsize", gIconSize);
  2428.         }
  2429.       } else {
  2430.         // use moz-collapsed so it doesn't persist hidden/collapsed,
  2431.         // so that new windows don't have missing toolbars
  2432.         if (aShow)
  2433.           els[i].removeAttribute("moz-collapsed");
  2434.         else
  2435.           els[i].setAttribute("moz-collapsed", "true");
  2436.       }
  2437.     }
  2438.     
  2439.     var controls = document.getElementsByAttribute("fullscreencontrol", "true");
  2440.     for (i = 0; i < controls.length; ++i)
  2441.       controls[i].hidden = aShow;
  2442.   }
  2443. };
  2444.  
  2445. function nsBrowserStatusHandler()
  2446. {
  2447.   this.init();
  2448. }
  2449.  
  2450. nsBrowserStatusHandler.prototype =
  2451. {
  2452.   userTyped :
  2453.   {
  2454.     _value : false,
  2455.     browser : null,
  2456.  
  2457.     get value() {
  2458.       if (this.browser != gBrowser.mCurrentBrowser)
  2459.         this._value = false;
  2460.       
  2461.       return this._value;
  2462.     },
  2463.  
  2464.     set value(aValue) {
  2465.       if (this._value != aValue) {
  2466.         this._value = aValue;
  2467.         this.browser = aValue ? gBrowser.mCurrentBrowser : null;
  2468.       }
  2469.  
  2470.       return aValue;
  2471.     }
  2472.   },
  2473.  
  2474.   // Stored Status, Link and Loading values
  2475.   status : "",
  2476.   defaultStatus : "",
  2477.   jsStatus : "",
  2478.   jsDefaultStatus : "",
  2479.   overLink : "",
  2480.   startTime : 0,
  2481.   statusText: "",
  2482.  
  2483.   statusTimeoutInEffect : false,
  2484.  
  2485.   hideAboutBlank : true,
  2486.  
  2487.   QueryInterface : function(aIID)
  2488.   {
  2489.     if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
  2490.         aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
  2491.         aIID.equals(Components.interfaces.nsIXULBrowserWindow) ||
  2492.         aIID.equals(Components.interfaces.nsISupports))
  2493.       return this;
  2494.     throw Components.results.NS_NOINTERFACE;
  2495.   },
  2496.  
  2497.   init : function()
  2498.   {
  2499.     this.throbberElement = document.getElementById("navigator-throbber");
  2500.     this.statusMeter     = document.getElementById("statusbar-icon");
  2501.     this.stopCommand     = document.getElementById("Browser:Stop");
  2502.     this.statusTextField = document.getElementById("statusbar-display");
  2503.     this.securityButton  = document.getElementById("security-button");
  2504.  
  2505.     // Initialize the security button's state and tooltip text
  2506.     const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
  2507.     this.onSecurityChange(null, null, nsIWebProgressListener.STATE_IS_INSECURE);
  2508.   },
  2509.  
  2510.   destroy : function()
  2511.   {
  2512.     // XXXjag to avoid leaks :-/, see bug 60729
  2513.     this.throbberElement = null;
  2514.     this.statusMeter     = null;
  2515.     this.stopCommand     = null;
  2516.     this.statusTextField = null;
  2517.     this.securityButton  = null;
  2518.     this.userTyped       = null;
  2519.     this.statusText      = null;
  2520.   },
  2521.  
  2522.   setJSStatus : function(status)
  2523.   {
  2524.     this.jsStatus = status;
  2525.     this.updateStatusField();
  2526.   },
  2527.  
  2528.   setJSDefaultStatus : function(status)
  2529.   {
  2530.     this.jsDefaultStatus = status;
  2531.     this.updateStatusField();
  2532.   },
  2533.  
  2534.   setDefaultStatus : function(status)
  2535.   {
  2536.     this.defaultStatus = status;
  2537.     this.updateStatusField();
  2538.   },
  2539.  
  2540.   setOverLink : function(link, b)
  2541.   {
  2542.     this.overLink = link;
  2543.     this.updateStatusField();
  2544.   },
  2545.  
  2546.   updateStatusField : function()
  2547.   {
  2548.     var text = this.overLink || this.status || this.jsStatus || this.jsDefaultStatus || this.defaultStatus;
  2549.  
  2550.     // check the current value so we don't trigger an attribute change
  2551.     // and cause needless (slow!) UI updates
  2552.     if (this.statusText != text) {
  2553.       this.statusTextField.label = text;
  2554.       this.statusText = text;
  2555.     }
  2556.   },
  2557.  
  2558.   onLinkIconAvailable : function(aHref) {
  2559.     if (gProxyFavIcon) {
  2560.       
  2561.       // XXXBlake gPrefService.getBoolPref("browser.chrome.site_icons"))
  2562.       gProxyFavIcon.setAttribute("src", aHref);
  2563.     }
  2564.   },
  2565.  
  2566.   onProgressChange : function (aWebProgress, aRequest,
  2567.                                aCurSelfProgress, aMaxSelfProgress,
  2568.                                aCurTotalProgress, aMaxTotalProgress)
  2569.   {
  2570.     if (aMaxTotalProgress > 0) {
  2571.       // This is highly optimized.  Don't touch this code unless
  2572.       // you are intimately familiar with the cost of setting
  2573.       // attrs on XUL elements. -- hyatt
  2574.       var percentage = (aCurTotalProgress * 100) / aMaxTotalProgress;
  2575.       this.statusMeter.value = percentage;
  2576.     } 
  2577.   },
  2578.  
  2579.   onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
  2580.   {  
  2581.     const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
  2582.     const nsIChannel = Components.interfaces.nsIChannel;
  2583.     if (aStateFlags & nsIWebProgressListener.STATE_START) {
  2584.         // This (thanks to the filter) is a network start or the first
  2585.         // stray request (the first request outside of the document load),
  2586.         // initialize the throbber and his friends.
  2587.         
  2588.         // Call start document load listeners (only if this is a network load)
  2589.         if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK &&
  2590.             aRequest && aWebProgress.DOMWindow == content)
  2591.           this.startDocumentLoad(aRequest);
  2592.   
  2593.         if (this.throbberElement) {          
  2594.           // Turn the throbber on.
  2595.           this.throbberElement.setAttribute("busy", "true");
  2596.         }
  2597.  
  2598.         // Turn the status meter on.
  2599.         this.statusMeter.value = 0;  // be sure to clear the progress bar
  2600.         if (gProgressCollapseTimer) {
  2601.           window.clearTimeout(gProgressCollapseTimer);
  2602.           gProgressCollapseTimer = null;
  2603.         }
  2604.         else
  2605.           this.statusMeter.parentNode.collapsed = false;
  2606.  
  2607.         // XXX: This needs to be based on window activity...
  2608.         this.stopCommand.removeAttribute("disabled");
  2609.     }
  2610.     else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
  2611.       if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
  2612.         if (aRequest) {
  2613.           if (aWebProgress.DOMWindow == content)
  2614.             this.endDocumentLoad(aRequest, aStatus);
  2615.         }
  2616.       }
  2617.  
  2618.       // This (thanks to the filter) is a network stop or the last
  2619.       // request stop outside of loading the document, stop throbbers
  2620.       // and progress bars and such
  2621.       if (aRequest) {
  2622.         var msg = "";
  2623.         // Get the channel if the request is a channel
  2624.         var channel;
  2625.         try {
  2626.           channel = aRequest.QueryInterface(nsIChannel);
  2627.         }
  2628.         catch(e) { };
  2629.           if (channel) {
  2630.             var location = channel.URI.spec;
  2631.             if (location != "about:blank") {
  2632.               const kErrorBindingAborted = 2152398850;
  2633.               const kErrorNetTimeout = 2152398862;
  2634.               switch (aStatus) {
  2635.                 case kErrorBindingAborted:
  2636.                   msg = gNavigatorBundle.getString("nv_stopped");
  2637.                   break;
  2638.                 case kErrorNetTimeout:
  2639.                   msg = gNavigatorBundle.getString("nv_timeout");
  2640.                   break;
  2641.               }
  2642.             }
  2643.           }
  2644.           // If msg is false then we did not have an error (channel may have
  2645.           // been null, in the case of a stray image load).
  2646.           if (!msg) {
  2647.             msg = gNavigatorBundle.getString("nv_done");
  2648.           }
  2649.           this.status = "";
  2650.           this.setDefaultStatus(msg);
  2651.         }
  2652.  
  2653.         // Turn the progress meter and throbber off.
  2654.         gProgressCollapseTimer = window.setTimeout("gProgressMeterPanel.collapsed = true; gProgressCollapseTimer = null;",
  2655.                                                    100);
  2656.  
  2657.         if (this.throbberElement)
  2658.           this.throbberElement.removeAttribute("busy");
  2659.  
  2660.         this.stopCommand.setAttribute("disabled", "true");
  2661.     }
  2662.   },
  2663.  
  2664.   onLocationChange : function(aWebProgress, aRequest, aLocation)
  2665.   {
  2666.     this.setOverLink("", null);
  2667.  
  2668.     var location = aLocation.spec;
  2669.  
  2670.     if (this.hideAboutBlank) {
  2671.       this.hideAboutBlank = false;
  2672.       if (location == "about:blank")
  2673.         location = "";
  2674.     }
  2675.  
  2676.     // We should probably not do this if the value has changed since the user
  2677.     // searched
  2678.     // Update urlbar only if a new page was loaded on the primary content area
  2679.     // Do not update urlbar if there was a subframe navigation
  2680.  
  2681.     if (aWebProgress.DOMWindow == content) {
  2682.       //XXXBlake don't we have to reinit this.urlBar, etc.
  2683.       //         when the toolbar changes?
  2684.       if (gURLBar && !this.userTyped.value) {
  2685.         // If the url has "wyciwyg://" as the protocol, strip it off.
  2686.         // Nobody wants to see it on the urlbar for dynamically generated
  2687.         // pages. 
  2688.         if (/^\s*wyciwyg:\/\/\d+\//.test(location))
  2689.           location = RegExp.rightContext;
  2690.         setTimeout(function(loc, aloc) { gURLBar.value = loc; SetPageProxyState("valid", aloc);}, 0, location, aLocation);
  2691.         // the above causes userTyped.value to become true, reset it
  2692.         this.userTyped.value = false;
  2693.       }
  2694.     }
  2695.     UpdateBackForwardButtons();
  2696.   },
  2697.  
  2698.   onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
  2699.   {
  2700.     this.status = aMessage;
  2701.     this.updateStatusField();
  2702.   },
  2703.  
  2704.   onSecurityChange : function(aWebProgress, aRequest, aState)
  2705.   {
  2706.     const wpl = Components.interfaces.nsIWebProgressListener;
  2707.  
  2708.     switch (aState) {
  2709.       case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_HIGH:
  2710.         this.securityButton.setAttribute("level", "high");
  2711.         break;
  2712.       case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_LOW:
  2713.         this.securityButton.setAttribute("level", "low");
  2714.         break;
  2715.       case wpl.STATE_IS_BROKEN:
  2716.         this.securityButton.setAttribute("level", "broken");
  2717.         break;
  2718.       case wpl.STATE_IS_INSECURE:
  2719.       default:
  2720.         this.securityButton.removeAttribute("level");
  2721.         break;
  2722.     }
  2723.  
  2724.     var securityUI = gBrowser.securityUI;
  2725.     if (securityUI)
  2726.       this.securityButton.setAttribute("tooltiptext", securityUI.tooltipText);
  2727.     else
  2728.       this.securityButton.removeAttribute("tooltiptext");
  2729.   },
  2730.  
  2731.   startDocumentLoad : function(aRequest)
  2732.   {
  2733.     // Reset so we can see if the user typed after the document load
  2734.     // starting and the location changing.
  2735.     this.userTyped.value = false;
  2736.  
  2737.     const nsIChannel = Components.interfaces.nsIChannel;
  2738.     var urlStr = aRequest.QueryInterface(nsIChannel).URI.spec;
  2739.     var observerService = Components.classes["@mozilla.org/observer-service;1"]
  2740.                                     .getService(Components.interfaces.nsIObserverService);
  2741.     try {
  2742.       observerService.notifyObservers(_content, "StartDocumentLoad", urlStr);
  2743.     } catch (e) {
  2744.     }
  2745.   },
  2746.  
  2747.   endDocumentLoad : function(aRequest, aStatus)
  2748.   {
  2749.     const nsIChannel = Components.interfaces.nsIChannel;
  2750.     var urlStr = aRequest.QueryInterface(nsIChannel).originalURI.spec;
  2751.  
  2752.     var observerService = Components.classes["@mozilla.org/observer-service;1"]
  2753.                                     .getService(Components.interfaces.nsIObserverService);
  2754.  
  2755.     var notification = Components.isSuccessCode(aStatus) ? "EndDocumentLoad" : "FailDocumentLoad";
  2756.     try {
  2757.       observerService.notifyObservers(_content, notification, urlStr);
  2758.     } catch (e) {
  2759.     }
  2760.   }
  2761. }
  2762.  
  2763. function onViewToolbarsPopupShowing(aEvent)
  2764. {
  2765.   var popup = aEvent.target;
  2766.   var i;
  2767.  
  2768.   // Empty the menu
  2769.   for (i = popup.childNodes.length-1; i >= 0; --i) {
  2770.     var deadItem = popup.childNodes[i];
  2771.     if (deadItem.hasAttribute("toolbarindex"))
  2772.       popup.removeChild(deadItem);
  2773.   }
  2774.   
  2775.   var firstMenuItem = popup.firstChild;
  2776.   
  2777.   var toolbox = document.getElementById("navigator-toolbox");
  2778.   for (i = 0; i < toolbox.childNodes.length; ++i) {
  2779.     var toolbar = toolbox.childNodes[i];
  2780.     var toolbarName = toolbar.getAttribute("toolbarname");
  2781.     var type = toolbar.getAttribute("type");
  2782.     if (toolbarName && type != "menubar") {
  2783.       var menuItem = document.createElement("menuitem");
  2784.       menuItem.setAttribute("toolbarindex", i);
  2785.       menuItem.setAttribute("type", "checkbox");
  2786.       menuItem.setAttribute("label", toolbarName);
  2787.       menuItem.setAttribute("accesskey", toolbar.getAttribute("accesskey"));
  2788.       menuItem.setAttribute("checked", toolbar.getAttribute("collapsed") != "true");
  2789.       popup.insertBefore(menuItem, firstMenuItem);        
  2790.       
  2791.       menuItem.addEventListener("command", onViewToolbarCommand, false);
  2792.     }
  2793.     toolbar = toolbar.nextSibling;
  2794.   }
  2795. }
  2796.  
  2797. function onViewToolbarCommand(aEvent)
  2798. {
  2799.   var toolbox = document.getElementById("navigator-toolbox");
  2800.   var index = aEvent.originalTarget.getAttribute("toolbarindex");
  2801.   var toolbar = toolbox.childNodes[index];
  2802.   
  2803.   toolbar.collapsed = aEvent.originalTarget.getAttribute("checked") != "true";
  2804.   document.persist(toolbar.id, "collapsed");
  2805. }
  2806.  
  2807. function displayPageInfo()
  2808. {
  2809.     window.openDialog("chrome://browser/content/pageInfo.xul", "_blank",
  2810.                       "dialog=no", null, "securityTab");
  2811. }
  2812.  
  2813. function displayPageReportFirstTime()
  2814. {
  2815.     window.openDialog("chrome://browser/content/pageReportFirstTime.xul", "_blank",
  2816.                       "modal");
  2817. }
  2818.  
  2819. function displayPageReport()
  2820. {
  2821.     window.openDialog("chrome://browser/content/pageReport.xul", "_blank",
  2822.                       "dialog=no,modal");
  2823. }
  2824.  
  2825. function nsBrowserContentListener(toplevelWindow, contentWindow)
  2826. {
  2827.     // this one is not as easy as you would hope.
  2828.     // need to convert toplevelWindow to an XPConnected object, instead
  2829.     // of a DOM-based object, to be able to QI() it to nsIXULWindow
  2830.     
  2831.     this.init(toplevelWindow, contentWindow);
  2832. }
  2833.  
  2834. /* implements nsIURIContentListener */
  2835.  
  2836. nsBrowserContentListener.prototype =
  2837. {
  2838.     init: function(toplevelWindow, contentWindow)
  2839.     {
  2840.         const nsIWebBrowserChrome = Components.interfaces.nsIWebBrowserChrome;
  2841.         this.toplevelWindow = toplevelWindow;
  2842.         this.contentWindow = contentWindow;
  2843.  
  2844.         // hook up the whole parent chain thing
  2845.         var windowDocShell = this.convertWindowToDocShell(toplevelWindow);
  2846.         if (windowDocShell)
  2847.             windowDocshell.parentURIContentListener = this;
  2848.     
  2849.         var registerWindow = false;
  2850.         try {          
  2851.           var treeItem = contentWindow.docShell.QueryInterface(Components.interfaces.nsIDocShellTreeItem);
  2852.           var treeOwner = treeItem.treeOwner;
  2853.           var interfaceRequestor = treeOwner.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  2854.           var webBrowserChrome = interfaceRequestor.getInterface(nsIWebBrowserChrome);
  2855.           if (webBrowserChrome)
  2856.           {
  2857.             var chromeFlags = webBrowserChrome.chromeFlags;
  2858.             var res = chromeFlags & nsIWebBrowserChrome.CHROME_ALL;
  2859.             var res2 = chromeFlags & nsIWebBrowserChrome.CHROME_DEFAULT;
  2860.             if ( res == nsIWebBrowserChrome.CHROME_ALL || res2 == nsIWebBrowserChrome.CHROME_DEFAULT)
  2861.             {             
  2862.               registerWindow = true;
  2863.             }
  2864.          }
  2865.        } catch (ex) {} 
  2866.  
  2867.         // register ourselves
  2868.        if (registerWindow)
  2869.        {
  2870.         var uriLoader = Components.classes["@mozilla.org/uriloader;1"].getService(Components.interfaces.nsIURILoader);
  2871.         uriLoader.registerContentListener(this);
  2872.        }
  2873.     },
  2874.     close: function()
  2875.     {
  2876.         this.contentWindow = null;
  2877.         var uriLoader = Components.classes["@mozilla.org/uriloader;1"].getService(Components.interfaces.nsIURILoader);
  2878.  
  2879.         uriLoader.unRegisterContentListener(this);
  2880.     },
  2881.     QueryInterface: function(iid)
  2882.     {
  2883.         if (iid.equals(Components.interfaces.nsIURIContentListener) ||
  2884.             iid.equals(Components.interfaces.nsISupportsWeakReference) ||
  2885.             iid.equals(Components.interfaces.nsISupports))
  2886.           return this;
  2887.         throw Components.results.NS_NOINTERFACE;
  2888.     },
  2889.     onStartURIOpen: function(uri)
  2890.     {
  2891.         // ignore and don't abort
  2892.         return false;
  2893.     },
  2894.  
  2895.     doContent: function(contentType, isContentPreferred, request, contentHandler)
  2896.     {
  2897.         // forward the doContent to our content area webshell
  2898.         var docShell = this.contentWindow.docShell;
  2899.         var contentListener;
  2900.         try {
  2901.             contentListener =
  2902.                 docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  2903.                 .getInterface(Components.interfaces.nsIURIContentListener);
  2904.         } catch (ex) {
  2905.             dump(ex);
  2906.         }
  2907.         
  2908.         if (!contentListener) return false;
  2909.         
  2910.         return contentListener.doContent(contentType, isContentPreferred, request, contentHandler);
  2911.         
  2912.     },
  2913.  
  2914.     isPreferred: function(contentType, desiredContentType)
  2915.     {
  2916.         // seems like we should be getting this from helper apps or something
  2917.         switch(contentType) {
  2918.             case "text/html":
  2919.             case "text/xul":
  2920.             case "text/rdf":
  2921.             case "text/xml":
  2922.             case "text/css":
  2923.             case "image/gif":
  2924.             case "image/jpeg":
  2925.             case "image/png":
  2926.             case "text/plain":
  2927.             case "application/http-index-format":
  2928.                 return true;
  2929.         }
  2930.         return false;
  2931.     },
  2932.     canHandleContent: function(contentType, isContentPreferred, desiredContentType)
  2933.     {
  2934.         var docShell = this.contentWindow.docShell;
  2935.         var contentListener;
  2936.         try {
  2937.             contentListener =
  2938.                 docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIURIContentListener);
  2939.         } catch (ex) {
  2940.             dump(ex);
  2941.         }
  2942.         if (!contentListener) return false;
  2943.         
  2944.         return contentListener.canHandleContent(contentType, isContentPreferred, desiredContentType);
  2945.     },
  2946.     convertWindowToDocShell: function(win) {
  2947.         // don't know how to do this
  2948.         return null;
  2949.     },
  2950.     loadCookie: null,
  2951.     parentContentListener: null
  2952. }
  2953.  
  2954. function toggleSidebar(aCommandID) {
  2955.   if (gInPrintPreviewMode)
  2956.     return;
  2957.   var sidebarBox = document.getElementById("sidebar-box");
  2958.   if (!aCommandID)
  2959.     aCommandID = sidebarBox.getAttribute("sidebarcommand");
  2960.  
  2961.   var elt = document.getElementById(aCommandID);
  2962.   var sidebar = document.getElementById("sidebar");
  2963.   var sidebarTitle = document.getElementById("sidebar-title");
  2964.   var sidebarSplitter = document.getElementById("sidebar-splitter");
  2965.  
  2966.   if (elt.getAttribute("checked") == "true") {
  2967.     elt.removeAttribute("checked");
  2968.     sidebarBox.setAttribute("sidebarcommand", "");
  2969.     sidebarTitle.setAttribute("value", "");
  2970.     sidebarBox.hidden = true;
  2971.     sidebarSplitter.hidden = true;
  2972.     return;
  2973.   }
  2974.   
  2975.   var elts = document.getElementsByAttribute("group", "sidebar");
  2976.   for (var i = 0; i < elts.length; ++i)
  2977.     elts[i].removeAttribute("checked");
  2978.  
  2979.   elt.setAttribute("checked", "true");;
  2980.  
  2981.   if (sidebarBox.hidden) {
  2982.     sidebarBox.hidden = false;
  2983.     sidebarSplitter.hidden = false;
  2984.   }
  2985.   
  2986.   var url = elt.getAttribute("sidebarurl");
  2987.   var title = elt.getAttribute("sidebartitle");
  2988.   if (!title)
  2989.     title = elt.getAttribute("label");
  2990.   sidebar.setAttribute("src", url);
  2991.   sidebarBox.setAttribute("src", url);
  2992.   sidebarBox.setAttribute("sidebarcommand", elt.id);
  2993.   sidebarTitle.setAttribute("value", title);
  2994. }
  2995.  
  2996. function goPreferences(containerID, paneURL, itemID)
  2997. {
  2998.   //check for an existing pref window and focus it; it's not application modal
  2999.   const kWindowMediatorContractID = "@mozilla.org/appshell/window-mediator;1";
  3000.   const kWindowMediatorIID = Components.interfaces.nsIWindowMediator;
  3001.   const kWindowMediator = Components.classes[kWindowMediatorContractID].getService(kWindowMediatorIID);
  3002.   var lastPrefWindow = kWindowMediator.getMostRecentWindow("mozilla:preferences");
  3003.   if (lastPrefWindow)
  3004.     lastPrefWindow.focus();
  3005.   else {
  3006.     var features = "chrome,titlebar,resizable";
  3007.     openDialog("chrome://browser/content/pref/pref.xul","PrefWindow", 
  3008.                features, paneURL, containerID, itemID);
  3009.   }
  3010. }
  3011.  
  3012. function updateHomeTooltip()
  3013. {
  3014.   var homeButton = document.getElementById("home-button");
  3015.   if (homeButton) {
  3016.     var homePage = getHomePage();
  3017.     homeButton.setAttribute("tooltiptext", homePage);
  3018.   }
  3019. }
  3020.  
  3021. function focusSearchBar()
  3022. {
  3023.   var searchBar = document.getElementById("search-bar");
  3024.   if (searchBar) {
  3025.     searchBar.select();
  3026.     searchBar.focus();
  3027.   }
  3028. }
  3029.  
  3030. const IMAGEPERMISSION = 1;
  3031. function nsContextMenu( xulMenu ) {
  3032.     this.target         = null;
  3033.     this.menu           = null;
  3034.     this.onTextInput    = false;
  3035.     this.onImage        = false;
  3036.     this.onLink         = false;
  3037.     this.onMailtoLink   = false;
  3038.     this.onSaveableLink = false;
  3039.     this.onMetaDataItem = false;
  3040.     this.onMathML       = false;
  3041.     this.link           = false;
  3042.     this.inFrame        = false;
  3043.     this.hasBGImage     = false;
  3044.     this.isTextSelected = false;
  3045.     this.inDirList      = false;
  3046.     this.shouldDisplay  = true;
  3047.  
  3048.     // Initialize new menu.
  3049.     this.initMenu( xulMenu );
  3050. }
  3051.  
  3052. // Prototype for nsContextMenu "class."
  3053. nsContextMenu.prototype = {
  3054.     // onDestroy is a no-op at this point.
  3055.     onDestroy : function () {
  3056.     },
  3057.     // Initialize context menu.
  3058.     initMenu : function ( popup ) {
  3059.         // Save menu.
  3060.         this.menu = popup;
  3061.  
  3062.         // Get contextual info.
  3063.         this.setTarget( document.popupNode );
  3064.         
  3065.         this.isTextSelected = this.isTextSelection();
  3066.  
  3067.         // Initialize (disable/remove) menu items.
  3068.         this.initItems();
  3069.     },
  3070.     initItems : function () {
  3071.         this.initOpenItems();
  3072.         this.initNavigationItems();
  3073.         this.initViewItems();
  3074.         this.initMiscItems();
  3075.         this.initSaveItems();
  3076.         this.initClipboardItems();
  3077.         this.initMetadataItems();
  3078.     },
  3079.     initOpenItems : function () {
  3080.         this.showItem( "context-openlink", this.onSaveableLink || ( this.inDirList && this.onLink ) );
  3081.         this.showItem( "context-openlinkintab", this.onSaveableLink || ( this.inDirList && this.onLink ) );
  3082.  
  3083.         this.showItem( "context-sep-open", this.onSaveableLink || ( this.inDirList && this.onLink ) );
  3084.     },
  3085.     initNavigationItems : function () {
  3086.         // Back determined by canGoBack broadcaster.
  3087.         this.setItemAttrFromNode( "context-back", "disabled", "canGoBack" );
  3088.  
  3089.         // Forward determined by canGoForward broadcaster.
  3090.         this.setItemAttrFromNode( "context-forward", "disabled", "canGoForward" );
  3091.         
  3092.         this.showItem( "context-back", !( this.isTextSelected || this.onLink || this.onImage || this.onTextInput ) );
  3093.         this.showItem( "context-forward", !( this.isTextSelected || this.onLink || this.onImage || this.onTextInput ) );
  3094.  
  3095.         this.showItem( "context-reload", !( this.isTextSelected || this.onLink || this.onImage || this.onTextInput ) );
  3096.         
  3097.         this.showItem( "context-stop", !( this.isTextSelected || this.onLink || this.onImage || this.onTextInput ) );
  3098.         this.showItem( "context-sep-stop", !( this.isTextSelected || this.onLink || this.onTextInput ) );
  3099.  
  3100.         // XXX: Stop is determined in navigator.js; the canStop broadcaster is broken
  3101.         //this.setItemAttrFromNode( "context-stop", "disabled", "canStop" );
  3102.     },
  3103.     initSaveItems : function () {
  3104.         this.showItem( "context-savepage", !( this.inDirList || this.isTextSelected || this.onTextInput || this.onLink ));
  3105.  
  3106.         // Save link depends on whether we're in a link.
  3107.         this.showItem( "context-savelink", this.onSaveableLink );
  3108.  
  3109.         // Save image depends on whether there is one.
  3110.         this.showItem( "context-saveimage", this.onImage );
  3111.         
  3112.         this.showItem( "context-sendimage", this.onImage );
  3113.     },
  3114.     initViewItems : function () {
  3115.         // View source is always OK, unless in directory listing.
  3116.         this.showItem( "context-viewpartialsource-selection", this.isTextSelected );
  3117.         this.showItem( "context-viewpartialsource-mathml", this.onMathML && !this.isTextSelected );
  3118.         this.showItem( "context-viewsource", !( this.inDirList || this.onImage || this.isTextSelected || this.onLink || this.onTextInput ) );
  3119.         this.showItem( "context-viewinfo", !( this.inDirList || this.onImage || this.isTextSelected || this.onLink || this.onTextInput ) );
  3120.  
  3121.         this.showItem( "context-sep-properties", !( this.inDirList || this.isTextSelected || this.onTextInput ) );
  3122.         // Set As Wallpaper depends on whether an image was clicked on, and only works on Windows.
  3123.         var isWin = navigator.appVersion.indexOf("Windows") != -1;
  3124.         this.showItem( "context-setWallpaper", isWin && this.onImage );
  3125.  
  3126.         if( isWin && this.onImage )
  3127.             // Disable the Set As Wallpaper menu item if we're still trying to load the image
  3128.           this.setItemAttr( "context-setWallpaper", "disabled", (("complete" in this.target) && !this.target.complete) ? "true" : null );
  3129.  
  3130.         // View Image depends on whether an image was clicked on.
  3131.         this.showItem( "context-viewimage", this.onImage );
  3132.  
  3133.         // View background image depends on whether there is one.
  3134.         this.showItem( "context-viewbgimage", !( this.inDirList || this.onImage || this.isTextSelected || this.onLink || this.onTextInput ) );
  3135.         this.showItem( "context-sep-viewbgimage", !( this.inDirList || this.onImage || this.isTextSelected || this.onLink || this.onTextInput ) );
  3136.         this.setItemAttr( "context-viewbgimage", "disabled", this.hasBGImage ? null : "true");
  3137.     },
  3138.     initMiscItems : function () {
  3139.         // Use "Bookmark This Link" if on a link.
  3140.         this.showItem( "context-bookmarkpage", !( this.isTextSelected || this.onTextInput || this.onLink ) );
  3141.         this.showItem( "context-bookmarklink", this.onLink && !this.onMailtoLink );
  3142.         this.showItem( "context-searchselect", this.isTextSelected );
  3143.         this.showItem( "frame", this.inFrame );
  3144.         this.showItem( "frame-sep", this.inFrame );
  3145.         this.showItem( "context-blockimage", this.onImage);
  3146.         if (this.onImage) {
  3147.           var blockImage = document.getElementById("context-blockimage");
  3148.           if (this.isImageBlocked()) {
  3149.             blockImage.setAttribute("checked", "true");
  3150.           }
  3151.           else
  3152.             blockImage.removeAttribute("checked");
  3153.         }
  3154.     },
  3155.     initClipboardItems : function () {
  3156.  
  3157.         // Copy depends on whether there is selected text.
  3158.         // Enabling this context menu item is now done through the global
  3159.         // command updating system
  3160.         // this.setItemAttr( "context-copy", "disabled", !this.isTextSelected() );
  3161.  
  3162.         goUpdateGlobalEditMenuItems();
  3163.  
  3164.         this.showItem( "context-undo", this.isTextSelected || this.onTextInput );
  3165.         this.showItem( "context-sep-undo", this.isTextSelected || this.onTextInput );
  3166.         this.showItem( "context-cut", this.isTextSelected || this.onTextInput );
  3167.         this.showItem( "context-copy", this.isTextSelected || this.onTextInput );
  3168.         this.showItem( "context-paste", this.isTextSelected || this.onTextInput );
  3169.         this.showItem( "context-delete", this.isTextSelected || this.onTextInput );
  3170.         this.showItem( "context-sep-paste", this.isTextSelected || this.onTextInput );
  3171.         this.showItem( "context-selectall", this.isTextSelected || this.onTextInput );
  3172.         this.showItem( "context-sep-selectall", this.isTextSelected );
  3173.  
  3174.         // XXX dr
  3175.         // ------
  3176.         // nsDocumentViewer.cpp has code to determine whether we're
  3177.         // on a link or an image. we really ought to be using that...
  3178.  
  3179.         // Copy email link depends on whether we're on an email link.
  3180.         this.showItem( "context-copyemail", this.onMailtoLink );
  3181.  
  3182.         // Copy link location depends on whether we're on a link.
  3183.         this.showItem( "context-copylink", this.onLink );
  3184.         this.showItem( "context-sep-copylink", this.onLink && this.onImage);
  3185.  
  3186.         // Copy image location depends on whether we're on an image.
  3187.         this.showItem( "context-copyimage", this.onImage );
  3188.         this.showItem( "context-sep-copyimage", this.onImage );
  3189.     },
  3190.     initMetadataItems : function () {
  3191.         // Show if user clicked on something which has metadata.
  3192.         this.showItem( "context-metadata", this.onMetaDataItem );
  3193.     },
  3194.     // Set various context menu attributes based on the state of the world.
  3195.     setTarget : function ( node ) {
  3196.         const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  3197.         if ( node.namespaceURI == xulNS ) {
  3198.           this.shouldDisplay = false;
  3199.           return;
  3200.         }
  3201.         // Initialize contextual info.
  3202.         this.onImage    = false;
  3203.         this.onMetaDataItem = false;
  3204.         this.onTextInput = false;
  3205.         this.imageURL   = "";
  3206.         this.onLink     = false;
  3207.         this.onMathML   = false;
  3208.         this.inFrame    = false;
  3209.         this.hasBGImage = false;
  3210.         this.bgImageURL = "";
  3211.  
  3212.         // Remember the node that was clicked.
  3213.         this.target = node;
  3214.  
  3215.         // See if the user clicked on an image.
  3216.         if ( this.target.nodeType == Node.ELEMENT_NODE ) {
  3217.              if ( this.target.localName.toUpperCase() == "IMG" ) {
  3218.                 this.onImage = true;
  3219.                 this.imageURL = this.target.src;
  3220.                 // Look for image map.
  3221.                 var mapName = this.target.getAttribute( "usemap" );
  3222.                 if ( mapName ) {
  3223.                     // Find map.
  3224.                     var map = this.target.ownerDocument.getElementById( mapName.substr(1) );
  3225.                     if ( map ) {
  3226.                         // Search child <area>s for a match.
  3227.                         var areas = map.childNodes;
  3228.                         //XXX Client side image maps are too hard for now!
  3229.                         areas.length = 0;
  3230.                         for ( var i = 0; i < areas.length && !this.onLink; i++ ) {
  3231.                             var area = areas[i];
  3232.                             if ( area.nodeType == Node.ELEMENT_NODE
  3233.                                  &&
  3234.                                  area.localName.toUpperCase() == "AREA" ) {
  3235.                                 // Get type (rect/circle/polygon/default).
  3236.                                 var type = area.getAttribute( "type" );
  3237.                                 var coords = this.parseCoords( area );
  3238.                                 switch ( type.toUpperCase() ) {
  3239.                                     case "RECT":
  3240.                                     case "RECTANGLE":
  3241.                                         break;
  3242.                                     case "CIRC":
  3243.                                     case "CIRCLE":
  3244.                                         break;
  3245.                                     case "POLY":
  3246.                                     case "POLYGON":
  3247.                                         break;
  3248.                                     case "DEFAULT":
  3249.                                         // Default matches entire image.
  3250.                                         this.onLink = true;
  3251.                                         this.link = area;
  3252.                                         this.onSaveableLink = this.isLinkSaveable( this.link );
  3253.                                         break;
  3254.                                 }
  3255.                             }
  3256.                         }
  3257.                     }
  3258.                 }
  3259.              } else if ( this.target.localName.toUpperCase() == "OBJECT"
  3260.                          &&
  3261.                          // See if object tag is for an image.
  3262.                          this.objectIsImage( this.target ) ) {
  3263.                 // This is an image.
  3264.                 this.onImage = true;
  3265.                 // URL must be constructed.
  3266.                 this.imageURL = this.objectImageURL( this.target );
  3267.              } else if ( this.target.localName.toUpperCase() == "INPUT") {
  3268.                type = this.target.getAttribute("type");
  3269.                if(type && type.toUpperCase() == "IMAGE") {
  3270.                  this.onImage = true;
  3271.                  // Convert src attribute to absolute URL.
  3272.                  this.imageURL = makeURLAbsolute( this.target.baseURI,
  3273.                                                   this.target.src );
  3274.                } else /* if (this.target.getAttribute( "type" ).toUpperCase() == "TEXT") */ {
  3275.                  this.onTextInput = this.isTargetATextBox(this.target);
  3276.                }
  3277.             } else if ( this.target.localName.toUpperCase() == "TEXTAREA" ) {
  3278.                  this.onTextInput = true;
  3279.             } else if ( this.target.localName.toUpperCase() == "HTML" ) {
  3280.                // pages with multiple <body>s are lame. we'll teach them a lesson.
  3281.                var bodyElt = this.target.ownerDocument.getElementsByTagName("body")[0];
  3282.                if ( bodyElt ) {
  3283.                  var computedURL = this.getComputedURL( bodyElt, "background-image" );
  3284.                  if ( computedURL ) {
  3285.                    this.hasBGImage = true;
  3286.                    this.bgImageURL = makeURLAbsolute( bodyElt.baseURI,
  3287.                                                       computedURL );
  3288.                  }
  3289.                }
  3290.             } else if ( "HTTPIndex" in _content &&
  3291.                         _content.HTTPIndex instanceof Components.interfaces.nsIHTTPIndex ) {
  3292.                 this.inDirList = true;
  3293.                 // Bubble outward till we get to an element with URL attribute
  3294.                 // (which should be the href).
  3295.                 var root = this.target;
  3296.                 while ( root && !this.link ) {
  3297.                     if ( root.tagName == "tree" ) {
  3298.                         // Hit root of tree; must have clicked in empty space;
  3299.                         // thus, no link.
  3300.                         break;
  3301.                     }
  3302.                     if ( root.getAttribute( "URL" ) ) {
  3303.                         // Build pseudo link object so link-related functions work.
  3304.                         this.onLink = true;
  3305.                         this.link = { href : root.getAttribute("URL"),
  3306.                                       getAttribute: function (attr) {
  3307.                                           if (attr == "title") {
  3308.                                               return root.firstChild.firstChild.getAttribute("label");
  3309.                                           } else {
  3310.                                               return "";
  3311.                                           }
  3312.                                       }
  3313.                                     };
  3314.                         // If element is a directory, then you can't save it.
  3315.                         if ( root.getAttribute( "container" ) == "true" ) {
  3316.                             this.onSaveableLink = false;
  3317.                         } else {
  3318.                             this.onSaveableLink = true;
  3319.                         }
  3320.                     } else {
  3321.                         root = root.parentNode;
  3322.                     }
  3323.                 }
  3324.             }
  3325.         }
  3326.  
  3327.         // We have meta data on images.
  3328.         this.onMetaDataItem = this.onImage;
  3329.         
  3330.         // See if the user clicked on MathML
  3331.         const NS_MathML = "http://www.w3.org/1998/Math/MathML";
  3332.         if ((this.target.nodeType == Node.TEXT_NODE &&
  3333.              this.target.parentNode.namespaceURI == NS_MathML)
  3334.              || (this.target.namespaceURI == NS_MathML))
  3335.           this.onMathML = true;
  3336.  
  3337.         // See if the user clicked in a frame.
  3338.         if ( this.target.ownerDocument != window._content.document ) {
  3339.             this.inFrame = true;
  3340.         }
  3341.         
  3342.         // Bubble out, looking for items of interest
  3343.         var elem = this.target;
  3344.         while ( elem ) {
  3345.             if ( elem.nodeType == Node.ELEMENT_NODE ) {
  3346.                 var localname = elem.localName.toUpperCase();
  3347.                 
  3348.                 // Link?
  3349.                 if ( !this.onLink && 
  3350.                     ( (localname === "A" && elem.href) ||
  3351.                       localname === "AREA" ||
  3352.                       localname === "LINK" ||
  3353.                       elem.getAttributeNS( "http://www.w3.org/1999/xlink", "type") == "simple" ) ) {
  3354.                     // Clicked on a link.
  3355.                     this.onLink = true;
  3356.                     this.onMetaDataItem = true;
  3357.                     // Remember corresponding element.
  3358.                     this.link = elem;
  3359.                     this.onMailtoLink = this.isLinkType( "mailto:", this.link );
  3360.                     // Remember if it is saveable.
  3361.                     this.onSaveableLink = this.isLinkSaveable( this.link );
  3362.                 }
  3363.                 
  3364.                 // Text input?
  3365.                 if ( !this.onTextInput ) {
  3366.                     // Clicked on a link.
  3367.                     this.onTextInput = this.isTargetATextBox(elem);
  3368.                 }
  3369.                 
  3370.                 // Metadata item?
  3371.                 if ( !this.onMetaDataItem ) {
  3372.                     // We currently display metadata on anything which fits
  3373.                     // the below test.
  3374.                     if ( ( localname === "BLOCKQUOTE" && 'cite' in elem && elem.cite)  ||
  3375.                          ( localname === "Q" && 'cite' in elem && elem.cite)           ||
  3376.                          ( localname === "TABLE" && 'summary' in elem && elem.summary) ||
  3377.                          ( ( localname === "INS" || localname === "DEL" ) &&
  3378.                            ( ( 'cite' in elem && elem.cite ) ||
  3379.                              ( 'dateTime' in elem && elem.dateTime ) ) )               ||
  3380.                          ( 'title' in elem && elem.title )                             ||
  3381.                          ( 'lang' in elem && elem.lang ) ) {
  3382.                         dump("On metadata item.\n");
  3383.                         this.onMetaDataItem = true;
  3384.                     }
  3385.                 }
  3386.  
  3387.                 // Background image?  Don't bother if we've already found a 
  3388.                 // background image further down the hierarchy.  Otherwise,
  3389.                 // we look for the computed background-image style.
  3390.                 if ( !this.hasBGImage ) {
  3391.                     var bgImgUrl = this.getComputedURL( elem, "background-image" );
  3392.                     if ( bgImgUrl ) {
  3393.                         this.hasBGImage = true;
  3394.                         this.bgImageURL = makeURLAbsolute( elem.baseURI,
  3395.                                                            bgImgUrl );
  3396.                     }
  3397.                 }
  3398.             }
  3399.             elem = elem.parentNode;    
  3400.         }
  3401.     },
  3402.     // Returns the computed style attribute for the given element.
  3403.     getComputedStyle: function( elem, prop ) {
  3404.          return elem.ownerDocument.defaultView.getComputedStyle( elem, '' ).getPropertyValue( prop );
  3405.     },
  3406.     // Returns a "url"-type computed style attribute value, with the url() stripped.
  3407.     getComputedURL: function( elem, prop ) {
  3408.          var url = elem.ownerDocument.defaultView.getComputedStyle( elem, '' ).getPropertyCSSValue( prop );
  3409.          return ( url.primitiveType == CSSPrimitiveValue.CSS_URI ) ? url.getStringValue() : null;
  3410.     },
  3411.     // Returns true iff clicked on link is saveable.
  3412.     isLinkSaveable : function ( link ) {
  3413.         // We don't do the Right Thing for news/snews yet, so turn them off
  3414.         // until we do.
  3415.         return !(this.isLinkType( "mailto:" , link )     ||
  3416.                  this.isLinkType( "javascript:" , link ) ||
  3417.                  this.isLinkType( "news:", link )        || 
  3418.                  this.isLinkType( "snews:", link ) ); 
  3419.     },
  3420.     // Returns true iff clicked on link is of type given.
  3421.     isLinkType : function ( linktype, link ) {        
  3422.         try {
  3423.             // Test for missing protocol property.
  3424.             if ( !link.protocol ) {
  3425.                 // We must resort to testing the URL string :-(.
  3426.                 var protocol;
  3427.                 if ( link.href ) {
  3428.                     protocol = link.href.substr( 0, linktype.length );
  3429.                 } else {
  3430.                     protocol = link.getAttributeNS("http://www.w3.org/1999/xlink","href");
  3431.                     if ( protocol ) {
  3432.                         protocol = protocol.substr( 0, linktype.length );
  3433.                     }
  3434.                 }
  3435.                 return protocol.toLowerCase() === linktype;        
  3436.             } else {
  3437.                 // Presume all but javascript: urls are saveable.
  3438.                 return link.protocol.toLowerCase() === linktype;
  3439.             }
  3440.         } catch (e) {
  3441.             // something was wrong with the link,
  3442.             // so we won't be able to save it anyway
  3443.             return false;
  3444.         }
  3445.     },
  3446.     // Open linked-to URL in a new window.
  3447.     openLink : function () {
  3448.         // Determine linked-to URL.
  3449.         openNewWindowWith(this.linkURL(), this.link, true);
  3450.     },
  3451.     // Open linked-to URL in a new tab.
  3452.     openLinkInTab : function () {
  3453.         // Determine linked-to URL.
  3454.         openNewTabWith(this.linkURL(), this.link, null, true);
  3455.     },
  3456.     // Open frame in a new tab.
  3457.     openFrameInTab : function () {
  3458.         // Determine linked-to URL.
  3459.         openNewTabWith(this.target.ownerDocument.location.href, null, null, true);
  3460.     },
  3461.     // Reload clicked-in frame.
  3462.     reloadFrame : function () {
  3463.         this.target.ownerDocument.location.reload();
  3464.     },
  3465.     // Open clicked-in frame in its own window.
  3466.     openFrame : function () {
  3467.         openNewWindowWith(this.target.ownerDocument.location.href, null, true);
  3468.     },
  3469.     // Open clicked-in frame in the same window
  3470.     showOnlyThisFrame : function () {
  3471.         window.loadURI(this.target.ownerDocument.location.href);
  3472.     },
  3473.     // View Partial Source
  3474.     viewPartialSource : function ( context ) {
  3475.         var focusedWindow = document.commandDispatcher.focusedWindow;
  3476.         if (focusedWindow == window)
  3477.           focusedWindow = _content;
  3478.         var docCharset = null;
  3479.         if (focusedWindow)
  3480.           docCharset = "charset=" + focusedWindow.document.characterSet;
  3481.  
  3482.         // "View Selection Source" and others such as "View MathML Source"
  3483.         // are mutually exclusive, with the precedence given to the selection
  3484.         // when there is one
  3485.         var reference = null;
  3486.         if (context == "selection")
  3487.           reference = focusedWindow.__proto__.getSelection.call(focusedWindow);
  3488.         else if (context == "mathml")
  3489.           reference = this.target;
  3490.         else
  3491.           throw "not reached";
  3492.  
  3493.         var docUrl = null; // unused (and play nice for fragments generated via XSLT too)
  3494.         window.openDialog("chrome://browser/content/viewPartialSource.xul",
  3495.                           "_blank", "scrollbars,resizable,chrome,dialog=no",
  3496.                           docUrl, docCharset, reference, context);
  3497.     },
  3498.     // Open new "view source" window with the frame's URL.
  3499.     viewFrameSource : function () {
  3500.         BrowserViewSourceOfDocument(this.target.ownerDocument);
  3501.     },
  3502.     viewInfo : function () {
  3503.       BrowserPageInfo();
  3504.     },
  3505.     viewFrameInfo : function () {
  3506.       BrowserPageInfo(this.target.ownerDocument);
  3507.     },
  3508.     // Change current window to the URL of the image.
  3509.     viewImage : function () {
  3510.         openTopWin( this.imageURL );
  3511.     },
  3512.     // Change current window to the URL of the background image.
  3513.     viewBGImage : function () {
  3514.         openTopWin( this.bgImageURL );
  3515.     },
  3516.     setWallpaper: function() {
  3517.       var winhooks = Components.classes[ "@mozilla.org/winhooks;1" ].
  3518.                        getService(Components.interfaces.nsIWindowsHooks);
  3519.       
  3520.       winhooks.setImageAsWallpaper(this.target, false);
  3521.     },    
  3522.     // Save URL of clicked-on frame.
  3523.     saveFrame : function () {
  3524.         saveDocument( this.target.ownerDocument );
  3525.     },
  3526.     // Save URL of clicked-on link.
  3527.     saveLink : function () {
  3528.         saveURL( this.linkURL(), this.linkText(), null, true );
  3529.     },
  3530.     // Save URL of clicked-on image.
  3531.     saveImage : function () {
  3532.         saveURL( this.imageURL, null, "SaveImageTitle", false );
  3533.     },
  3534.     toggleImageBlocking : function (aBlock) {
  3535.       var permissionmanager =
  3536.         Components.classes["@mozilla.org/permissionmanager;1"]
  3537.           .getService(Components.interfaces.nsIPermissionManager);
  3538.       permissionmanager.add(this.imageURL, !aBlock, IMAGEPERMISSION);
  3539.     },
  3540.     isImageBlocked : function() {
  3541.        var permissionmanager =
  3542.          Components.classes["@mozilla.org/permissionmanager;1"]
  3543.            .getService(Components.interfaces.nsIPermissionManager);
  3544.        return permissionmanager.testForBlocking(this.imageURL, IMAGEPERMISSION);
  3545.     },
  3546.     // Generate email address and put it on clipboard.
  3547.     copyEmail : function () {
  3548.         // Copy the comma-separated list of email addresses only.
  3549.         // There are other ways of embedding email addresses in a mailto:
  3550.         // link, but such complex parsing is beyond us.
  3551.         var url = this.linkURL();
  3552.         var qmark = url.indexOf( "?" );
  3553.         var addresses;
  3554.         
  3555.         if ( qmark > 7 ) {                   // 7 == length of "mailto:"
  3556.             addresses = url.substring( 7, qmark );
  3557.         } else {
  3558.             addresses = url.substr( 7 );
  3559.         }
  3560.  
  3561.         var clipboard = this.getService( "@mozilla.org/widget/clipboardhelper;1",
  3562.                                          Components.interfaces.nsIClipboardHelper );
  3563.         clipboard.copyString(addresses);
  3564.     },    
  3565.     addBookmark : function() {
  3566.       var docshell = document.getElementById( "content" ).webNavigation;
  3567.       BookmarksUtils.addBookmark( docshell.currentURI.spec,
  3568.                                   docshell.document.title,
  3569.                                   docshell.document.charset,
  3570.                                   false );
  3571.     },
  3572.     addBookmarkForFrame : function() {
  3573.       var doc = this.target.ownerDocument;
  3574.       var uri = doc.location.href;
  3575.       var title = doc.title;
  3576.       if ( !title )
  3577.         title = uri;
  3578.       BookmarksUtils.addBookmark( uri,
  3579.                                   title,
  3580.                                   doc.charset,
  3581.                                   false );
  3582.     },
  3583.     // Open Metadata window for node
  3584.     showMetadata : function () {
  3585.         window.openDialog(  "chrome://navigator/content/metadata.xul",
  3586.                             "_blank",
  3587.                             "scrollbars,resizable,chrome,dialog=no",
  3588.                             this.target);
  3589.     },
  3590.  
  3591.     ///////////////
  3592.     // Utilities //
  3593.     ///////////////
  3594.  
  3595.     // Create instance of component given contractId and iid (as string).
  3596.     createInstance : function ( contractId, iidName ) {
  3597.         var iid = Components.interfaces[ iidName ];
  3598.         return Components.classes[ contractId ].createInstance( iid );
  3599.     },
  3600.     // Get service given contractId and iid (as string).
  3601.     getService : function ( contractId, iidName ) {
  3602.         var iid = Components.interfaces[ iidName ];
  3603.         return Components.classes[ contractId ].getService( iid );
  3604.     },
  3605.     // Show/hide one item (specified via name or the item element itself).
  3606.     showItem : function ( itemOrId, show ) {
  3607.         var item = itemOrId.constructor == String ? document.getElementById(itemOrId) : itemOrId;
  3608.         if (item) 
  3609.           item.hidden = !show;
  3610.     },
  3611.     // Set given attribute of specified context-menu item.  If the
  3612.     // value is null, then it removes the attribute (which works
  3613.     // nicely for the disabled attribute).
  3614.     setItemAttr : function ( id, attr, val ) {
  3615.         var elem = document.getElementById( id );
  3616.         if ( elem ) {
  3617.             if ( val == null ) {
  3618.                 // null indicates attr should be removed.
  3619.                 elem.removeAttribute( attr );
  3620.             } else {
  3621.                 // Set attr=val.
  3622.                 elem.setAttribute( attr, val );
  3623.             }
  3624.         }
  3625.     },
  3626.     // Set context menu attribute according to like attribute of another node
  3627.     // (such as a broadcaster).
  3628.     setItemAttrFromNode : function ( item_id, attr, other_id ) {
  3629.         var elem = document.getElementById( other_id );
  3630.         if ( elem && elem.getAttribute( attr ) == "true" ) {
  3631.             this.setItemAttr( item_id, attr, "true" );
  3632.         } else {
  3633.             this.setItemAttr( item_id, attr, null );
  3634.         }
  3635.     },
  3636.     // Temporary workaround for DOM api not yet implemented by XUL nodes.
  3637.     cloneNode : function ( item ) {
  3638.         // Create another element like the one we're cloning.
  3639.         var node = document.createElement( item.tagName );
  3640.  
  3641.         // Copy attributes from argument item to the new one.
  3642.         var attrs = item.attributes;
  3643.         for ( var i = 0; i < attrs.length; i++ ) {
  3644.             var attr = attrs.item( i );
  3645.             node.setAttribute( attr.nodeName, attr.nodeValue );
  3646.         }
  3647.  
  3648.         // Voila!
  3649.         return node;
  3650.     },
  3651.     // Generate fully-qualified URL for clicked-on link.
  3652.     linkURL : function () {
  3653.         if (this.link.href) {
  3654.           return this.link.href;
  3655.         }
  3656.         var href = this.link.getAttributeNS("http://www.w3.org/1999/xlink","href");
  3657.         if (!href || !href.match(/\S/)) {
  3658.           throw "Empty href"; // Without this we try to save as the current doc, for example, HTML case also throws if empty
  3659.         }
  3660.         href = makeURLAbsolute(this.link.baseURI,href);
  3661.         return href;
  3662.     },
  3663.     // Get text of link.
  3664.     linkText : function () {
  3665.         var text = gatherTextUnder( this.link );
  3666.         if (!text || !text.match(/\S/)) {
  3667.           text = this.link.getAttribute("title");
  3668.           if (!text || !text.match(/\S/)) {
  3669.             text = this.link.getAttribute("alt");
  3670.             if (!text || !text.match(/\S/)) {
  3671.               if (this.link.href) {                
  3672.                 text = this.link.href;
  3673.               } else {
  3674.                 text = getAttributeNS("http://www.w3.org/1999/xlink", "href");
  3675.                 if (text && text.match(/\S/)) {
  3676.                   text = makeURLAbsolute(this.link.baseURI, text);
  3677.                 }
  3678.               }
  3679.             }
  3680.           }
  3681.         }
  3682.  
  3683.         return text;
  3684.     },
  3685.  
  3686.     //Get selected object and convert it to a string to get
  3687.     //selected text.   Only use the first 15 chars.
  3688.     isTextSelection : function() {
  3689.         var result = false;
  3690.         var selection = this.searchSelected();
  3691.  
  3692.         var searchSelectText;
  3693.         if (selection != "") {
  3694.             searchSelectText = selection.toString();
  3695.             if (searchSelectText.length > 15)
  3696.                 searchSelectText = searchSelectText.substr(0,15) + "...";
  3697.             result = true;
  3698.  
  3699.           // format "Search for <selection>" string to show in menu
  3700.           searchSelectText = gNavigatorBundle.getFormattedString("searchText", [searchSelectText]);
  3701.           this.setItemAttr("context-searchselect", "label", searchSelectText);
  3702.         } 
  3703.         return result;
  3704.     },
  3705.     
  3706.     searchSelected : function() {
  3707.         var focusedWindow = document.commandDispatcher.focusedWindow;
  3708.         var searchStr = focusedWindow.__proto__.getSelection.call(focusedWindow);
  3709.         searchStr = searchStr.toString();
  3710.         searchStr = searchStr.replace( /^\s+/, "" );
  3711.         searchStr = searchStr.replace(/(\n|\r|\t)+/g, " ");
  3712.         searchStr = searchStr.replace(/\s+$/,"");
  3713.         return searchStr;
  3714.     },
  3715.     
  3716.     // Determine if target <object> is an image.
  3717.     objectIsImage : function ( objElem ) {
  3718.         var result = false;
  3719.         // Get type and data attributes.
  3720.         var type = objElem.getAttribute( "type" );
  3721.         var data = objElem.getAttribute( "data" );
  3722.         // Presume any mime type of the form "image/..." is an image.
  3723.         // There must be a data= attribute with an URL, also.
  3724.         if ( type.substring( 0, 6 ) == "image/" && data && data != "" ) {
  3725.             result = true;
  3726.         }
  3727.         return result;
  3728.     },
  3729.     // Extract image URL from <object> tag.
  3730.     objectImageURL : function ( objElem ) {
  3731.         // Extract url from data= attribute.
  3732.         var data = objElem.getAttribute( "data" );
  3733.         // Make it absolute.
  3734.         return makeURLAbsolute( objElem.baseURI, data );
  3735.     },
  3736.     // Parse coords= attribute and return array.
  3737.     parseCoords : function ( area ) {
  3738.         return [];
  3739.     },
  3740.     toString : function () {
  3741.         return "contextMenu.target     = " + this.target + "\n" +
  3742.                "contextMenu.onImage    = " + this.onImage + "\n" +
  3743.                "contextMenu.onLink     = " + this.onLink + "\n" +
  3744.                "contextMenu.link       = " + this.link + "\n" +
  3745.                "contextMenu.inFrame    = " + this.inFrame + "\n" +
  3746.                "contextMenu.hasBGImage = " + this.hasBGImage + "\n";
  3747.     },
  3748.     isTargetATextBox : function ( node )
  3749.     {
  3750.       if (node.nodeType != Node.ELEMENT_NODE)
  3751.         return false;
  3752.  
  3753.       if (node.localName.toUpperCase() == "INPUT") {
  3754.         var attrib = "";
  3755.         var type = node.getAttribute("type");
  3756.  
  3757.         if (type)
  3758.           attrib = type.toUpperCase();
  3759.  
  3760.         return( (attrib != "IMAGE") &&
  3761.                 (attrib != "CHECKBOX") &&
  3762.                 (attrib != "RADIO") &&
  3763.                 (attrib != "SUBMIT") &&
  3764.                 (attrib != "RESET") &&
  3765.                 (attrib != "FILE") &&
  3766.                 (attrib != "HIDDEN") &&
  3767.                 (attrib != "RESET") &&
  3768.                 (attrib != "BUTTON") );
  3769.       } else  {
  3770.         return(node.localName.toUpperCase() == "TEXTAREA");
  3771.       }
  3772.     },
  3773.     
  3774.     // Determines whether or not the separator with the specified ID should be 
  3775.     // shown or not by determining if there are any non-hidden items between it
  3776.     // and the previous separator. 
  3777.     shouldShowSeparator : function ( aSeparatorID )
  3778.     {
  3779.       var separator = document.getElementById(aSeparatorID);
  3780.       if (separator) {
  3781.         var sibling = separator.previousSibling;
  3782.         while (sibling && sibling.localName != "menuseparator") {
  3783.           if (sibling.getAttribute("hidden") != "true")
  3784.             return true;
  3785.           sibling = sibling.previousSibling;
  3786.         }
  3787.       }
  3788.       return false;  
  3789.     }
  3790. };
  3791.  
  3792. /*************************************************************************
  3793.  *
  3794.  *   nsDefaultEngine : nsIObserver
  3795.  *
  3796.  *************************************************************************/
  3797. function nsDefaultEngine()
  3798. {
  3799.     try
  3800.     {
  3801.         var pb = Components.classes["@mozilla.org/preferences-service;1"].
  3802.                    getService(Components.interfaces.nsIPrefBranch);
  3803.         var pbi = pb.QueryInterface(
  3804.                     Components.interfaces.nsIPrefBranchInternal);
  3805.         pbi.addObserver(this.domain, this, false);
  3806.  
  3807.         // reuse code by explicitly invoking initial |observe| call
  3808.         // to initialize the |icon| and |name| member variables
  3809.         this.observe(pb, "", this.domain);
  3810.     }
  3811.     catch (ex)
  3812.     {
  3813.     }
  3814. }
  3815.  
  3816. nsDefaultEngine.prototype = 
  3817. {
  3818.     name: "",
  3819.     icon: "",
  3820.     domain: "browser.search.defaultengine",
  3821.  
  3822.     // nsIObserver implementation
  3823.     observe: function(aPrefBranch, aTopic, aPrefName)
  3824.     {
  3825.         try
  3826.         {
  3827.             var rdf = Components.
  3828.                         classes["@mozilla.org/rdf/rdf-service;1"].
  3829.                         getService(Components.interfaces.nsIRDFService);
  3830.             var ds = rdf.GetDataSource("rdf:internetsearch");
  3831.             var defaultEngine = aPrefBranch.getCharPref(aPrefName);
  3832.             var res = rdf.GetResource(defaultEngine);
  3833.  
  3834.             // get engine ``pretty'' name
  3835.             const kNC_Name = rdf.GetResource(
  3836.                                "http://home.netscape.com/NC-rdf#Name");
  3837.             var engineName = ds.GetTarget(res, kNC_Name, true);
  3838.             if (engineName)
  3839.             {
  3840.                 this.name = engineName.QueryInterface(
  3841.                               Components.interfaces.nsIRDFLiteral).Value;
  3842.             }
  3843.  
  3844.             // get URL to engine vendor icon
  3845.             const kNC_Icon = rdf.GetResource(
  3846.                                "http://home.netscape.com/NC-rdf#Icon");
  3847.             var iconURL = ds.GetTarget(res, kNC_Icon, true);
  3848.             if (iconURL)
  3849.             {
  3850.                 this.icon = iconURL.QueryInterface(
  3851.                   Components.interfaces.nsIRDFLiteral).Value;
  3852.             }
  3853.         }
  3854.         catch (ex)
  3855.         {
  3856.         }
  3857.     }
  3858. }
  3859.  
  3860. /*
  3861.  * - [ Dependencies ] ---------------------------------------------------------
  3862.  *  utilityOverlay.js:
  3863.  *    - gatherTextUnder
  3864.  */
  3865.  
  3866.  // Called whenever the user clicks in the content area,
  3867.  // except when left-clicking on links (special case)
  3868.  // should always return true for click to go through
  3869.  function contentAreaClick(event) 
  3870.  {
  3871.    var target = event.target;
  3872.    var linkNode;
  3873.  
  3874.    var local_name = target.localName;
  3875.  
  3876.    if (local_name) {
  3877.      local_name = local_name.toLowerCase();
  3878.    }
  3879.  
  3880.    switch (local_name) {
  3881.      case "a":
  3882.      case "area":
  3883.      case "link":
  3884.        if (target.hasAttribute("href")) 
  3885.          linkNode = target;
  3886.        break;
  3887.      default:
  3888.        linkNode = findParentNode(event.originalTarget, "a");
  3889.        // <a> cannot be nested.  So if we find an anchor without an
  3890.        // href, there is no useful <a> around the target
  3891.        if (linkNode && !linkNode.hasAttribute("href"))
  3892.          linkNode = null;
  3893.        break;
  3894.    }
  3895.    if (linkNode) {
  3896.      handleLinkClick(event, linkNode.href, linkNode);
  3897.      return true;
  3898.    } else {
  3899.      // Try simple XLink
  3900.      var href;
  3901.      linkNode = target;
  3902.      while (linkNode) {
  3903.        if (linkNode.nodeType == Node.ELEMENT_NODE) {
  3904.          href = linkNode.getAttributeNS("http://www.w3.org/1999/xlink", "href");
  3905.          break;
  3906.        }
  3907.        linkNode = linkNode.parentNode;
  3908.      }
  3909.      if (href && href != "") {
  3910.        href = makeURLAbsolute(target.baseURI,href);
  3911.        handleLinkClick(event, href, null);
  3912.        return true;
  3913.      }
  3914.    }
  3915.    if (event.button == 1 &&
  3916.        !findParentNode(event.originalTarget, "scrollbar") &&
  3917.        gPrefService.getBoolPref("middlemouse.contentLoadURL")) {
  3918.      if (middleMousePaste(event)) {
  3919.        event.preventBubble();
  3920.      }
  3921.    }
  3922.    return true;
  3923.  }
  3924.  
  3925. function handleLinkClick(event, href, linkNode)
  3926. {
  3927.   switch (event.button) {                                   
  3928.     case 0:  
  3929.       if (event.ctrlKey) {
  3930.         openNewTabWith(href, linkNode, event, true);
  3931.         event.preventBubble();
  3932.         return true;
  3933.       } 
  3934.                                                        // if left button clicked
  3935.       if (event.shiftKey) {
  3936.         openNewWindowWith(href, linkNode, true);
  3937.         event.preventBubble();
  3938.         return true;
  3939.       }
  3940.       
  3941.       if (event.altKey) {
  3942.         saveURL(href, linkNode ? gatherTextUnder(linkNode) : "");
  3943.         return true;
  3944.       }
  3945.  
  3946.       return false;
  3947.     case 1:                                                         // if middle button clicked
  3948.       var tab;
  3949.       try {
  3950.         tab = gPrefService.getBoolPref("browser.tabs.opentabfor.middleclick")
  3951.       }
  3952.       catch(ex) {
  3953.         tab = true;
  3954.       }
  3955.       if (tab)
  3956.         openNewTabWith(href, linkNode, event, true);
  3957.       else
  3958.         openNewWindowWith(href, linkNode, true);
  3959.       event.preventBubble();
  3960.       return true;
  3961.   }
  3962.   return false;
  3963. }
  3964.  
  3965. function middleMousePaste(event)
  3966. {
  3967.   var url = readFromClipboard();
  3968.   if (!url)
  3969.     return false;
  3970.   url = getShortcutOrURI(url);
  3971.   if (!url)
  3972.     return false;
  3973.  
  3974.   // On ctrl-middleclick, open in new tab.
  3975.   if (event.ctrlKey)
  3976.     openNewTabWith(url, null, event, true);
  3977.  
  3978.   // If ctrl wasn't down, then just load the url in the current win/tab.
  3979.   loadURI(url);
  3980.   event.preventBubble();
  3981.   return true;
  3982. }
  3983.  
  3984. function makeURLAbsolute( base, url ) 
  3985. {
  3986.   // Construct nsIURL.
  3987.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  3988.                 .getService(Components.interfaces.nsIIOService);
  3989.   var baseURI  = ioService.newURI(base, null, null);
  3990.  
  3991.   return ioService.newURI(baseURI.resolve(url), null, null).spec;
  3992. }
  3993.  
  3994. function findParentNode(node, parentNode)
  3995. {
  3996.   if (node && node.nodeType == Node.TEXT_NODE) {
  3997.     node = node.parentNode;
  3998.   }
  3999.   while (node) {
  4000.     var nodeName = node.localName;
  4001.     if (!nodeName)
  4002.       return null;
  4003.     nodeName = nodeName.toLowerCase();
  4004.     if (nodeName == "body" || nodeName == "html" ||
  4005.         nodeName == "#document") {
  4006.       return null;
  4007.     }
  4008.     if (nodeName == parentNode)
  4009.       return node;
  4010.     node = node.parentNode;
  4011.   }
  4012.   return null;
  4013. }
  4014.  
  4015. function saveFrameDocument()
  4016. {
  4017.   var focusedWindow = document.commandDispatcher.focusedWindow;
  4018.   if (isContentFrame(focusedWindow))
  4019.     saveDocument(focusedWindow.document);
  4020. }
  4021.  
  4022. /*
  4023.  * Note that most of this routine has been moved into C++ in order to
  4024.  * be available for all <browser> tags as well as gecko embedding. See
  4025.  * mozilla/content/base/src/nsContentAreaDragDrop.cpp.
  4026.  *
  4027.  * Do not add any new fuctionality here other than what is needed for
  4028.  * a standalone product.
  4029.  */
  4030.  
  4031. var contentAreaDNDObserver = {
  4032.   onDrop: function (aEvent, aXferData, aDragSession)
  4033.     {
  4034.       var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
  4035.  
  4036.       // valid urls don't contain spaces ' '; if we have a space it isn't a valid url so bail out
  4037.       if (!url || !url.length || url.indexOf(" ", 0) != -1) 
  4038.         return;
  4039.  
  4040.       switch (document.firstChild.getAttribute('windowtype')) {
  4041.         case "navigator:browser":
  4042.           loadURI(getShortcutOrURI(url));
  4043.           break;
  4044.         case "navigator:view-source":
  4045.           viewSource(url);
  4046.           break;
  4047.       }
  4048.       
  4049.       // keep the event from being handled by the dragDrop listeners
  4050.       // built-in to gecko if they happen to be above us.    
  4051.       aEvent.preventDefault();
  4052.     },
  4053.  
  4054.   getSupportedFlavours: function ()
  4055.     {
  4056.       var flavourSet = new FlavourSet();
  4057.       flavourSet.appendFlavour("text/x-moz-url");
  4058.       flavourSet.appendFlavour("text/unicode");
  4059.       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  4060.       return flavourSet;
  4061.     }
  4062.   
  4063. };
  4064.  
  4065. // For extensions
  4066. function getBrowser()
  4067. {
  4068.   if (!gBrowser)
  4069.     gBrowser = document.getElementById("content");
  4070.   return gBrowser;
  4071. }
  4072.  
  4073. function MultiplexHandler(event)
  4074. { try {
  4075.     var node = event.target;
  4076.     var name = node.getAttribute('name');
  4077.  
  4078.     if (name == 'detectorGroup') {
  4079.         SetForcedDetector(true);
  4080.         SelectDetector(event, false);
  4081.     } else if (name == 'charsetGroup') {
  4082.         var charset = node.getAttribute('id');
  4083.         charset = charset.substring('charset.'.length, charset.length)
  4084.         SetForcedCharset(charset);
  4085.         SetDefaultCharacterSet(charset);
  4086.     } else if (name == 'charsetCustomize') {
  4087.         //do nothing - please remove this else statement, once the charset prefs moves to the pref window
  4088.     } else {
  4089.         SetForcedCharset(node.getAttribute('id'));
  4090.         SetDefaultCharacterSet(node.getAttribute('id'));
  4091.     }
  4092.     } catch(ex) { alert(ex); }
  4093. }
  4094.  
  4095. function SetDefaultCharacterSet(charset)
  4096. {
  4097.     BrowserSetDefaultCharacterSet(charset);
  4098. }
  4099.  
  4100. function SelectDetector(event, doReload)
  4101. {
  4102.     var uri =  event.target.getAttribute("id");
  4103.     var prefvalue = uri.substring('chardet.'.length, uri.length);
  4104.     if ("off" == prefvalue) { // "off" is special value to turn off the detectors
  4105.         prefvalue = "";
  4106.     }
  4107.  
  4108.     try {
  4109.         var pref = Components.classes["@mozilla.org/preferences-service;1"]
  4110.                              .getService(Components.interfaces.nsIPrefBranch);
  4111.         var str =  Components.classes["@mozilla.org/supports-string;1"]
  4112.                              .createInstance(Components.interfaces.nsISupportsString);
  4113.  
  4114.         str.data = prefvalue;
  4115.         pref.setComplexValue("intl.charset.detector",
  4116.                              Components.interfaces.nsISupportsString, str);
  4117.         if (doReload) window._content.location.reload();
  4118.     }
  4119.     catch (ex) {
  4120.         dump("Failed to set the intl.charset.detector preference.\n");
  4121.     }
  4122. }
  4123.  
  4124. function SetForcedDetector(doReload)
  4125. {
  4126.     BrowserSetForcedDetector(doReload);
  4127. }
  4128.  
  4129. function SetForcedCharset(charset)
  4130. {
  4131.     BrowserSetForcedCharacterSet(charset);
  4132. }
  4133.  
  4134. function BrowserSetDefaultCharacterSet(aCharset)
  4135. {
  4136.   // no longer needed; set when setting Force; see bug 79608
  4137. }
  4138.  
  4139. function BrowserSetForcedCharacterSet(aCharset)
  4140. {
  4141.   var docCharset = getBrowser().docShell.QueryInterface(
  4142.                             Components.interfaces.nsIDocCharset);
  4143.   docCharset.charset = aCharset;
  4144.   BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
  4145. }
  4146.  
  4147. function BrowserSetForcedDetector(doReload)
  4148. {
  4149.   getBrowser().documentCharsetInfo.forcedDetector = true;
  4150.   if (doReload)
  4151.     BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
  4152. }
  4153.  
  4154. function UpdateCurrentCharset()
  4155. {
  4156.     var menuitem = null;
  4157.  
  4158.     // exctract the charset from DOM
  4159.     var wnd = document.commandDispatcher.focusedWindow;
  4160.     if ((window == wnd) || (wnd == null)) wnd = window._content;
  4161.     menuitem = document.getElementById('charset.' + wnd.document.characterSet);
  4162.  
  4163.     if (menuitem) {
  4164.         // uncheck previously checked item to workaround Mac checkmark problem
  4165.         // bug 98625
  4166.         if (gPrevCharset) {
  4167.             var pref_item = document.getElementById('charset.' + gPrevCharset);
  4168.             if (pref_item)
  4169.               pref_item.setAttribute('checked', 'false');
  4170.         }
  4171.         menuitem.setAttribute('checked', 'true');
  4172.     }
  4173. }
  4174.  
  4175. function UpdateCharsetDetector()
  4176. {
  4177.     var prefvalue;
  4178.  
  4179.     try {
  4180.         var pref = Components.classes["@mozilla.org/preferences-service;1"]
  4181.                              .getService(Components.interfaces.nsIPrefBranch);
  4182.         prefvalue = pref.getComplexValue("intl.charset.detector",
  4183.                                          Components.interfaces.nsIPrefLocalizedString).data;
  4184.     }
  4185.     catch (ex) {
  4186.         prefvalue = "";
  4187.     }
  4188.  
  4189.     if (prefvalue == "") prefvalue = "off";
  4190.     dump("intl.charset.detector = "+ prefvalue + "\n");
  4191.  
  4192.     prefvalue = 'chardet.' + prefvalue;
  4193.     var menuitem = document.getElementById(prefvalue);
  4194.  
  4195.     if (menuitem) {
  4196.         menuitem.setAttribute('checked', 'true');
  4197.     }
  4198. }
  4199.  
  4200. function UpdateMenus(event)
  4201. {
  4202.     // use setTimeout workaround to delay checkmark the menu
  4203.     // when onmenucomplete is ready then use it instead of oncreate
  4204.     // see bug 78290 for the detail
  4205.     UpdateCurrentCharset();
  4206.     setTimeout("UpdateCurrentCharset()", 0);
  4207.     UpdateCharsetDetector();
  4208.     setTimeout("UpdateCharsetDetector()", 0);
  4209. }
  4210.  
  4211. function CreateMenu(node)
  4212. {
  4213.   var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  4214.   observerService.notifyObservers(null, "charsetmenu-selected", node);
  4215. }
  4216.  
  4217. function charsetLoadListener (event)
  4218. {
  4219.     var charset = window._content.document.characterSet;
  4220.  
  4221.     if (charset.length > 0 && (charset != gLastBrowserCharset)) {
  4222.         if (!gCharsetMenu)
  4223.           gCharsetMenu = Components.classes['@mozilla.org/rdf/datasource;1?name=charset-menu'].getService().QueryInterface(Components.interfaces.nsICurrentCharsetListener);
  4224.         gCharsetMenu.SetCurrentCharset(charset);
  4225.         gPrevCharset = gLastBrowserCharset;
  4226.         gLastBrowserCharset = charset;
  4227.     }
  4228. }
  4229.