/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * Communicator Shared Utility Library * for shared application glue for the Communicator suite of applications **/ var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyModuleGetters(this, { BrowserUtils: "resource://gre/modules/BrowserUtils.jsm", PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm", RecentWindow: "resource:///modules/RecentWindow.jsm", }); // XPCOMUtils.defineLazyGetter(this, "Weave", function() { // let tmp = {}; // ChromeUtils.import("resource://services-sync/main.js", tmp); // return tmp.Weave; // }); /* Note: All Editor/Composer-related methods have been moved to editorApplicationOverlay.js, so app windows that require those must include editorTasksOverlay.xul */ /** * Go into online/offline mode **/ const kProxyManual = ["network.proxy.ftp", "network.proxy.http", "network.proxy.socks", "network.proxy.ssl"]; var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab"; var gShowBiDi = false; var gUtilityBundle = null; var gPrivate = null; function toggleOfflineStatus() { var checkfunc; try { checkfunc = document.getElementById("offline-status").getAttribute('checkfunc'); } catch (ex) { checkfunc = null; } if (checkfunc) { if (!eval(checkfunc)) { // the pre-offline check function returned false, so don't go offline return; } } Services.io.manageOfflineStatus = false; Services.io.offline = !Services.io.offline; } function setNetworkStatus(networkProxyType) { try { Services.prefs.setIntPref("network.proxy.type", networkProxyType); } catch (ex) {} } function InitProxyMenu() { var networkProxyNo = document.getElementById("network-proxy-no"); var networkProxyManual = document.getElementById("network-proxy-manual"); var networkProxyPac = document.getElementById("network-proxy-pac"); var networkProxyWpad = document.getElementById("network-proxy-wpad"); var networkProxySystem = document.getElementById("network-proxy-system"); var proxyLocked = Services.prefs.prefIsLocked("network.proxy.type"); if (proxyLocked) { networkProxyNo.setAttribute("disabled", "true"); networkProxyWpad.setAttribute("disabled", "true"); networkProxySystem.setAttribute("disabled", "true"); } else { networkProxyNo.removeAttribute("disabled"); networkProxyWpad.removeAttribute("disabled"); networkProxySystem.removeAttribute("disabled"); } // If no proxy is configured, disable the menuitems. // Checking for proxy manual settings. var proxyManuallyConfigured = false; for (var i = 0; i < kProxyManual.length; i++) { if (Services.prefs.getStringPref(kProxyManual[i], "") != "") { proxyManuallyConfigured = true; break; } } if (proxyManuallyConfigured && !proxyLocked) { networkProxyManual.removeAttribute("disabled"); } else { networkProxyManual.setAttribute("disabled", "true"); } //Checking for proxy PAC settings. var proxyAutoConfigured = false; if (Services.prefs.getStringPref("network.proxy.autoconfig_url", "") != "") proxyAutoConfigured = true; if (proxyAutoConfigured && !proxyLocked) { networkProxyPac.removeAttribute("disabled"); } else { networkProxyPac.setAttribute("disabled", "true"); } // The pref value 3 for network.proxy.type is unused to maintain // backwards compatibility. Treat 3 equally to 0. See bug 115720. var networkProxyStatus = [networkProxyNo, networkProxyManual, networkProxyPac, networkProxyNo, networkProxyWpad, networkProxySystem]; var networkProxyType = Services.prefs.getIntPref("network.proxy.type", 0); networkProxyStatus[networkProxyType].setAttribute("checked", "true"); } function setProxyTypeUI() { var panel = document.getElementById("offline-status"); if (!panel) return; var onlineTooltip = "onlineTooltip" + Services.prefs.getIntPref("network.proxy.type", 0); panel.setAttribute("tooltiptext", gUtilityBundle.getString(onlineTooltip)); } function SetStringPref(aPref, aValue) { try { Services.prefs.setStringPref(aPref, aValue); } catch (e) {} } function GetLocalizedStringPref(aPrefName, aDefaultValue) { try { return Services.prefs.getComplexValue(aPrefName, Ci.nsIPrefLocalizedString).data; } catch (e) { Cu.reportError("Couldn't get " + aPrefName + " pref: " + e); } return aDefaultValue; } function GetLocalFilePref(aName) { try { return Services.prefs.getComplexValue(aName, Ci.nsIFile); } catch (e) {} return null; } /** * Returns the Desktop folder. */ function GetDesktopFolder() { return Services.dirsvc.get("Desk", Ci.nsIFile); } /** * Returns the relevant nsIFile directory. */ function GetSpecialDirectory(aName) { return Services.dirsvc.get(aName, Ci.nsIFile); } function GetUrlbarHistoryFile() { var profileDir = GetSpecialDirectory("ProfD"); profileDir.append("urlbarhistory.sqlite"); return profileDir; } function setOfflineUI(offline) { var broadcaster = document.getElementById("Communicator:WorkMode"); var panel = document.getElementById("offline-status"); if (!broadcaster || !panel) return; // Checking for a preference "network.online", if it's locked, disabling // network icon and menu item if (Services.prefs.prefIsLocked("network.online")) broadcaster.setAttribute("disabled", "true"); if (offline) { broadcaster.setAttribute("offline", "true"); broadcaster.setAttribute("checked", "true"); panel.removeAttribute("context"); panel.setAttribute("tooltiptext", gUtilityBundle.getString("offlineTooltip")); } else { broadcaster.removeAttribute("offline"); broadcaster.removeAttribute("checked"); panel.setAttribute("context", "networkProperties"); setProxyTypeUI(); } } function getBrowserURL() { try { var url = Services.prefs.getCharPref("browser.chromeURL"); if (url) return url; } catch(e) { } return "chrome://navigator/content/navigator.xul"; } function goPreferences(paneID) { //check for an existing pref window and focus it; it's not application modal var lastPrefWindow = Services.wm.getMostRecentWindow("mozilla:preferences"); if (lastPrefWindow) lastPrefWindow.focus(); else openDialog("chrome://communicator/content/pref/preferences.xul", "PrefWindow", "non-private,chrome,titlebar,dialog=no,resizable", paneID); } function goToggleToolbar(id, elementID) { var toolbar = document.getElementById(id); if (!toolbar) return; var type = toolbar.getAttribute("type"); var toggleAttribute = type == "menubar" ? "autohide" : "hidden"; var hidden = toolbar.getAttribute(toggleAttribute) == "true"; var element = document.getElementById(elementID); toolbar.setAttribute(toggleAttribute, !hidden); if (element) element.setAttribute("checked", hidden) document.persist(id, toggleAttribute); document.persist(elementID, "checked"); if (toolbar.hasAttribute("customindex")) persistCustomToolbar(toolbar); } var gCustomizeSheet = false; function SuiteCustomizeToolbar(aMenuItem) { let toolbar = aMenuItem.parentNode.triggerNode; while (toolbar.localName != "toolbar") { toolbar = toolbar.parentNode; if (!toolbar) return false; } return goCustomizeToolbar(toolbar.toolbox); } function goCustomizeToolbar(toolbox) { /* If the toolbox has a method "customizeInit" then call it first. The optional "customizeDone" method will be invoked by the callback from the Customize Window so we don't need to take care of that */ if ("customizeInit" in toolbox) toolbox.customizeInit(); var customizeURL = "chrome://communicator/content/customizeToolbar.xul"; gCustomizeSheet = Services.prefs.getBoolPref("toolbar.customization.usesheet", false); if (gCustomizeSheet) { var sheetFrame = document.getElementById("customizeToolbarSheetIFrame"); var panel = document.getElementById("customizeToolbarSheetPopup"); sheetFrame.hidden = false; sheetFrame.toolbox = toolbox; sheetFrame.panel = panel; // The document might not have been loaded yet, if this is the first time. // If it is already loaded, reload it so that the onload initialization // code re-runs. if (sheetFrame.getAttribute("src") == customizeURL) sheetFrame.contentWindow.location.reload(); else sheetFrame.setAttribute("src", customizeURL); // Open the panel, but make it invisible until the iframe has loaded so // that the user doesn't see a white flash. panel.style.visibility = "hidden"; toolbox.addEventListener("beforecustomization", function toolboxBeforeCustom() { toolbox.removeEventListener("beforecustomization", toolboxBeforeCustom); panel.style.removeProperty("visibility"); }); panel.openPopup(toolbox, "after_start", 0, 0); return sheetFrame.contentWindow; } else { return window.openDialog(customizeURL, "", "chrome,all,dependent", toolbox); } } function onViewToolbarsPopupShowing(aEvent, aInsertPoint) { var popup = aEvent.target; if (popup != aEvent.currentTarget) return; // Empty the menu var deadItems = popup.getElementsByAttribute("toolbarid", "*"); for (let i = deadItems.length - 1; i >= 0; --i) deadItems[i].remove(); // Thunderbird/Lightning function signature is: // onViewToolbarsPopupShowing(aEvent, toolboxIds, aInsertPoint) // where toolboxIds is either a string or an array of strings. var firstMenuItem = aInsertPoint instanceof XULElement ? aInsertPoint : popup.firstChild; var toolbar = document.popupNode || popup; while (toolbar.localName != "toolbar") toolbar = toolbar.parentNode; var toolbox = toolbar.toolbox; var externalToolbars = Array.from(toolbox.externalToolbars) .filter(function(toolbar) { return toolbar.hasAttribute("toolbarname")}); var toolbars = Array.from(toolbox.getElementsByAttribute("toolbarname", "*")) .filter(function(toolbar) { return !toolbar.hasAttribute("hideinmenu")}); toolbars = toolbars.concat(externalToolbars); var menusep = document.getElementById("toolbarmode-sep"); var menubar = toolbox.getElementsByAttribute("type", "menubar").item(0); if (!menubar || !toolbars.length) { if (menusep) menusep.hidden = true; return; } if (menusep) menusep.hidden = false; toolbars.forEach(function(bar) { let type = bar.getAttribute("type"); let toggleAttribute = type == "menubar" ? "autohide" : "hidden"; let isHidden = bar.getAttribute(toggleAttribute) == "true"; let menuItem = document.createElement("menuitem"); menuItem.setAttribute("id", "toggle_" + bar.id); menuItem.setAttribute("toolbarid", bar.id); menuItem.setAttribute("type", "checkbox"); menuItem.setAttribute("label", bar.getAttribute("toolbarname")); menuItem.setAttribute("accesskey", bar.getAttribute("accesskey")); menuItem.setAttribute("checked", !isHidden); popup.insertBefore(menuItem, firstMenuItem); }); } function onToolbarModePopupShowing(aEvent) { var popup = aEvent.target; var toolbar = document.popupNode; while (toolbar.localName != "toolbar") toolbar = toolbar.parentNode; var toolbox = toolbar.toolbox; var mode = toolbar.getAttribute("mode") || "full"; var modePopup = document.getElementById("toolbarModePopup"); var radio = modePopup.getElementsByAttribute("value", mode); radio[0].setAttribute("checked", "true"); var small = toolbar.getAttribute("iconsize") == "small"; var smallicons = document.getElementById("toolbarmode-smallicons"); smallicons.setAttribute("checked", small); smallicons.setAttribute("disabled", mode == "text"); var end = toolbar.getAttribute("labelalign") == "end"; var labelalign = document.getElementById("toolbarmode-labelalign"); labelalign.setAttribute("checked", end); labelalign.setAttribute("disabled", mode != "full"); var custommode = (toolbar.getAttribute("mode") || "full") != (toolbar.getAttribute("defaultmode") || toolbox.getAttribute("mode") || "full"); var customicon = (toolbar.getAttribute("iconsize") || "large") != (toolbar.getAttribute("defaulticonsize") || toolbox.getAttribute("iconsize") || "large"); var customalign = (toolbar.getAttribute("labelalign") || "bottom") != (toolbar.getAttribute("defaultlabelalign") || toolbox.getAttribute("labelalign") || "bottom"); var custom = custommode || customicon || customalign || toolbar.hasAttribute("ignoremodepref"); var defmode = document.getElementById("toolbarmode-default"); defmode.setAttribute("checked", !custom); defmode.setAttribute("disabled", !custom); var command = document.getElementById("cmd_CustomizeToolbars"); var menuitem = document.getElementById("customize_toolbars"); menuitem.hidden = !command; menuitem.previousSibling.hidden = !command; } function onViewToolbarCommand(aEvent) { var toolbar = aEvent.originalTarget.getAttribute("toolbarid"); if (toolbar) goToggleToolbar(toolbar); } function goSetToolbarState(aEvent) { aEvent.stopPropagation(); var toolbar = document.popupNode; while (toolbar.localName != "toolbar") toolbar = toolbar.parentNode; var toolbox = toolbar.parentNode; var target = aEvent.originalTarget; var mode = target.value; var radiogroup = target.getAttribute("name"); var primary = /toolbar-primary/.test(toolbar.getAttribute("class")); switch (mode) { case "smallicons": var size = target.getAttribute("checked") == "true" ? "small" : "large"; toolbar.setAttribute("iconsize", size); break; case "end": var align = target.getAttribute("checked") == "true" ? "end" : "bottom"; toolbar.setAttribute("labelalign", align); break; case "default": toolbar.setAttribute("mode", toolbar.getAttribute("defaultmode") || toolbox.getAttribute("mode")); toolbar.setAttribute("iconsize", toolbar.getAttribute("defaulticonsize") || toolbox.getAttribute("iconsize")); toolbar.setAttribute("labelalign", toolbar.getAttribute("defaultlabelalign") || toolbox.getAttribute("labelalign")); if (primary) toolbar.removeAttribute("ignoremodepref"); break; default: toolbar.setAttribute("mode", mode); if (primary) toolbar.setAttribute("ignoremodepref", "true"); break; } document.persist(toolbar.id, "mode"); document.persist(toolbar.id, "iconsize"); document.persist(toolbar.id, "labelalign"); if (primary) document.persist(toolbar.id, "ignoremodepref"); if (toolbar.hasAttribute("customindex")) persistCustomToolbar(toolbar); } function persistCustomToolbar(toolbar) { var toolbox = toolbar.parentNode; var name = toolbar.getAttribute("toolbarname").replace(" ", "_"); var attrs = ["mode", "iconsize", "labelalign", "hidden"]; for (let i = 0; i < attrs.length; i++) { let value = toolbar.getAttribute(attrs[i]); let attr = name + attrs[i]; toolbox.toolbarset.setAttribute(attr, value); document.persist(toolbox.toolbarset.id, attr); } } /* Common Customize Toolbar code */ function toolboxCustomizeInit(menubarID) { // Disable the toolbar context menu items var menubar = document.getElementById(menubarID); for (let i = 0; i < menubar.childNodes.length; ++i) { let item = menubar.childNodes[i]; if (item.getAttribute("disabled") != "true") { item.setAttribute("disabled", "true"); item.setAttribute("saved-disabled", "false"); } } var cmd = document.getElementById("cmd_CustomizeToolbars"); cmd.setAttribute("disabled", "true"); } function toolboxCustomizeDone(menubarID, toolbox, aToolboxChanged) { if (gCustomizeSheet) { document.getElementById("customizeToolbarSheetIFrame").hidden = true; document.getElementById("customizeToolbarSheetPopup").hidePopup(); if (content) content.focus(); else window.focus(); } // Re-enable parts of the UI we disabled during the dialog var menubar = document.getElementById(menubarID); for (let i = 0; i < menubar.childNodes.length; ++i) { let item = menubar.childNodes[i]; if (item.hasAttribute("saved-disabled")) { item.removeAttribute("disabled"); item.removeAttribute("saved-disabled"); } } var cmd = document.getElementById("cmd_CustomizeToolbars"); cmd.removeAttribute("disabled"); var toolbars = toolbox.getElementsByAttribute("customindex", "*"); for (let i = 0; i < toolbars.length; ++i) { persistCustomToolbar(toolbars[i]); } } function toolboxCustomizeChange(toolbox, event) { if (event != "reset") return; var toolbars = toolbox.getElementsByAttribute("toolbarname", "*"); for (let i = 0; i < toolbars.length; ++i) { let toolbar = toolbars[i]; toolbar.setAttribute("labelalign", toolbar.getAttribute("defaultlabelalign") || toolbox.getAttribute("labelalign")); document.persist(toolbar.id, "labelalign"); let primary = /toolbar-primary/.test(toolbar.getAttribute("class")); if (primary) { toolbar.removeAttribute("ignoremodepref"); document.persist(toolbar.id, "ignoremodepref"); } } } function goClickThrobber(urlPref, aEvent) { var url = GetLocalizedStringPref(urlPref); if (url) openUILinkIn(url, whereToOpenLink(aEvent, false, true, true)); } function getTopWin(skipPopups) { // If this is called in a browser window, use that window regardless of // whether it's the frontmost window, since commands can be executed in // background windows (bug 626148). if (top.document.documentElement.getAttribute("windowtype") == "navigator:browser" && (!skipPopups || top.toolbar.visible)) return top; let isPrivate = PrivateBrowsingUtils.isWindowPrivate(window); return RecentWindow.getMostRecentBrowserWindow({private: isPrivate, allowPopups: !skipPopups}); } function isRestricted( url ) { try { let uri = Services.uriFixup .createFixupURI(url, Ci.nsIURIFixup.FIXUP_FLAG_NONE); const URI_INHERITS_SECURITY_CONTEXT = Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT; return Services.netUtils .URIChainHasFlags(uri, URI_INHERITS_SECURITY_CONTEXT); } catch (e) { return false; } } function goAbout(aProtocol) { var target; var url = "about:" + (aProtocol || ""); var defaultAboutState = Services.prefs.getIntPref("browser.link.open_external"); switch (defaultAboutState) { case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW: target = "window"; break; case Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW: target = "current"; break; default: target = "tabfocused"; } openUILinkIn(url, target); } function goTroubleshootingPage() { goAbout("support"); } function goReleaseNotes() { // get release notes URL from prefs try { openUILink(Services.urlFormatter.formatURLPref("app.releaseNotesURL")); } catch (ex) { dump(ex); } } function openDictionaryList() { try { openAsExternal(Services.urlFormatter.formatURLPref("spellchecker.dictionaries.download.url")); } catch (ex) { dump(ex); } } // Prompt user to restart the browser in safe mode function safeModeRestart() { // prompt the user to confirm var promptTitle = gUtilityBundle.getString("safeModeRestartPromptTitle"); var promptMessage = gUtilityBundle.getString("safeModeRestartPromptMessage"); var restartText = gUtilityBundle.getString("safeModeRestartButton"); var checkboxText = gUtilityBundle.getString("safeModeRestartCheckbox"); var checkbox = { value: true }; var buttonFlags = (Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING) + (Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL) + Services.prompt.BUTTON_POS_0_DEFAULT; var rv = Services.prompt.confirmEx(window, promptTitle, promptMessage, buttonFlags, restartText, null, null, checkboxText, checkbox); if (rv == 0) { if (checkbox.value) Cc["@mozilla.org/process/environment;1"] .getService(Ci.nsIEnvironment) .set("MOZ_SAFE_MODE_RESTART", "1"); BrowserUtils.restartApplication(); } } function checkForUpdates() { var um = Cc["@mozilla.org/updates/update-manager;1"] .getService(Ci.nsIUpdateManager); var prompter = Cc["@mozilla.org/updates/update-prompt;1"] .createInstance(Ci.nsIUpdatePrompt); // If there's an update ready to be applied, show the "Update Downloaded" // UI instead and let the user know they have to restart the browser for // the changes to be applied. if (um.activeUpdate && um.activeUpdate.state == "pending") prompter.showUpdateDownloaded(um.activeUpdate); else prompter.checkForUpdates(); } function updateCheckUpdatesItem() { var hasUpdater = "nsIApplicationUpdateService" in Ci; var checkForUpdates = document.getElementById("checkForUpdates"); if (!hasUpdater) { var updateSeparator = document.getElementById("updateSeparator"); checkForUpdates.hidden = true; updateSeparator.hidden = true; return; } var updates = Cc["@mozilla.org/updates/update-service;1"] .getService(Ci.nsIApplicationUpdateService); var um = Cc["@mozilla.org/updates/update-manager;1"] .getService(Ci.nsIUpdateManager); // Disable the UI if the update enabled pref has been locked by the // administrator or if we cannot update for some other reason. var canCheckForUpdates = updates.canCheckForUpdates; checkForUpdates.setAttribute("disabled", !canCheckForUpdates); if (!canCheckForUpdates) return; // By default, show "Check for Updates..." var key = "default"; if (um.activeUpdate) { switch (um.activeUpdate.state) { case "downloading": // If we're downloading an update at present, show the text: // "Downloading SeaMonkey x.x..." otherwise we're paused, and show // "Resume Downloading SeaMonkey x.x..." key = updates.isDownloading ? "downloading" : "resume"; break; case "pending": // If we're waiting for the user to restart, show: "Apply Downloaded // Updates Now..." key = "pending"; break; } } // If there's an active update, substitute its name into the label // we show for this item, otherwise display a generic label. if (um.activeUpdate && um.activeUpdate.name) checkForUpdates.label = gUtilityBundle.getFormattedString("updatesItem_" + key, [um.activeUpdate.name]); else checkForUpdates.label = gUtilityBundle.getString("updatesItem_" + key + "Fallback"); checkForUpdates.accessKey = gUtilityBundle.getString("updatesItem_" + key + "AccessKey"); if (um.activeUpdate && updates.isDownloading) checkForUpdates.setAttribute("loading", "true"); else checkForUpdates.removeAttribute("loading"); } // update menu items that rely on focus function goUpdateGlobalEditMenuItems() { goUpdateCommand('cmd_undo'); goUpdateCommand('cmd_redo'); goUpdateCommand('cmd_cut'); goUpdateCommand('cmd_copy'); goUpdateCommand('cmd_paste'); goUpdateCommand('cmd_selectAll'); goUpdateCommand('cmd_delete'); if (gShowBiDi) goUpdateCommand('cmd_switchTextDirection'); } // update menu items that rely on the current selection function goUpdateSelectEditMenuItems() { goUpdateCommand('cmd_cut'); goUpdateCommand('cmd_copy'); goUpdateCommand('cmd_delete'); goUpdateCommand('cmd_selectAll'); } // update menu items that relate to undo/redo function goUpdateUndoEditMenuItems() { goUpdateCommand('cmd_undo'); goUpdateCommand('cmd_redo'); } // update menu items that depend on clipboard contents function goUpdatePasteMenuItems() { goUpdateCommand('cmd_paste'); } // update Find As You Type menu items, they rely on focus function goUpdateFindTypeMenuItems() { goUpdateCommand('cmd_findTypeText'); goUpdateCommand('cmd_findTypeLinks'); } // Gather all descendent text under given document node. function gatherTextUnder(root) { var text = ""; var node = root.firstChild; var depth = 1; while ( node && depth > 0 ) { // See if this node is text. if ( node.nodeType == Node.TEXT_NODE ) { // Add this text to our collection. text += " " + node.data; } else if ( node instanceof HTMLImageElement ) { // If it has an alt= attribute, add that. var altText = node.getAttribute( "alt" ); if ( altText && altText != "" ) { text += " " + altText; } } // Find next node to test. // First, see if this node has children. if ( node.hasChildNodes() ) { // Go to first child. node = node.firstChild; depth++; } else { // No children, try next sibling. if ( node.nextSibling ) { node = node.nextSibling; } else { // Last resort is a sibling of an ancestor. while ( node && depth > 0 ) { node = node.parentNode; depth--; if ( node.nextSibling ) { node = node.nextSibling; break; } } } } } // Strip leading and trailing whitespaces, // then compress remaining whitespaces. return text.trim().replace(/\s+/g, " "); } var offlineObserver = { observe: function(subject, topic, state) { // sanity checks if (topic != "network:offline-status-changed") return; setOfflineUI(state == "offline"); } } var proxyTypeObserver = { observe: function(subject, topic, state) { // sanity checks if (state == "network.proxy.type" && !Services.io.offline) setProxyTypeUI(); } } function utilityOnLoad(aEvent) { gUtilityBundle = document.getElementById("bundle_utilityOverlay"); var broadcaster = document.getElementById("Communicator:WorkMode"); if (!broadcaster) return; Services.obs.addObserver(offlineObserver, "network:offline-status-changed"); // make sure we remove this observer later Services.prefs.addObserver("network.proxy.type", proxyTypeObserver); addEventListener("unload", utilityOnUnload, false); // set the initial state setOfflineUI(Services.io.offline); // Check for system proxy settings class and show menuitem if present if ("@mozilla.org/system-proxy-settings;1" in Cc && document.getElementById("network-proxy-system")) document.getElementById("network-proxy-system").hidden = false; } function utilityOnUnload(aEvent) { Services.obs.removeObserver(offlineObserver, "network:offline-status-changed"); Services.prefs.removeObserver("network.proxy.type", proxyTypeObserver); } addEventListener("load", utilityOnLoad, false); /** * example use: * suggestUniqueFileName("testname", ".txt", ["testname.txt", "testname(2).txt"]) * returns "testname(3).txt" * does not check file system for existing files * * @param aBaseName base name for generating unique filenames. * * @param aExtension extension name to use for the generated filename. * * @param aExistingNames array of names in use. * * @return suggested filename as a string. */ function suggestUniqueFileName(aBaseName, aExtension, aExistingNames) { var suffix = 1; aBaseName = validateFileName(aBaseName); var suggestion = aBaseName + aExtension; while (aExistingNames.includes(suggestion)) { suffix++; suggestion = aBaseName + "(" + suffix + ")" + aExtension; } return suggestion; } function focusElement(aElement) { if (isElementVisible(aElement)) aElement.focus(); } function isElementVisible(aElement) { if (!aElement) return false; // If aElement or a direct or indirect parent is hidden or collapsed, // height, width or both will be 0. var bo = aElement.boxObject; return (bo.height > 0 && bo.width > 0); } function makeURLAbsolute(aBase, aUrl, aCharset) { // Construct nsIURL. return Services.io.newURI(aUrl, aCharset, Services.io.newURI(aBase, aCharset)).spec; } /** * whereToLoadExternalLink: Returns values for opening a new external link. * * @returns (object[]} an array of objects with the following structure: * - (string) where location where to open the link. * - (bool) loadInBackground load url in background. * - (bool) Focus browser after load. */ function whereToLoadExternalLink() { let openParms = { where: null, loadInBackground: false, avoidBrowserFocus: false, } switch (Services.prefs.getIntPref("browser.link.open_external")) { case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW: openParms.where = "window"; break; case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB: openParms.where = "tab"; break; case Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW: openParms.where = "current"; break; default: console.log("Check pref browser.link.open_external"); openParms.where = "current"; } openParms.loadInBackground = Services.prefs.getBoolPref("browser.tabs.loadDivertedInBackground"); openParms.avoidBrowserFocus = Services.prefs.getBoolPref("browser.tabs.avoidBrowserFocus"); return openParms; } function openAsExternal(aURL) { let openParms = whereToLoadExternalLink(); openNewTabWindowOrExistingWith(aURL, openParms.where, null, openParms.loadInBackground); } /** * openNewTabWith: opens a new tab with the given URL. * openNewWindowWith: opens a new window with the given URL. * openNewPrivateWith: opens a private window with the given URL. * * @param aURL * The URL to open (as a string). * @param aDocument * The document from which the URL came, or null. This is used to set * the referrer header and to do a security check of whether the * document is allowed to reference the URL. If null, there will be no * referrer header and no security check. * @param aPostData * Form POST data, or null. * @param aEvent * The triggering event (for the purpose of determining whether to open * in the background), or null. * @param aAllowThirdPartyFixup * If true, then we allow the URL text to be sent to third party * services (e.g., Google's I Feel Lucky) for interpretation. This * parameter may be undefined in which case it is treated as false. * @param [optional] aReferrer * If aDocument is null, then this will be used as the referrer. * There will be no security check. * @param [optional] aReferrerPolicy * Referrer policy - Ci.nsIHttpChannel.REFERRER_POLICY_*. */ function openNewPrivateWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup, aReferrer, aReferrerPolicy) { return openNewTabWindowOrExistingWith(aURL, "private", aDocument, null, aPostData, aAllowThirdPartyFixup, aReferrer, aReferrerPolicy); } function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup, aReferrer, aReferrerPolicy) { return openNewTabWindowOrExistingWith(aURL, "window", aDocument, null, aPostData, aAllowThirdPartyFixup, aReferrer, aReferrerPolicy); } function openNewTabWith(aURL, aDocument, aPostData, aEvent, aAllowThirdPartyFixup, aReferrer, aReferrerPolicy) { let where = aEvent && aEvent.shiftKey ? "tabshifted" : "tab"; return openNewTabWindowOrExistingWith(aURL, where, aDocument, null, aPostData, aAllowThirdPartyFixup, aReferrer, aReferrerPolicy); } function openNewTabWindowOrExistingWith(aURL, aWhere, aDocument, aLoadInBackground, aPostData, aAllowThirdPartyFixup, aReferrer, aReferrerPolicy) { // Make sure we are allowed to open this url if (aDocument) urlSecurityCheck(aURL, aDocument.nodePrincipal); // Where appropriate we want to pass the charset of the // current document over to a new tab / window. var originCharset = null; if (aWhere != "current") { originCharset = aDocument && aDocument.characterSet; if (!originCharset && document.documentElement.getAttribute("windowtype") == "navigator:browser") originCharset = window.content.document.characterSet; } var isPrivate = false; if (aWhere == "private") { aWhere = "window"; isPrivate = true; } var referrerURI = aDocument ? aDocument.documentURIObject : aReferrer; return openLinkIn(aURL, aWhere, { charset: originCharset, postData: aPostData, inBackground: aLoadInBackground, allowThirdPartyFixup: aAllowThirdPartyFixup, referrerURI: referrerURI, referrerPolicy: aReferrerPolicy, private: isPrivate, }); } /** * Handle command events bubbling up from error page content * called from oncommand by s that support error pages */ function BrowserOnCommand(event) { // Don't trust synthetic events if (!event.isTrusted) return; const ot = event.originalTarget; const ownerDoc = ot.ownerDocument; const docURI = ownerDoc.documentURI; const buttonID = ot.getAttribute("anonid"); // If the event came from an ssl error page, it is probably either the "Add // Exception" or "Get Me Out Of Here" button if (docURI.startsWith("about:certerror?")) { if (buttonID == "exceptionDialogButton") { let docshell = ownerDoc.defaultView .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); let securityInfo = docshell.failedChannel.securityInfo; let sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider) .SSLStatus; let params = { exceptionAdded : false, sslStatus : sslStatus }; switch (Services.prefs.getIntPref("browser.ssl_override_behavior", 2)) { case 2 : // Pre-fetch & pre-populate. params.prefetchCert = true; // Fall through. case 1 : // Pre-populate. params.location = ownerDoc.location.href; } window.openDialog('chrome://pippki/content/exceptionDialog.xul', '', 'chrome,centerscreen,modal', params); // If the user added the exception cert, attempt to reload the page if (params.exceptionAdded) ownerDoc.location.reload(); } else if (buttonID == "getMeOutOfHereButton") { // Redirect them to a known-functioning page, default start page getMeOutOfHere(); } } else if (docURI.startsWith("about:blocked")) { // The event came from a button on a malware/phishing block page // First check whether the reason, so that we can // use the right strings/links let reason = "phishing"; if (/e=malwareBlocked/.test(docURI)) { reason = "malware"; } else if (/e=unwantedBlocked/.test(docURI)) { reason = "unwanted"; } else if (/e=harmfulBlocked/.test(docURI)) { reason = "harmful"; } let docShell = ownerDoc.defaultView .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); let blockedInfo = {}; if (docShell.failedChannel) { let classifiedChannel = docShell.failedChannel. QueryInterface(Ci.nsIClassifiedChannel); if (classifiedChannel) { let httpChannel = docShell.failedChannel.QueryInterface(Ci.nsIHttpChannel); let reportUri = httpChannel.URI.clone(); // Remove the query to avoid leaking sensitive data if (reportUri instanceof Ci.nsIURL) { reportUri = reportUri.mutate().setQuery("").finalize(); } blockedInfo = { list: classifiedChannel.matchedList, provider: classifiedChannel.matchedProvider, uri: reportUri.asciiSpec }; } } switch (buttonID) { case "getMeOutOfHereButton": getMeOutOfHere(); break; case "reportButton": // This is the "Why is this site blocked" button. We redirect // to the generic page describing phishing/malware protection. try { loadURI(Services.urlFormatter.formatURLPref("browser.safebrowsing.warning.infoURL")); } catch (e) { Cu.reportError("Couldn't get phishing info URL: " + e); } break; case "ignoreWarningButton": if (Services.prefs.getBoolPref("browser.safebrowsing.allowOverride")) { getBrowser().getNotificationBox().ignoreSafeBrowsingWarning(reason, blockedInfo); } break; } } } /** * Re-direct the browser to a known-safe page. This function is * used when, for example, the user browses to a known malware page * and is presented with about:blocked. The "Get me out of here!" * button should take the user to the default start page so that even * when their own homepage is infected, we can get them somewhere safe. */ function getMeOutOfHere() { // Get the start page from the *default* pref branch, not the user's var prefs = Services.prefs.getDefaultBranch(null); var url = "about:blank"; try { url = prefs.getComplexValue("browser.startup.homepage", Ci.nsIPrefLocalizedString).data; } catch(e) {} loadURI(url); } function popupNotificationMenuShowing(event) { var notificationbox = document.popupNode.parentNode.control; var uri = notificationbox.activeBrowser.currentURI; var allowPopupsForSite = document.getElementById("allowPopupsForSite"); allowPopupsForSite.notificationbox = notificationbox; var showPopupManager = document.getElementById("showPopupManager"); // Only offer this menu item for the top window. // See bug 280536 for problems with frames and iframes. try { // uri.host generates an exception on nsISimpleURIs. var allowString = gUtilityBundle.getFormattedString("popupAllow", [uri.host || uri.spec]); allowPopupsForSite.setAttribute("label", allowString); showPopupManager.hostport = uri.hostPort; allowPopupsForSite.hidden = gPrivate; } catch (ex) { allowPopupsForSite.hidden = true; showPopupManager.hostport = ""; } var separator = document.getElementById("popupNotificationMenuSeparator"); separator.hidden = !createShowPopupsMenu(event.target, notificationbox.activeBrowser); } function RemovePopupsItems(parent) { while (parent.lastChild && parent.lastChild.hasAttribute("popupReportIndex")) parent.lastChild.remove(); } function createShowPopupsMenu(parent, browser) { if (!browser) return false; if (!browser.blockedPopups || browser.blockedPopups.count == 0) return false; parent.browser = browser; browser.retrieveListOfBlockedPopups().then(blockedPopups => { for (var i = 0; i < blockedPopups.length; i++) { let blockedPopup = blockedPopups[i]; // popupWindowURI will be null if the file picker popup is blocked. if (!blockedPopup.popupWindowURIspec) continue; let str = gUtilityBundle.getFormattedString("popupMenuShow", [blockedPopup.popupWindowURIspec]); // Check for duplicates in the blockedPopups list and reuse the old menuitem. let menuitem = parent.getElementsByAttribute("label", str).item(0); if (!menuitem) { menuitem = document.createElement("menuitem"); menuitem.setAttribute("label", str); } menuitem.setAttribute("popupReportIndex", i); parent.appendChild(menuitem); } }, null); return parent.getElementsByAttribute("popupReportIndex", "*").item(0) != null; } function popupBlockerMenuCommand(target) { if (target.hasAttribute("popupReportIndex")) target.parentNode.browser.unblockPopup(target.getAttribute("popupReportIndex")); } function hostUrl() { var url = ""; try { url = getBrowser().currentURI.scheme + "://" + getBrowser().currentURI.hostPort; } catch (e) {} return url; } function disablePopupBlockerNotifications() { Services.prefs.setBoolPref("privacy.popups.showBrowserMessage", false); } // Used as an onclick handler for UI elements with link-like behavior. // e.g. onclick="checkForMiddleClick(this, event);" function checkForMiddleClick(node, event) { // We should be using the disabled property here instead of the attribute, // but some elements that this function is used with don't support it (e.g. // menuitem). if (node.getAttribute("disabled") == "true") return; // Do nothing if (event.button == 1) { /* Execute the node's oncommand or command. * * XXX: we should use node.oncommand(event) once bug 246720 is fixed. */ var target = node.hasAttribute("oncommand") ? node : node.ownerDocument.getElementById(node.getAttribute("command")); var fn = new Function("event", target.getAttribute("oncommand")); fn.call(target, event); // If the middle-click was on part of a menu, close the menu. // (Menus close automatically with left-click but not with middle-click.) closeMenus(event.target); } } // Closes all popups that are ancestors of the node. function closeMenus(node) { if ("tagName" in node) { if (node.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" && (node.tagName == "menupopup" || node.tagName == "popup")) node.hidePopup(); closeMenus(node.parentNode); } } /** * Toggle a splitter to show or hide some piece of UI (e.g. the message preview * pane). * * @param aSplitterId the splitter that should be toggled */ function togglePaneSplitter(aSplitterId) { var splitter = document.getElementById(aSplitterId); if (splitter.getAttribute("state") == "collapsed") splitter.setAttribute("state", "open"); else splitter.setAttribute("state", "collapsed"); } /* openUILink handles clicks on UI elements that cause URLs to load. * * As the third argument, you may pass an object with the same properties as * accepted by openUILinkIn, plus "ignoreButton" and "ignoreSave". * * Note: Firefox uses aIgnoreAlt while SeaMonkey uses aIgnoreSave because in * SeaMonkey, Save can be Alt or Shift depending on ui.key.saveLink.shift. * * For API compatibility with Firefox the object version uses params.ignoreAlt * although for SeaMonkey it is effectively ignoreSave. */ function openUILink(url, aEvent, aIgnoreButton, aIgnoreSave, aAllowThirdPartyFixup, aPostData, aReferrerURI) { var params; if (aIgnoreButton && typeof aIgnoreButton == "object") { params = aIgnoreButton; // don't forward "ignoreButton" and "ignoreSave" to openUILinkIn. aIgnoreButton = params.ignoreButton; aIgnoreSave = params.ignoreAlt; delete params.ignoreButton; delete params.ignoreAlt; } else { params = {allowThirdPartyFixup: aAllowThirdPartyFixup, postData: aPostData, referrerURI: aReferrerURI, referrerPolicy: Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, initiatingDoc: aEvent ? aEvent.target.ownerDocument : document,} } var where = whereToOpenLink(aEvent, aIgnoreButton, aIgnoreSave); return openUILinkIn(url, where, params); } /* whereToOpenLink() looks at an event to decide where to open a link. * * The event may be a mouse event (click, double-click, middle-click) or keypress event (enter). * * The logic for modifiers is as following: * If browser.tabs.opentabfor.middleclick is true, then Ctrl (or Meta) and middle-click * open a new tab, depending on Shift, browser.tabs.loadInBackground, and * ignoreBackground. * Otherwise if middlemouse.openNewWindow is true, then Ctrl (or Meta) and middle-click * open a new window. * Otherwise if middle-click is pressed then nothing happens. * Save is Alt or Shift depending on the ui.key.saveLink.shift preference. * Otherwise if Alt, or Shift, or Ctrl (or Meta) is pressed then nothing happens. * Otherwise the most recent browser is used for left clicks. * * Exceptions: * - Alt is ignored for menu items selected using the keyboard so you don't accidentally save stuff. * - Alt is hard to use in context menus, because pressing Alt closes the menu. * - Alt can't be used on the bookmarks toolbar because Alt is used for "treat this as something draggable". * - The button is ignored for the middle-click-paste-URL feature, since it's always a middle-click. */ function whereToOpenLink(e, ignoreButton, ignoreSave, ignoreBackground = false) { // This method must treat a null event like a left click without modifier keys (i.e. // e = { shiftKey:false, ctrlKey:false, metaKey:false, altKey:false, button:0 }) // for compatibility purposes. if (!e) return "current"; var shift = e.shiftKey; var ctrl = e.ctrlKey; var meta = e.metaKey; var alt = e.altKey && !ignoreSave; // ignoreButton allows "middle-click paste" to use function without always opening in a new window. var middle = !ignoreButton && e.button == 1; // Don't do anything special with right-mouse clicks. They're probably clicks on context menu items. // On macOS ctrl is not evaluated. var metaKey = AppConstants.platform == "macosx" ? meta : ctrl; if (metaKey || middle) { if (Services.prefs.getBoolPref("browser.tabs.opentabfor.middleclick", true)) return ignoreBackground ? "tabfocused" : shift ? "tabshifted" : "tab"; if (Services.prefs.getBoolPref("middlemouse.openNewWindow", true)) return "window"; if (middle) return null; } if (!ignoreSave) { if (Services.prefs.getBoolPref("ui.key.saveLink.shift", true) ? shift : alt) return "save"; } if (alt || shift || meta || ctrl) return null; return "current"; } /* openUILinkIn opens a URL in a place specified by the parameter |where|. * * |where| can be: * "current" current tab (if there aren't any browser windows, then in a new window instead) * "tab" new tab (if there aren't any browser windows, then in a new window instead) * "tabshifted" same as "tab" but in background if default is to select new tabs, and vice versa * "tabfocused" same as "tab" but explicitly focus new tab * "private" private browsing window * "window" new window * "save" save to disk (with no filename hint!) * * aAllowThirdPartyFixup controls whether third party services such as Google's * I'm Feeling Lucky are allowed to interpret this URL. This parameter may be * undefined, which is treated as false. * * Instead of aAllowThirdPartyFixup, you may also pass an object with any of * these properties: * allowThirdPartyFixup (boolean) * postData (nsIInputStream) * referrerURI (nsIURI) * relatedToCurrent (boolean) * initiatingDoc (document) * userContextId (unsigned int) */ function openUILinkIn(url, where, aAllowThirdPartyFixup, aPostData, aReferrerURI) { var params; if (arguments.length == 3 && typeof arguments[2] == "object") { params = aAllowThirdPartyFixup; } else { params = { allowThirdPartyFixup: aAllowThirdPartyFixup, postData: aPostData, referrerURI: aReferrerURI, referrerPolicy: Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, }; } if (where == "private") { where = "window"; params.private = true; } params.fromChrome = true; return openLinkIn(url, where, params); } function openLinkIn(url, where, params) { if (!where || !url) return null; var aFromChrome = params.fromChrome; var aAllowThirdPartyFixup = params.allowThirdPartyFixup; var aPostData = params.postData; var aCharset = params.charset; var aReferrerURI = params.referrerURI; var aReferrerPolicy = ("referrerPolicy" in params ? params.referrerPolicy : Ci.nsIHttpChannel.REFERRER_POLICY_UNSET); var aRelatedToCurrent = params.relatedToCurrent; var aAllowMixedContent = params.allowMixedContent; var aInBackground = params.inBackground; var aAvoidBrowserFocus = params.avoidBrowserFocus; var aDisallowInheritPrincipal = params.disallowInheritPrincipal; var aInitiatingDoc = params.initiatingDoc ? params.initiatingDoc : document; var aIsPrivate = params.private; var aNoReferrer = params.noReferrer; var aUserContextId = params.userContextId; var aPrincipal = params.originPrincipal; var aTriggeringPrincipal = params.triggeringPrincipal; var aForceAboutBlankViewerInCurrent = params.forceAboutBlankViewerInCurrent; if (where == "save") { saveURL(url, null, null, true, true, aNoReferrer ? null : aReferrerURI, aInitiatingDoc); return null; } // Establish which window we'll load the link in. var w = getTopWin(); // We don't want to open tabs in popups, so try to find a non-popup window in // that case. if ((where == "tab" || where == "tabshifted") && w && !w.toolbar.visible) { w = getTopWin(true); aRelatedToCurrent = false; } // Teach the principal about the right OA to use, e.g. in case when // opening a link in a new private window, or in a new container tab. // Please note we do not have to do that for SystemPrincipals and we // can not do it for NullPrincipals since NullPrincipals are only // identical if they actually are the same object (See Bug: 1346759) function useOAForPrincipal(principal) { if (principal && principal.isCodebasePrincipal) { let attrs = { userContextId: aUserContextId, }; return Services.scriptSecurityManager.createCodebasePrincipal(principal.URI, attrs); } return principal; } aPrincipal = useOAForPrincipal(aPrincipal); aTriggeringPrincipal = useOAForPrincipal(aTriggeringPrincipal); if (!w || where == "window") { let features = "chrome,dialog=no,all"; if (aIsPrivate) { features += ",private"; // To prevent regular browsing data from leaking to private browsing // sites, strip the referrer when opening a new private window. aNoReferrer = true; } // This propagates to window.arguments. var sa = Cc["@mozilla.org/array;1"]. createInstance(Ci.nsIMutableArray); var wuri = Cc["@mozilla.org/supports-string;1"]. createInstance(Ci.nsISupportsString); wuri.data = url; let charset = null; if (aCharset) { charset = Cc["@mozilla.org/supports-string;1"] .createInstance(Ci.nsISupportsString); charset.data = "charset=" + aCharset; } var allowThirdPartyFixupSupports = Cc["@mozilla.org/supports-PRBool;1"]. createInstance(Ci.nsISupportsPRBool); allowThirdPartyFixupSupports.data = aAllowThirdPartyFixup; var referrerURISupports = null; if (aReferrerURI && !aNoReferrer) { referrerURISupports = Cc["@mozilla.org/supports-string;1"]. createInstance(Ci.nsISupportsString); referrerURISupports.data = aReferrerURI.spec; } var referrerPolicySupports = Cc["@mozilla.org/supports-PRUint32;1"]. createInstance(Ci.nsISupportsPRUint32); referrerPolicySupports.data = aReferrerPolicy; var userContextIdSupports = Cc["@mozilla.org/supports-PRUint32;1"]. createInstance(Ci.nsISupportsPRUint32); userContextIdSupports.data = aUserContextId; sa.appendElement(wuri); sa.appendElement(charset); sa.appendElement(referrerURISupports); sa.appendElement(aPostData); sa.appendElement(allowThirdPartyFixupSupports); sa.appendElement(referrerPolicySupports); sa.appendElement(userContextIdSupports); sa.appendElement(aPrincipal); sa.appendElement(aTriggeringPrincipal); const sourceWindow = (w || window); Services.ww.openWindow(sourceWindow, getBrowserURL(), null, features, sa); return; } let loadInBackground = aInBackground; if (loadInBackground == null) { loadInBackground = aFromChrome ? false : Services.prefs.getBoolPref("browser.tabs.loadInBackground"); } if (aAvoidBrowserFocus == null) { aAvoidBrowserFocus = Services.prefs.getBoolPref("browser.tabs.avoidBrowserFocus", false); } // reuse the browser if its current tab is empty if (isBrowserEmpty(w.getBrowser())) where = "current"; switch (where) { case "current": let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE; if (aAllowThirdPartyFixup) { flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS; } if (aDisallowInheritPrincipal) { flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER; } if (aForceAboutBlankViewerInCurrent) { w.gBrowser.selectedBrowser.createAboutBlankContentViewer(aPrincipal); } w.getBrowser().loadURIWithFlags(url, { triggeringPrincipal: aTriggeringPrincipal, flags, referrerURI: aNoReferrer ? null : aReferrerURI, referrerPolicy: aReferrerPolicy, postData: aPostData, userContextId: aUserContextId }); if (!aAvoidBrowserFocus) { w.content.focus(); } break; case "tabfocused": // forces tab to be focused loadInBackground = true; // fall through case "tabshifted": loadInBackground = !loadInBackground; // fall through case "tab": var browser = w.getBrowser(); var tab = browser.addTab(url, { referrerURI: aReferrerURI, referrerPolicy: aReferrerPolicy, charset: aCharset, postData: aPostData, ownerTab: loadInBackground ? null : browser.selectedTab, allowThirdPartyFixup: aAllowThirdPartyFixup, relatedToCurrent: aRelatedToCurrent, allowMixedContent: aAllowMixedContent, noReferrer: aNoReferrer, userContextId: aUserContextId, originPrincipal: aPrincipal, triggeringPrincipal: aTriggeringPrincipal, }); if (!loadInBackground) { browser.selectedTab = tab; } if (!aAvoidBrowserFocus) { w.content.focus(); } break; } return w; } // This opens the URLs contained in the given array in new tabs // of the most recent window, creates a new window if necessary. function openUILinkArrayIn(urlArray, where, allowThirdPartyFixup) { if (!where || !urlArray.length) return null; if (where == "save") { for (var i = 0; i < urlArray.length; i++) saveURL(urlArray[i], null, null, true, true, null, document); return null; } var w = getTopWin(); if (!w || where == "window") { return window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", urlArray.join("\n"), // Pretend that we're a home page group null, null, null, allowThirdPartyFixup); } var loadInBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground"); var browser = w.getBrowser(); switch (where) { case "current": w.loadURI(urlArray[0], null, null, allowThirdPartyFixup); w.content.focus(); break; case "tabshifted": loadInBackground = !loadInBackground; // fall through case "tab": var tab = browser.addTab(urlArray[0], {allowThirdPartyFixup: allowThirdPartyFixup}); if (!loadInBackground) { browser.selectedTab = tab; w.content.focus(); } } var relatedToCurrent = where == "current"; for (var i = 1; i < urlArray.length; i++) browser.addTab(urlArray[i], {allowThirdPartyFixup: allowThirdPartyFixup, relatedToCurrent: relatedToCurrent}); return w; } /** * Switch to a tab that has a given URI, and focusses its browser window. * If a matching tab is in this window, it will be switched to. Otherwise, other * windows will be searched. * * @param aURI * URI to search for * @param aOpenNew * True to open a new tab and switch to it, if no existing tab is found * @param A callback to call when the tab is open, the tab's browser will be * passed as an argument * @return True if a tab was switched to (or opened), false otherwise */ function switchToTabHavingURI(aURI, aOpenNew, aCallback) { function switchIfURIInWindow(aWindow) { if (!aWindow.gBrowser) return false; let browsers = aWindow.gBrowser.browsers; for (let i = 0; i < browsers.length; i++) { let browser = browsers[i]; if (browser.currentURI.equals(aURI)) { // Focus the matching window & tab aWindow.focus(); aWindow.gBrowser.tabContainer.selectedIndex = i; if (aCallback) aCallback(browser); return true; } } return false; } // This can be passed either nsIURI or a string. if (!(aURI instanceof Ci.nsIURI)) aURI = Services.io.newURI(aURI); // Prioritise this window. if (switchIfURIInWindow(window)) return true; let winEnum = Services.wm.getEnumerator("navigator:browser"); while (winEnum.hasMoreElements()) { let browserWin = winEnum.getNext(); // Skip closed (but not yet destroyed) windows, // and the current window (which was checked earlier). if (browserWin.closed || browserWin == window) continue; if (switchIfURIInWindow(browserWin)) return true; } // No opened tab has that url. if (aOpenNew) { let browserWin = openUILinkIn(aURI.spec, "tabfocused"); if (aCallback) { browserWin.addEventListener("pageshow", function browserWinPageShow(event) { if (event.target.location.href != aURI.spec) return; browserWin.removeEventListener("pageshow", browserWinPageShow, true); aCallback(browserWin.getBrowser().selectedBrowser); }, true); } return true; } return false; } // Determines if a browser is "empty" function isBrowserEmpty(aBrowser) { return aBrowser.sessionHistory.count < 2 && aBrowser.currentURI.spec == "about:blank" && !aBrowser.contentDocument.body.hasChildNodes(); } function subscribeToFeed(href, event) { // Just load the feed in the content area to either subscribe or show the // preview UI var w = getTopWin(); var charset; if (w) { var browser = w.getBrowser(); charset = browser.characterSet; } else { // When calling this function without any open navigator window charset = document.characterSet; } let feedURI = makeURI(href, charset); openUILink(href, event, false, true); } function subscribeToFeedMiddleClick(href, event) { if (event.button == 1) { this.subscribeToFeed(href, event); // unlike for command events, we have to close the menus manually closeMenus(event.target); } } function OpenSearchEngineManager() { var window = Services.wm.getMostRecentWindow("Browser:SearchManager"); if (window) window.focus(); else { var arg = { value: false }; openDialog("chrome://communicator/content/search/engineManager.xul", "_blank", "chrome,dialog,modal,centerscreen,resizable", arg); if (arg.value) loadAddSearchEngines(); } } function loadAddSearchEngines() { var newWindowPref = Services.prefs.getIntPref("browser.link.open_newwindow"); var where = newWindowPref == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB ? "tabfocused" : "window"; var searchEnginesURL = Services.urlFormatter.formatURLPref("browser.search.searchEnginesURL"); openUILinkIn(searchEnginesURL, where); } function FillInHTMLTooltip(tipElement) { // Don't show the tooltip if the tooltip node is a document or disconnected. if (!tipElement.ownerDocument || (tipElement.ownerDocument.compareDocumentPosition(tipElement) & document.DOCUMENT_POSITION_DISCONNECTED)) return false; var defView = tipElement.ownerDocument.defaultView; // XXX Work around bug 350679: // "Tooltips can be fired in documents with no view". if (!defView) return false; const XLinkNS = "http://www.w3.org/1999/xlink"; const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var titleText = null; var XLinkTitleText = null; var SVGTitleText = null; var lookingForSVGTitle = true; var direction = defView.getComputedStyle(tipElement, "") .getPropertyValue("direction"); // If the element is invalid per HTML5 Forms specifications and has no title, // show the constraint validation error message. if ((tipElement instanceof HTMLInputElement || tipElement instanceof HTMLTextAreaElement || tipElement instanceof HTMLSelectElement || tipElement instanceof HTMLButtonElement) && !tipElement.hasAttribute("title") && (!tipElement.form || !tipElement.form.noValidate)) { // If the element is barred from constraint validation or is valid, // the validation message will be the empty string. titleText = tipElement.validationMessage || null; } while ((titleText == null) && (XLinkTitleText == null) && (SVGTitleText == null) && tipElement) { if (tipElement.nodeType == Node.ELEMENT_NODE && tipElement.namespaceURI != XULNS) { titleText = tipElement.getAttribute("title"); if ((tipElement instanceof HTMLAnchorElement || tipElement instanceof HTMLAreaElement || tipElement instanceof HTMLLinkElement || tipElement instanceof SVGAElement) && tipElement.href) { XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title"); } if (lookingForSVGTitle && (!(tipElement instanceof SVGElement) || tipElement.parentNode.nodeType == Node.DOCUMENT_NODE)) { lookingForSVGTitle = false; } if (lookingForSVGTitle) { let length = tipElement.childNodes.length; for (let i = 0; i < length; i++) { let childNode = tipElement.childNodes[i]; if (childNode instanceof SVGTitleElement) { SVGTitleText = childNode.textContent; break; } } } direction = defView.getComputedStyle(tipElement, "") .getPropertyValue("direction"); } tipElement = tipElement.parentNode; } var tipNode = document.getElementById("aHTMLTooltip"); tipNode.style.direction = direction; return [titleText, XLinkTitleText, SVGTitleText].some(function (t) { if (t && /\S/.test(t)) { // Make CRLF and CR render one line break each. tipNode.setAttribute("label", t.replace(/\r\n?/g, "\n")); return true; } return false; }); } function GetFileFromString(aString) { // If empty string just return null. if (!aString) return null; let commandLine = Cc["@mozilla.org/toolkit/command-line;1"] .createInstance(Ci.nsICommandLine); let uri = commandLine.resolveURI(aString); return uri instanceof Ci.nsIFileURL ? uri.file.QueryInterface(Ci.nsIFile) : null; } function CopyImage() { var param = Cu.createCommandParams(); param.setLongValue("imageCopy", Ci.nsIContentViewerEdit.COPY_IMAGE_ALL); document.commandDispatcher.getControllerForCommand("cmd_copyImage") .QueryInterface(Ci.nsICommandController) .doCommandWithParams("cmd_copyImage", param); } /** * Moved from toolkit/content/globalOverlay.js */ function goSetMenuValue(aCommand, aLabelAttribute) { var commandNode = top.document.getElementById(aCommand); if (commandNode) { var label = commandNode.getAttribute(aLabelAttribute); if (label) commandNode.setAttribute("label", label); } } function goSetAccessKey(aCommand, aValueAttribute) { var commandNode = top.document.getElementById(aCommand); if (commandNode) { var value = commandNode.getAttribute(aValueAttribute); if (value) commandNode.setAttribute("accesskey", value); } } // this function is used to inform all the controllers attached to a node that an event has occurred // (e.g. the tree controllers need to be informed of blur events so that they can change some of the // menu items back to their default values) function goOnEvent(aNode, aEvent) { var numControllers = aNode.controllers.getControllerCount(); var controller; for (var controllerIndex = 0; controllerIndex < numControllers; controllerIndex++) { controller = aNode.controllers.getControllerAt(controllerIndex); if (controller) controller.onEvent(aEvent); } }